bandas-df 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bandas_df-0.3.0/LICENSE +21 -0
- bandas_df-0.3.0/PKG-INFO +246 -0
- bandas_df-0.3.0/README.md +195 -0
- bandas_df-0.3.0/bandas/__init__.py +120 -0
- bandas_df-0.3.0/bandas/dataframe.py +949 -0
- bandas_df-0.3.0/bandas/datetimes.py +71 -0
- bandas_df-0.3.0/bandas/dl.py +55 -0
- bandas_df-0.3.0/bandas/groupby.py +326 -0
- bandas_df-0.3.0/bandas/io.py +115 -0
- bandas_df-0.3.0/bandas/lazy.py +79 -0
- bandas_df-0.3.0/bandas/ml.py +83 -0
- bandas_df-0.3.0/bandas/ops.py +91 -0
- bandas_df-0.3.0/bandas/preprocessing.py +158 -0
- bandas_df-0.3.0/bandas/reshape.py +88 -0
- bandas_df-0.3.0/bandas/series.py +634 -0
- bandas_df-0.3.0/bandas/sql.py +166 -0
- bandas_df-0.3.0/bandas/stats.py +98 -0
- bandas_df-0.3.0/bandas/strings.py +77 -0
- bandas_df-0.3.0/bandas/utils.py +83 -0
- bandas_df-0.3.0/bandas/viz.py +80 -0
- bandas_df-0.3.0/bandas/window.py +148 -0
- bandas_df-0.3.0/bandas_df.egg-info/PKG-INFO +246 -0
- bandas_df-0.3.0/bandas_df.egg-info/SOURCES.txt +28 -0
- bandas_df-0.3.0/bandas_df.egg-info/dependency_links.txt +1 -0
- bandas_df-0.3.0/bandas_df.egg-info/requires.txt +47 -0
- bandas_df-0.3.0/bandas_df.egg-info/top_level.txt +1 -0
- bandas_df-0.3.0/pyproject.toml +40 -0
- bandas_df-0.3.0/setup.cfg +4 -0
- bandas_df-0.3.0/tests/test_advanced.py +149 -0
- bandas_df-0.3.0/tests/test_basic.py +51 -0
bandas_df-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 salim-studio
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
bandas_df-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bandas-df
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: bandas — pandas-compatible, faster DataFrame + universal data platform (SQL/DB, time-series, preprocessing, ML/DL, viz, lazy)
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: dataframe,pandas,fast,numpy,sql,database,machine-learning,deep-learning,data-science,analytics,time-series,preprocessing
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: numpy>=1.26
|
|
11
|
+
Requires-Dist: pandas>=2.0
|
|
12
|
+
Requires-Dist: numba>=0.57
|
|
13
|
+
Requires-Dist: pyarrow>=12
|
|
14
|
+
Requires-Dist: sqlalchemy>=2.0
|
|
15
|
+
Requires-Dist: duckdb>=0.9
|
|
16
|
+
Requires-Dist: scikit-learn>=1.3
|
|
17
|
+
Requires-Dist: scipy>=1.10
|
|
18
|
+
Requires-Dist: matplotlib>=3.7
|
|
19
|
+
Requires-Dist: seaborn>=0.12
|
|
20
|
+
Requires-Dist: openpyxl>=3.1
|
|
21
|
+
Requires-Dist: xlrd>=2.0
|
|
22
|
+
Provides-Extra: speed
|
|
23
|
+
Requires-Dist: numba>=0.57; extra == "speed"
|
|
24
|
+
Requires-Dist: pyarrow>=12; extra == "speed"
|
|
25
|
+
Provides-Extra: db
|
|
26
|
+
Requires-Dist: sqlalchemy>=2.0; extra == "db"
|
|
27
|
+
Requires-Dist: duckdb>=0.9; extra == "db"
|
|
28
|
+
Provides-Extra: ml
|
|
29
|
+
Requires-Dist: scikit-learn>=1.3; extra == "ml"
|
|
30
|
+
Requires-Dist: scipy>=1.10; extra == "ml"
|
|
31
|
+
Provides-Extra: dl
|
|
32
|
+
Requires-Dist: torch>=2.0; extra == "dl"
|
|
33
|
+
Requires-Dist: tensorflow>=2.14; extra == "dl"
|
|
34
|
+
Provides-Extra: viz
|
|
35
|
+
Requires-Dist: matplotlib>=3.7; extra == "viz"
|
|
36
|
+
Requires-Dist: seaborn>=0.12; extra == "viz"
|
|
37
|
+
Provides-Extra: excel
|
|
38
|
+
Requires-Dist: openpyxl>=3.1; extra == "excel"
|
|
39
|
+
Requires-Dist: xlrd>=2.0; extra == "excel"
|
|
40
|
+
Provides-Extra: all
|
|
41
|
+
Requires-Dist: numba>=0.57; extra == "all"
|
|
42
|
+
Requires-Dist: pyarrow>=12; extra == "all"
|
|
43
|
+
Requires-Dist: pytest; extra == "all"
|
|
44
|
+
Requires-Dist: sqlalchemy>=2.0; extra == "all"
|
|
45
|
+
Requires-Dist: duckdb>=0.9; extra == "all"
|
|
46
|
+
Requires-Dist: scikit-learn>=1.3; extra == "all"
|
|
47
|
+
Requires-Dist: scipy>=1.10; extra == "all"
|
|
48
|
+
Requires-Dist: matplotlib>=3.7; extra == "all"
|
|
49
|
+
Requires-Dist: openpyxl>=3.1; extra == "all"
|
|
50
|
+
Dynamic: license-file
|
|
51
|
+
|
|
52
|
+
# bandas ⚡ — pandas-compatible, faster + Universal Data Platform
|
|
53
|
+
|
|
54
|
+
> أُعيدت تسمية المكتبة من `fandas` إلى `bandas` — المستودع الرسمي الآن: https://github.com/salim-studio/bandas
|
|
55
|
+
> للترحيل: `pip uninstall fandas` ثم `pip install bandas-df`، واستبدل `import fandas` بـ `import bandas`.
|
|
56
|
+
|
|
57
|
+
`bandas` واجهة مطابقة لـ `pandas` (نفس الأسماء: `DataFrame`, `Series`, `read_csv`, `concat`, `merge`...) لكن **أسرع**، ومع **منظومة متكاملة** لقواعد البيانات، السلاسل الزمنية، تجهيز البيانات، تعلم الآلة، التعلم العميق، والتصوير — لتصبح خيار المطورين ومحللي البيانات وعلماء البيانات.
|
|
58
|
+
|
|
59
|
+
## لماذا bandas؟
|
|
60
|
+
|
|
61
|
+
1. **تخزين عمودي خالص بـ NumPy** بدون Overhead الـ BlockManager.
|
|
62
|
+
2. **Fast-paths رقمية**: `sum/mean/min/max` عبر numpy مباشرة + `bincount` للـ groupby.
|
|
63
|
+
3. **تسريع اختياري بـ Numba** + **قراءة CSV بـ PyArrow** (أسرع 3-5x).
|
|
64
|
+
4. **SQL حقيقي**: `df.sql("SELECT ...")` بدون أي اعتماد إضافي (sqlite مدمج)، وموصل موحد `Database` لـ sqlite / duckdb / postgres / mysql / sqlalchemy.
|
|
65
|
+
5. **ML/DL جاهز**: `train_test_split`, `KFold`, مقاييس، `StandardScaler`, `OneHotEncoder`, `to_torch`, `to_tensorflow`, `torch_dataset`.
|
|
66
|
+
6. **تحليل متقدم**: `rolling/expanding/ewm`, `shift/diff/pct_change`, `pivot_table/melt/crosstab`, `str/dt accessors`, `LazyFrame` للملفات الضخمة خارج الذاكرة.
|
|
67
|
+
|
|
68
|
+
## تنصيب
|
|
69
|
+
|
|
70
|
+
تنصيب واحد يثبّت كل شيء (سرعة + قواعد بيانات + تعلم آلة + تصوير + إكسل):
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pip install bandas-df
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
من المصدر:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install -e .
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
إضافي فقط للتعلم العميق (torch و tensorflow ضخمان — جيجابايتات — وغير متوفرين لكل نسخ Python):
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install "bandas-df[dl]"
|
|
86
|
+
# أو من المصدر:
|
|
87
|
+
pip install -e ".[dl]"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 1) أساسيات (أسرع من pandas)
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
import bandas as bd
|
|
94
|
+
|
|
95
|
+
df = bd.DataFrame({"a": [1,2,3], "b": [4.0,5.0,6.0]})
|
|
96
|
+
print(df.head())
|
|
97
|
+
print(df["a"].sum())
|
|
98
|
+
|
|
99
|
+
df2 = bd.read_csv("data.csv") # pyarrow إن وجد
|
|
100
|
+
g = df2.groupby("city")["price"].mean()
|
|
101
|
+
print(g.to_pandas())
|
|
102
|
+
|
|
103
|
+
pdf = df.to_pandas()
|
|
104
|
+
df3 = bd.from_pandas(pdf)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
النتيجة على 500k صف: `sum 1.9x`, `mean 1.5x`, `groupby 1.3x` أسرع من pandas (انظر `bench/bench.py`).
|
|
108
|
+
|
|
109
|
+
## 2) قواعد البيانات / SQL
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
# SQL فوري بدون إعداد — يعمل دائماً (sqlite مدمج)
|
|
113
|
+
top = df.sql("SELECT city, AVG(price) AS m FROM df GROUP BY city ORDER BY m DESC")
|
|
114
|
+
|
|
115
|
+
# استعلام عبر عدة جداول
|
|
116
|
+
from bandas import sql_query
|
|
117
|
+
out = sql_query("SELECT * FROM a JOIN b ON a.k = b.k WHERE a.v > 10", {"a": a, "b": b})
|
|
118
|
+
|
|
119
|
+
# موصل موحد
|
|
120
|
+
from bandas.sql import Database
|
|
121
|
+
db = Database.sqlite("app.db") # أو :memory:
|
|
122
|
+
# db = Database.duckdb("data.duckdb") # يحتاج duckdb
|
|
123
|
+
# db = Database.postgres(user=..., password=..., host=..., db=...)
|
|
124
|
+
db.write(df, "sales")
|
|
125
|
+
print(db.query("SELECT COUNT(*) AS n FROM sales").to_pandas())
|
|
126
|
+
print(db.tables())
|
|
127
|
+
|
|
128
|
+
# pandas API
|
|
129
|
+
df.to_sql("sales", "sqlite:///app.db")
|
|
130
|
+
df2 = bd.read_sql("SELECT * FROM sales", "sqlite:///app.db")
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## 3) سلاسل زمنية ونوافذ
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
s = df["price"]
|
|
137
|
+
s.rolling(7).mean() # متوسط متحرك
|
|
138
|
+
s.expanding().sum()
|
|
139
|
+
s.ewm(span=10).mean()
|
|
140
|
+
s.shift(1); s.diff(); s.pct_change(); s.cumsum()
|
|
141
|
+
df.rolling(30).mean(); df.ewm(alpha=0.3).mean()
|
|
142
|
+
|
|
143
|
+
bd.to_datetime(["2024-01-01", "2024-02-01"])
|
|
144
|
+
bd.date_range("2024-01-01", periods=12, freq="ME")
|
|
145
|
+
df["d"].dt.year / .month / .day / .dayofweek
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## 4) نصوص وفئات وإعادة تشكيل
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
df["name"].str.lower().str.strip().str.contains("ali")
|
|
152
|
+
df["name"].str.replace("a", "@").str.split(" ", expand=True)
|
|
153
|
+
bd.get_dummies(df, columns=["city"])
|
|
154
|
+
bd.melt(df, id_vars=["city"])
|
|
155
|
+
bd.pivot_table(df, values="price", index="city", columns="year", aggfunc="mean")
|
|
156
|
+
bd.crosstab(df["city"], df["year"])
|
|
157
|
+
bd.cut(df["age"], bins=[0,18,60,100])
|
|
158
|
+
bd.qcut(df["price"], 4)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## 5) تجهيز البيانات (Preprocessing)
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
bd.SimpleImputer(strategy="mean").fit_transform(df)
|
|
165
|
+
bd.StandardScaler().fit_transform(df)
|
|
166
|
+
bd.MinMaxScaler().fit_transform(df)
|
|
167
|
+
bd.RobustScaler().fit_transform(df)
|
|
168
|
+
bd.LabelEncoder().fit_transform(df["city"])
|
|
169
|
+
bd.OneHotEncoder(columns=["city"]).fit_transform(df)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## 6) تعلم الآلة
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
X_train, X_test, y_train, y_test = bd.train_test_split(X, y, test_size=0.2, random_state=0)
|
|
176
|
+
list(bd.KFold(n_splits=5).split(X))
|
|
177
|
+
bd.accuracy_score(y, pred); bd.f1_score(y, pred)
|
|
178
|
+
bd.mean_squared_error(y, pred); bd.r2_score(y, pred)
|
|
179
|
+
|
|
180
|
+
# يعمل مباشرة مع sklearn
|
|
181
|
+
from sklearn.ensemble import RandomForestClassifier
|
|
182
|
+
X, y = bd.to_sklearn_Xy if False else (df.drop(columns=["target"]).to_numpy(), df["target"].to_numpy())
|
|
183
|
+
clf = RandomForestClassifier().fit(X_train_numpy, y_train_numpy)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## 7) التعلم العميق
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
X_t, y_t = df.to_torch(target="label") # torch.Tensor
|
|
190
|
+
loader = bd.dl.torch_dataset(df, target="label", batch_size=64)
|
|
191
|
+
ds = bd.dl.tf_dataset(df, target="label") # tf.data.Dataset
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## 8) ملفات ضخمة (Lazy / out-of-core)
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
lf = bd.read_csv_chunked("big.csv", chunksize=100_000)
|
|
198
|
+
out = lf.filter(lambda d: d[d["x"] > 0]).select(["x","y"]).collect()
|
|
199
|
+
print(lf.sum("x"), lf.mean("x"), lf.count())
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## 9) تصوير سريع
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
df.plot(kind="line", x="date", y="price")
|
|
206
|
+
df.plot(kind="bar", x="city", y="sales")
|
|
207
|
+
df["price"].hist(bins=50)
|
|
208
|
+
bd.viz.scatter(df, "a", "b"); bd.viz.heatmap_corr(df)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## 10) IO شامل
|
|
212
|
+
|
|
213
|
+
`read_csv / read_parquet / read_json / read_excel / read_html / read_feather / read_orc / read_sql` +
|
|
214
|
+
`to_csv / to_parquet / to_json / to_excel / to_sql` — كلها بنفس توقيع pandas.
|
|
215
|
+
|
|
216
|
+
## هيكل المشروع
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
bandas/
|
|
220
|
+
__init__.py # الواجهة العامة + concat/merge/options/show_versions
|
|
221
|
+
series.py # Series + str/dt + rolling/ewm + cum*/shift/diff + ML helpers
|
|
222
|
+
dataframe.py # DataFrame + SQL + stats + reshape + viz + torch
|
|
223
|
+
groupby.py # GroupBy السريع + std/var/median/first/last/nunique
|
|
224
|
+
io.py # كل قارئات الملفات + chunked
|
|
225
|
+
sql.py # sql_query + read_sql/to_sql + Database الموحد
|
|
226
|
+
reshape.py # get_dummies/melt/pivot/crosstab/cut/qcut
|
|
227
|
+
window.py # Rolling/Expanding/EWM
|
|
228
|
+
strings.py # Series.str
|
|
229
|
+
datetimes.py # Series.dt + to_datetime/date_range
|
|
230
|
+
preprocessing.py # Imputer/Scaler/Encoder
|
|
231
|
+
ml.py # split/CV/metrics/sklearn bridge
|
|
232
|
+
dl.py # torch/tensorflow bridges
|
|
233
|
+
stats.py # corr/cov/outliers/summary
|
|
234
|
+
lazy.py # LazyFrame خارج الذاكرة
|
|
235
|
+
viz.py # رسوم سريعة
|
|
236
|
+
ops.py / utils.py
|
|
237
|
+
tests/test_basic.py + test_advanced.py (20 اختباراً)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## اختبار و Benchmark
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
pytest -q
|
|
244
|
+
python bench/bench.py
|
|
245
|
+
python -c "import bandas; bandas.show_versions()"
|
|
246
|
+
```
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# bandas ⚡ — pandas-compatible, faster + Universal Data Platform
|
|
2
|
+
|
|
3
|
+
> أُعيدت تسمية المكتبة من `fandas` إلى `bandas` — المستودع الرسمي الآن: https://github.com/salim-studio/bandas
|
|
4
|
+
> للترحيل: `pip uninstall fandas` ثم `pip install bandas-df`، واستبدل `import fandas` بـ `import bandas`.
|
|
5
|
+
|
|
6
|
+
`bandas` واجهة مطابقة لـ `pandas` (نفس الأسماء: `DataFrame`, `Series`, `read_csv`, `concat`, `merge`...) لكن **أسرع**، ومع **منظومة متكاملة** لقواعد البيانات، السلاسل الزمنية، تجهيز البيانات، تعلم الآلة، التعلم العميق، والتصوير — لتصبح خيار المطورين ومحللي البيانات وعلماء البيانات.
|
|
7
|
+
|
|
8
|
+
## لماذا bandas؟
|
|
9
|
+
|
|
10
|
+
1. **تخزين عمودي خالص بـ NumPy** بدون Overhead الـ BlockManager.
|
|
11
|
+
2. **Fast-paths رقمية**: `sum/mean/min/max` عبر numpy مباشرة + `bincount` للـ groupby.
|
|
12
|
+
3. **تسريع اختياري بـ Numba** + **قراءة CSV بـ PyArrow** (أسرع 3-5x).
|
|
13
|
+
4. **SQL حقيقي**: `df.sql("SELECT ...")` بدون أي اعتماد إضافي (sqlite مدمج)، وموصل موحد `Database` لـ sqlite / duckdb / postgres / mysql / sqlalchemy.
|
|
14
|
+
5. **ML/DL جاهز**: `train_test_split`, `KFold`, مقاييس، `StandardScaler`, `OneHotEncoder`, `to_torch`, `to_tensorflow`, `torch_dataset`.
|
|
15
|
+
6. **تحليل متقدم**: `rolling/expanding/ewm`, `shift/diff/pct_change`, `pivot_table/melt/crosstab`, `str/dt accessors`, `LazyFrame` للملفات الضخمة خارج الذاكرة.
|
|
16
|
+
|
|
17
|
+
## تنصيب
|
|
18
|
+
|
|
19
|
+
تنصيب واحد يثبّت كل شيء (سرعة + قواعد بيانات + تعلم آلة + تصوير + إكسل):
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install bandas-df
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
من المصدر:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install -e .
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
إضافي فقط للتعلم العميق (torch و tensorflow ضخمان — جيجابايتات — وغير متوفرين لكل نسخ Python):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install "bandas-df[dl]"
|
|
35
|
+
# أو من المصدر:
|
|
36
|
+
pip install -e ".[dl]"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 1) أساسيات (أسرع من pandas)
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import bandas as bd
|
|
43
|
+
|
|
44
|
+
df = bd.DataFrame({"a": [1,2,3], "b": [4.0,5.0,6.0]})
|
|
45
|
+
print(df.head())
|
|
46
|
+
print(df["a"].sum())
|
|
47
|
+
|
|
48
|
+
df2 = bd.read_csv("data.csv") # pyarrow إن وجد
|
|
49
|
+
g = df2.groupby("city")["price"].mean()
|
|
50
|
+
print(g.to_pandas())
|
|
51
|
+
|
|
52
|
+
pdf = df.to_pandas()
|
|
53
|
+
df3 = bd.from_pandas(pdf)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
النتيجة على 500k صف: `sum 1.9x`, `mean 1.5x`, `groupby 1.3x` أسرع من pandas (انظر `bench/bench.py`).
|
|
57
|
+
|
|
58
|
+
## 2) قواعد البيانات / SQL
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
# SQL فوري بدون إعداد — يعمل دائماً (sqlite مدمج)
|
|
62
|
+
top = df.sql("SELECT city, AVG(price) AS m FROM df GROUP BY city ORDER BY m DESC")
|
|
63
|
+
|
|
64
|
+
# استعلام عبر عدة جداول
|
|
65
|
+
from bandas import sql_query
|
|
66
|
+
out = sql_query("SELECT * FROM a JOIN b ON a.k = b.k WHERE a.v > 10", {"a": a, "b": b})
|
|
67
|
+
|
|
68
|
+
# موصل موحد
|
|
69
|
+
from bandas.sql import Database
|
|
70
|
+
db = Database.sqlite("app.db") # أو :memory:
|
|
71
|
+
# db = Database.duckdb("data.duckdb") # يحتاج duckdb
|
|
72
|
+
# db = Database.postgres(user=..., password=..., host=..., db=...)
|
|
73
|
+
db.write(df, "sales")
|
|
74
|
+
print(db.query("SELECT COUNT(*) AS n FROM sales").to_pandas())
|
|
75
|
+
print(db.tables())
|
|
76
|
+
|
|
77
|
+
# pandas API
|
|
78
|
+
df.to_sql("sales", "sqlite:///app.db")
|
|
79
|
+
df2 = bd.read_sql("SELECT * FROM sales", "sqlite:///app.db")
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## 3) سلاسل زمنية ونوافذ
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
s = df["price"]
|
|
86
|
+
s.rolling(7).mean() # متوسط متحرك
|
|
87
|
+
s.expanding().sum()
|
|
88
|
+
s.ewm(span=10).mean()
|
|
89
|
+
s.shift(1); s.diff(); s.pct_change(); s.cumsum()
|
|
90
|
+
df.rolling(30).mean(); df.ewm(alpha=0.3).mean()
|
|
91
|
+
|
|
92
|
+
bd.to_datetime(["2024-01-01", "2024-02-01"])
|
|
93
|
+
bd.date_range("2024-01-01", periods=12, freq="ME")
|
|
94
|
+
df["d"].dt.year / .month / .day / .dayofweek
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## 4) نصوص وفئات وإعادة تشكيل
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
df["name"].str.lower().str.strip().str.contains("ali")
|
|
101
|
+
df["name"].str.replace("a", "@").str.split(" ", expand=True)
|
|
102
|
+
bd.get_dummies(df, columns=["city"])
|
|
103
|
+
bd.melt(df, id_vars=["city"])
|
|
104
|
+
bd.pivot_table(df, values="price", index="city", columns="year", aggfunc="mean")
|
|
105
|
+
bd.crosstab(df["city"], df["year"])
|
|
106
|
+
bd.cut(df["age"], bins=[0,18,60,100])
|
|
107
|
+
bd.qcut(df["price"], 4)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 5) تجهيز البيانات (Preprocessing)
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
bd.SimpleImputer(strategy="mean").fit_transform(df)
|
|
114
|
+
bd.StandardScaler().fit_transform(df)
|
|
115
|
+
bd.MinMaxScaler().fit_transform(df)
|
|
116
|
+
bd.RobustScaler().fit_transform(df)
|
|
117
|
+
bd.LabelEncoder().fit_transform(df["city"])
|
|
118
|
+
bd.OneHotEncoder(columns=["city"]).fit_transform(df)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## 6) تعلم الآلة
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
X_train, X_test, y_train, y_test = bd.train_test_split(X, y, test_size=0.2, random_state=0)
|
|
125
|
+
list(bd.KFold(n_splits=5).split(X))
|
|
126
|
+
bd.accuracy_score(y, pred); bd.f1_score(y, pred)
|
|
127
|
+
bd.mean_squared_error(y, pred); bd.r2_score(y, pred)
|
|
128
|
+
|
|
129
|
+
# يعمل مباشرة مع sklearn
|
|
130
|
+
from sklearn.ensemble import RandomForestClassifier
|
|
131
|
+
X, y = bd.to_sklearn_Xy if False else (df.drop(columns=["target"]).to_numpy(), df["target"].to_numpy())
|
|
132
|
+
clf = RandomForestClassifier().fit(X_train_numpy, y_train_numpy)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## 7) التعلم العميق
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
X_t, y_t = df.to_torch(target="label") # torch.Tensor
|
|
139
|
+
loader = bd.dl.torch_dataset(df, target="label", batch_size=64)
|
|
140
|
+
ds = bd.dl.tf_dataset(df, target="label") # tf.data.Dataset
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## 8) ملفات ضخمة (Lazy / out-of-core)
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
lf = bd.read_csv_chunked("big.csv", chunksize=100_000)
|
|
147
|
+
out = lf.filter(lambda d: d[d["x"] > 0]).select(["x","y"]).collect()
|
|
148
|
+
print(lf.sum("x"), lf.mean("x"), lf.count())
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## 9) تصوير سريع
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
df.plot(kind="line", x="date", y="price")
|
|
155
|
+
df.plot(kind="bar", x="city", y="sales")
|
|
156
|
+
df["price"].hist(bins=50)
|
|
157
|
+
bd.viz.scatter(df, "a", "b"); bd.viz.heatmap_corr(df)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## 10) IO شامل
|
|
161
|
+
|
|
162
|
+
`read_csv / read_parquet / read_json / read_excel / read_html / read_feather / read_orc / read_sql` +
|
|
163
|
+
`to_csv / to_parquet / to_json / to_excel / to_sql` — كلها بنفس توقيع pandas.
|
|
164
|
+
|
|
165
|
+
## هيكل المشروع
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
bandas/
|
|
169
|
+
__init__.py # الواجهة العامة + concat/merge/options/show_versions
|
|
170
|
+
series.py # Series + str/dt + rolling/ewm + cum*/shift/diff + ML helpers
|
|
171
|
+
dataframe.py # DataFrame + SQL + stats + reshape + viz + torch
|
|
172
|
+
groupby.py # GroupBy السريع + std/var/median/first/last/nunique
|
|
173
|
+
io.py # كل قارئات الملفات + chunked
|
|
174
|
+
sql.py # sql_query + read_sql/to_sql + Database الموحد
|
|
175
|
+
reshape.py # get_dummies/melt/pivot/crosstab/cut/qcut
|
|
176
|
+
window.py # Rolling/Expanding/EWM
|
|
177
|
+
strings.py # Series.str
|
|
178
|
+
datetimes.py # Series.dt + to_datetime/date_range
|
|
179
|
+
preprocessing.py # Imputer/Scaler/Encoder
|
|
180
|
+
ml.py # split/CV/metrics/sklearn bridge
|
|
181
|
+
dl.py # torch/tensorflow bridges
|
|
182
|
+
stats.py # corr/cov/outliers/summary
|
|
183
|
+
lazy.py # LazyFrame خارج الذاكرة
|
|
184
|
+
viz.py # رسوم سريعة
|
|
185
|
+
ops.py / utils.py
|
|
186
|
+
tests/test_basic.py + test_advanced.py (20 اختباراً)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## اختبار و Benchmark
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
pytest -q
|
|
193
|
+
python bench/bench.py
|
|
194
|
+
python -c "import bandas; bandas.show_versions()"
|
|
195
|
+
```
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""bandas — pandas-compatible, faster DataFrame library + universal data platform.
|
|
2
|
+
|
|
3
|
+
Core (fast NumPy paths) + SQL/DB + time-series + preprocessing + ML/DL + viz + lazy.
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from .series import Series
|
|
8
|
+
from .dataframe import DataFrame
|
|
9
|
+
from .io import (
|
|
10
|
+
read_csv, read_parquet, read_json, read_excel, read_html,
|
|
11
|
+
read_feather, read_orc, read_sql, read_csv_chunked,
|
|
12
|
+
from_pandas, to_pandas,
|
|
13
|
+
)
|
|
14
|
+
from .sql import sql_query, to_sql, Database
|
|
15
|
+
from .reshape import get_dummies, melt, pivot_table, crosstab, cut, qcut
|
|
16
|
+
from .datetimes import to_datetime, date_range
|
|
17
|
+
from .lazy import LazyFrame
|
|
18
|
+
from . import preprocessing, ml, stats, viz, dl
|
|
19
|
+
from .preprocessing import SimpleImputer, StandardScaler, MinMaxScaler, RobustScaler, LabelEncoder, OneHotEncoder
|
|
20
|
+
from .ml import train_test_split, KFold, accuracy_score, mean_squared_error, mean_absolute_error, r2_score, precision_score, recall_score, f1_score
|
|
21
|
+
|
|
22
|
+
__version__ = "0.3.0"
|
|
23
|
+
__all__ = [
|
|
24
|
+
"DataFrame", "Series", "Database", "LazyFrame",
|
|
25
|
+
"read_csv", "read_parquet", "read_json", "read_excel", "read_html",
|
|
26
|
+
"read_feather", "read_orc", "read_sql", "read_csv_chunked",
|
|
27
|
+
"from_pandas", "to_pandas", "sql_query", "to_sql",
|
|
28
|
+
"concat", "merge", "merge_ordered", "merge_asof",
|
|
29
|
+
"get_dummies", "melt", "pivot_table", "crosstab", "cut", "qcut",
|
|
30
|
+
"to_datetime", "date_range",
|
|
31
|
+
"SimpleImputer", "StandardScaler", "MinMaxScaler", "RobustScaler",
|
|
32
|
+
"LabelEncoder", "OneHotEncoder",
|
|
33
|
+
"train_test_split", "KFold",
|
|
34
|
+
"accuracy_score", "mean_squared_error", "mean_absolute_error", "r2_score",
|
|
35
|
+
"precision_score", "recall_score", "f1_score",
|
|
36
|
+
"preprocessing", "ml", "stats", "viz", "dl",
|
|
37
|
+
"show_versions", "options",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def concat(objs, axis=0, ignore_index=False):
|
|
42
|
+
import numpy as np
|
|
43
|
+
from .series import Series as _S
|
|
44
|
+
if not objs:
|
|
45
|
+
return DataFrame({})
|
|
46
|
+
if isinstance(objs[0], _S):
|
|
47
|
+
arr = np.concatenate([np.asarray(o._data) for o in objs])
|
|
48
|
+
idx = np.concatenate([np.asarray(o._index) for o in objs]) if not ignore_index else np.arange(len(arr))
|
|
49
|
+
return _S(arr, index=idx, name=objs[0]._name)
|
|
50
|
+
if axis == 1:
|
|
51
|
+
out_cols, out_data = [], {}
|
|
52
|
+
n = max(len(o) for o in objs)
|
|
53
|
+
for o in objs:
|
|
54
|
+
for c in o._columns:
|
|
55
|
+
name = c
|
|
56
|
+
k = 0
|
|
57
|
+
while name in out_data:
|
|
58
|
+
k += 1
|
|
59
|
+
name = f"{c}_{k}"
|
|
60
|
+
out_cols.append(name)
|
|
61
|
+
a = np.asarray(o._cols[c])
|
|
62
|
+
if len(a) < n:
|
|
63
|
+
pad = np.full(n - len(a), np.nan, dtype=np.float64 if a.dtype.kind in "iuf" else object)
|
|
64
|
+
a = np.concatenate([a.astype(pad.dtype) if a.dtype != pad.dtype else a, pad])
|
|
65
|
+
out_data[name] = a
|
|
66
|
+
nd = DataFrame.__new__(DataFrame)
|
|
67
|
+
nd._columns = out_cols
|
|
68
|
+
nd._cols = out_data
|
|
69
|
+
nd._index = np.arange(n) if ignore_index else np.asarray(objs[0]._index)
|
|
70
|
+
return nd
|
|
71
|
+
cols = list(objs[0]._columns)
|
|
72
|
+
for o in objs[1:]:
|
|
73
|
+
for c in o._columns:
|
|
74
|
+
if c not in cols:
|
|
75
|
+
cols.append(c)
|
|
76
|
+
out = {c: [] for c in cols}
|
|
77
|
+
idx_parts = []
|
|
78
|
+
for o in objs:
|
|
79
|
+
for c in cols:
|
|
80
|
+
if c in o._cols:
|
|
81
|
+
out[c].append(np.asarray(o._cols[c]))
|
|
82
|
+
else:
|
|
83
|
+
out[c].append(np.full(len(o), np.nan))
|
|
84
|
+
idx_parts.append(np.asarray(o._index))
|
|
85
|
+
data = {c: np.concatenate(v) if v else np.array([]) for c, v in out.items()}
|
|
86
|
+
idx = np.arange(sum(len(o) for o in objs)) if ignore_index else np.concatenate(idx_parts) if idx_parts else np.array([])
|
|
87
|
+
return DataFrame(data, index=idx)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def merge(left, right, on=None, how="inner", left_on=None, right_on=None):
|
|
91
|
+
return left.merge(right, on=on, how=how, left_on=left_on, right_on=right_on)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def merge_ordered(left, right, on=None, how="outer", **kw):
|
|
95
|
+
out = merge(left, right, on=on, how=how, **kw)
|
|
96
|
+
return out.sort_values(on) if on else out
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def merge_asof(left, right, on=None, direction="backward"):
|
|
100
|
+
import pandas as pd
|
|
101
|
+
return DataFrame(pd.merge_asof(left.to_pandas().sort_values(on), right.to_pandas().sort_values(on), on=on, direction=direction))
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class _Options(dict):
|
|
105
|
+
def __repr__(self): return f"bandas.options({dict(self)})"
|
|
106
|
+
|
|
107
|
+
options = _Options({"display.max_rows": 10, "compute.numba": True, "io.pyarrow": True})
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def show_versions():
|
|
111
|
+
import sys, numpy, pandas
|
|
112
|
+
info = {"python": sys.version.split()[0], "bandas": __version__, "numpy": numpy.__version__, "pandas": pandas.__version__}
|
|
113
|
+
for mod in ("pyarrow", "numba", "sqlalchemy", "duckdb", "sklearn", "torch", "tensorflow", "matplotlib"):
|
|
114
|
+
try:
|
|
115
|
+
m = __import__(mod)
|
|
116
|
+
info[mod] = getattr(m, "__version__", "installed")
|
|
117
|
+
except Exception:
|
|
118
|
+
info[mod] = "not installed"
|
|
119
|
+
for k, v in info.items(): print(f"{k}: {v}")
|
|
120
|
+
return info
|