clean-data-tools 0.1.0__py3-none-any.whl
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.
- clean_data_tools-0.1.0.dist-info/METADATA +334 -0
- clean_data_tools-0.1.0.dist-info/RECORD +10 -0
- clean_data_tools-0.1.0.dist-info/WHEEL +5 -0
- clean_data_tools-0.1.0.dist-info/licenses/LICENSE +21 -0
- clean_data_tools-0.1.0.dist-info/top_level.txt +1 -0
- cleandata/__init__.py +16 -0
- cleandata/cleaner.py +188 -0
- cleandata/normalizer.py +121 -0
- cleandata/outlier.py +147 -0
- cleandata/utils.py +65 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: clean-data-tools
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: ابزارهای قدرتمند برای تمیزکاری و پیشپردازش دادهها
|
|
5
|
+
Author-email: Hasan Bagheri <hasan111bagher@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/0hasanbagheri0/clean-data
|
|
8
|
+
Project-URL: Repository, https://github.com/0hasanbagheri0/clean-data
|
|
9
|
+
Project-URL: Issues, https://github.com/0hasanbagheri0/clean-data/issues
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
15
|
+
Requires-Python: >=3.7
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: pandas>=1.0.0
|
|
19
|
+
Requires-Dist: numpy>=1.18.0
|
|
20
|
+
Requires-Dist: scipy>=1.4.0
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
markdown
|
|
24
|
+
# Clean-Data
|
|
25
|
+
|
|
26
|
+
ابزارهای قدرتمند برای تمیزکاری و پیشپردازش دادهها در پایتون
|
|
27
|
+
|
|
28
|
+
[](https://badge.fury.io/py/clean-data)
|
|
29
|
+
[](https://www.python.org/downloads/)
|
|
30
|
+
[](https://opensource.org/licenses/MIT)
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 🌐 English | [فارسی](#فارسی)
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
# English Documentation
|
|
39
|
+
|
|
40
|
+
## 📁 Clean-Data
|
|
41
|
+
|
|
42
|
+
**Clean-Data** is a powerful library for data cleaning and preprocessing in Python. It simplifies repetitive tasks like handling missing values, removing duplicates, detecting outliers, and normalizing data.
|
|
43
|
+
---
|
|
44
|
+
### ✨ Key Features
|
|
45
|
+
|
|
46
|
+
- **Remove Duplicates**: Eliminate duplicate records easily
|
|
47
|
+
- **Handle Missing Values**: Fill with mean, median, mode, or custom values
|
|
48
|
+
- **Outlier Detection**: Using IQR and Z-Score methods
|
|
49
|
+
- **Data Normalization**: Min-Max, Standardization, and Robust Scaling
|
|
50
|
+
- **Auto Type Conversion**: Convert columns to appropriate types
|
|
51
|
+
- **Quality Report**: Get detailed statistics about your data
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### 📦 Installation
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install clean-data
|
|
59
|
+
```
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### 🚀 Quick Start
|
|
63
|
+
```python
|
|
64
|
+
import pandas as pd
|
|
65
|
+
from cleandata import DataCleaner, OutlierDetector, Normalizer, get_data_quality_report
|
|
66
|
+
```
|
|
67
|
+
# Load data
|
|
68
|
+
```bash
|
|
69
|
+
df = pd.read_csv("data.csv")
|
|
70
|
+
```
|
|
71
|
+
# Clean data
|
|
72
|
+
```bash
|
|
73
|
+
cleaner = DataCleaner(df)
|
|
74
|
+
```
|
|
75
|
+
```bash
|
|
76
|
+
cleaner.remove_duplicates()
|
|
77
|
+
```
|
|
78
|
+
```bash
|
|
79
|
+
cleaner.fill_missing("mean")
|
|
80
|
+
```
|
|
81
|
+
```bash
|
|
82
|
+
cleaner.strip_strings()
|
|
83
|
+
```
|
|
84
|
+
# Detect and remove outliers
|
|
85
|
+
```bash
|
|
86
|
+
detector = OutlierDetector(cleaner.get_data())
|
|
87
|
+
```
|
|
88
|
+
```bash
|
|
89
|
+
outliers = detector.detect_iqr()
|
|
90
|
+
```
|
|
91
|
+
```bash
|
|
92
|
+
df_clean = detector.remove_outliers()
|
|
93
|
+
```
|
|
94
|
+
# Normalize
|
|
95
|
+
```bash
|
|
96
|
+
normalizer = Normalizer(df_clean)
|
|
97
|
+
```
|
|
98
|
+
```bash
|
|
99
|
+
df_scaled = normalizer.min_max_scale()
|
|
100
|
+
```
|
|
101
|
+
# Quality report
|
|
102
|
+
```bash
|
|
103
|
+
report = get_data_quality_report(df_clean)
|
|
104
|
+
```
|
|
105
|
+
```bash
|
|
106
|
+
print(report)
|
|
107
|
+
```
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
### 📚 API Reference
|
|
111
|
+
# DataCleaner Class
|
|
112
|
+
|Method| Description|
|
|
113
|
+
| :--- | :--- |
|
|
114
|
+
|remove_duplicates(subset, keep) |Remove duplicate rows|
|
|
115
|
+
|fill_missing(method, columns) |Fill missing values with mean, median, mode, or custom|
|
|
116
|
+
|remove_missing(threshold, axis) |Remove rows/columns with too many missing values|
|
|
117
|
+
|convert_types(columns) |Auto-convert column data types|
|
|
118
|
+
|strip_strings(columns) |Remove extra whitespace from strings|
|
|
119
|
+
|rename_columns(mapping) |Rename columns|
|
|
120
|
+
|filter_rows(condition) |Filter rows based on condition|
|
|
121
|
+
|reset() |Revert to original data|
|
|
122
|
+
|
|
123
|
+
# OutlierDetector Class
|
|
124
|
+
|
|
125
|
+
|Method |Description|
|
|
126
|
+
| :--- | :--- |
|
|
127
|
+
|detect_iqr(columns, multiplier) |Detect outliers using IQR method|
|
|
128
|
+
|detect_zscore(columns, threshold) |Detect outliers using Z-Score method|
|
|
129
|
+
|remove_outliers(columns, method, threshold) |Remove rows with outliers|
|
|
130
|
+
|replace_outliers(columns, method, multiplier) |Replace outliers with mean/median/custom|
|
|
131
|
+
|
|
132
|
+
# Normalizer Class
|
|
133
|
+
|
|
134
|
+
|Method |Description|
|
|
135
|
+
| :--- | :--- |
|
|
136
|
+
|min_max_scale(columns, feature_range) |Scale to a range (default 0-1)|
|
|
137
|
+
|standardize(columns) |Standardize to mean=0, std=1|
|
|
138
|
+
|robust_scale(columns) |Scale using median and IQR (robust to outliers)|
|
|
139
|
+
|log_transform(columns) |Apply log transformation|
|
|
140
|
+
# Utility Functions
|
|
141
|
+
|Function |Description|
|
|
142
|
+
| :--- | :--- |
|
|
143
|
+
|get_data_quality_report(df)| Get comprehensive data quality report|
|
|
144
|
+
|get_column_info(df, column)| Get detailed info about a specific column|
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
### 🛠️ Requirements
|
|
149
|
+
Python 3.7 or higher
|
|
150
|
+
|
|
151
|
+
pandas>=1.0.0
|
|
152
|
+
|
|
153
|
+
numpy>=1.18.0
|
|
154
|
+
|
|
155
|
+
scipy>=1.4.0
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
### 🤝 Contributing
|
|
160
|
+
We welcome contributions! Please:
|
|
161
|
+
|
|
162
|
+
1.Fork the repository
|
|
163
|
+
|
|
164
|
+
2.Create a new branch (git checkout -b feature/amazing-feature)
|
|
165
|
+
|
|
166
|
+
3.Commit your changes (git commit -m 'Add amazing feature')
|
|
167
|
+
|
|
168
|
+
4.Push to the branch (git push origin feature/amazing-feature)
|
|
169
|
+
|
|
170
|
+
5.Open a Pull Request
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### 📄 License
|
|
175
|
+
This project is licensed under the MIT License.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
### 📧 Contact
|
|
180
|
+
Email: hasan111bagher@gmail.com
|
|
181
|
+
|
|
182
|
+
GitHub: 0hasanbagheri0
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
فارسی
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
### 📁 Clean-Data
|
|
192
|
+
Clean-Data یک کتابخانه قدرتمند برای تمیزکاری و پیشپردازش دادهها در پایتون است. این کتابخانه کارهای تکراری مانند مدیریت مقادیر خالی، حذف رکوردهای تکراری، تشخیص دادههای پرت و نرمالسازی دادهها را ساده میکند.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
### ✨ ویژگیهای کلیدی
|
|
197
|
+
|
|
198
|
+
حذف رکوردهای تکراری: حذف آسان رکوردهای تکراری
|
|
199
|
+
|
|
200
|
+
مدیریت مقادیر خالی: پر کردن با میانگین، میانه، مد یا مقدار دلخواه
|
|
201
|
+
|
|
202
|
+
تشخیص دادههای پرت: با روشهای IQR و Z-Score
|
|
203
|
+
|
|
204
|
+
نرمالسازی دادهها: Min-Max، Standardization و Robust Scaling
|
|
205
|
+
|
|
206
|
+
تبدیل خودکار نوع دادهها: تبدیل ستونها به نوع مناسب
|
|
207
|
+
|
|
208
|
+
گزارش کیفیت: دریافت آمار دقیق از دادهها
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
### 📦 نصب
|
|
213
|
+
```bash
|
|
214
|
+
pip install clean-data
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
### 🚀 شروع سریع
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
|
|
224
|
+
import pandas as pd
|
|
225
|
+
from cleandata import DataCleaner, OutlierDetector, Normalizer, get_data_quality_report
|
|
226
|
+
```
|
|
227
|
+
# بارگذاری داده
|
|
228
|
+
```bash
|
|
229
|
+
df = pd.read_csv("data.csv")
|
|
230
|
+
```
|
|
231
|
+
# تمیزکاری
|
|
232
|
+
```bash
|
|
233
|
+
cleaner = DataCleaner(df)
|
|
234
|
+
```
|
|
235
|
+
```bash
|
|
236
|
+
cleaner.remove_duplicates()
|
|
237
|
+
```
|
|
238
|
+
```bash
|
|
239
|
+
cleaner.fill_missing("mean")
|
|
240
|
+
```
|
|
241
|
+
```bash
|
|
242
|
+
cleaner.strip_strings()
|
|
243
|
+
```
|
|
244
|
+
# تشخیص و حذف دادههای پرت
|
|
245
|
+
```bash
|
|
246
|
+
detector = OutlierDetector(cleaner.get_data())
|
|
247
|
+
```
|
|
248
|
+
```bash
|
|
249
|
+
outliers = detector.detect_iqr()
|
|
250
|
+
```
|
|
251
|
+
```bash
|
|
252
|
+
df_clean = detector.remove_outliers()
|
|
253
|
+
```
|
|
254
|
+
# نرمالسازی
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
normalizer = Normalizer(df_clean)
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
```bash
|
|
261
|
+
df_scaled = normalizer.min_max_scale()
|
|
262
|
+
```
|
|
263
|
+
# گزارش کیفیت
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
report = get_data_quality_report(df_clean)
|
|
267
|
+
print(report)
|
|
268
|
+
```
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
### 📚 راهنمای توابع
|
|
272
|
+
# کلاس DataCleaner
|
|
273
|
+
|تابع |توضیح|
|
|
274
|
+
| :--- | :--- |
|
|
275
|
+
|remove_duplicates(subset, keep)| حذف سطرهای تکراری|
|
|
276
|
+
|fill_missing(method, columns) |پر کردن مقادیر خالی با میانگین، میانه، مد یا مقدار دلخواه|
|
|
277
|
+
|remove_missing(threshold, axis)| حذف سطرها/ستونهایی که مقادیر خالی زیادی دارند|
|
|
278
|
+
|convert_types(columns)| تبدیل خودکار نوع ستونها|
|
|
279
|
+
|strip_strings(columns)| حذف فاصلههای اضافی از رشتهها|
|
|
280
|
+
|rename_columns(mapping)| تغییر نام ستونها|
|
|
281
|
+
|filter_rows(condition)| فیلتر کردن سطرها بر اساس شرط|
|
|
282
|
+
|reset()| بازگشت به دادههای اصلی|
|
|
283
|
+
# کلاس OutlierDetector
|
|
284
|
+
|تابع |توضیح|
|
|
285
|
+
| :--- | :--- |
|
|
286
|
+
|detect_iqr(columns, multiplier) |تشخیص دادههای پرت با روش IQR|
|
|
287
|
+
|detect_zscore(columns, threshold) |تشخیص دادههای پرت با روش Z-Score|
|
|
288
|
+
|remove_outliers(columns, method, threshold) |حذف سطرهای حاوی دادههای پرت|
|
|
289
|
+
|replace_outliers(columns, method, multiplier) |جایگزینی دادههای پرت با میانگین/میانه/مقدار دلخواه|
|
|
290
|
+
# کلاس Normalizer
|
|
291
|
+
|تابع |توضیح|
|
|
292
|
+
| :--- | :--- |
|
|
293
|
+
|min_max_scale(columns, feature_range) |مقیاسسازی به بازه مشخص (پیشفرض ۰ تا ۱)|
|
|
294
|
+
|standardize(columns) |استانداردسازی (میانگین صفر، انحراف معیار یک)|
|
|
295
|
+
|robust_scale(columns) |مقیاسسازی مقاوم به دادههای پرت (با میانه و IQR)|
|
|
296
|
+
|log_transform(columns)| اعمال تبدیل لگاریتمی|
|
|
297
|
+
# توابع کمکی
|
|
298
|
+
|تابع |توضیح|
|
|
299
|
+
| :--- | :--- |
|
|
300
|
+
|get_data_quality_report(df) |دریافت گزارش کامل کیفیت داده|
|
|
301
|
+
|get_column_info(df, column) |دریافت اطلاعات دقیق یک ستون خاص|
|
|
302
|
+
|
|
303
|
+
### 🛠️ نیازمندیها
|
|
304
|
+
|
|
305
|
+
Python 3.7 یا بالاتر
|
|
306
|
+
|
|
307
|
+
pandas>=1.0.0
|
|
308
|
+
|
|
309
|
+
numpy>=1.18.0
|
|
310
|
+
|
|
311
|
+
scipy>=1.4.0
|
|
312
|
+
|
|
313
|
+
### 🤝 مشارکت
|
|
314
|
+
از مشارکت شما استقبال میکنیم! لطفاً:
|
|
315
|
+
|
|
316
|
+
1.مخزن را Fork کنید
|
|
317
|
+
|
|
318
|
+
2.یک شاخه جدید بسازید (git checkout -b feature/amazing-feature)
|
|
319
|
+
|
|
320
|
+
3.تغییرات را Commit کنید (git commit -m 'Add amazing feature')
|
|
321
|
+
|
|
322
|
+
4.به شاخه خود Push کنید (git push origin feature/amazing-feature)
|
|
323
|
+
|
|
324
|
+
5.یک Pull Request باز کنید
|
|
325
|
+
|
|
326
|
+
### 📄 مجوز
|
|
327
|
+
این پروژه تحت مجوز MIT منتشر شده است.
|
|
328
|
+
|
|
329
|
+
### 📧 ارتباط با من
|
|
330
|
+
ایمیل: hasan111bagher@gmail.com
|
|
331
|
+
|
|
332
|
+
گیتهاب: 0hasanbagheri0
|
|
333
|
+
|
|
334
|
+
✨ اگر این کتابخانه برای شما مفید بود، به آن یک ⭐ در گیتهاب بدهید!
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
clean_data_tools-0.1.0.dist-info/licenses/LICENSE,sha256=rL-ShFgU5oeaikXXGM55veZaqeTbpEhE4lnDOdN81d0,1091
|
|
2
|
+
cleandata/__init__.py,sha256=7t2d_oGM1EEOCRgg52F7OcPOAVkodNh_PszoVS5lgF8,388
|
|
3
|
+
cleandata/cleaner.py,sha256=Viz7_Tt_e7lvAl0EDSPPIXjnlz5LwpJsHUweWKo980s,7249
|
|
4
|
+
cleandata/normalizer.py,sha256=x_jIzb9vGnZmvxaENLd-P0LS_sbD7hbQYsjZLjt_qi4,4173
|
|
5
|
+
cleandata/outlier.py,sha256=oYw6ng1LMm-lRoONPjv9LsenOOcPGS7oiq5HSCtXE6M,5079
|
|
6
|
+
cleandata/utils.py,sha256=xKqxKp9hIzWNX6M4SExsxoMQ8TNLDsokHoPPm7L8frY,2266
|
|
7
|
+
clean_data_tools-0.1.0.dist-info/METADATA,sha256=3GHJZwixBuI9HxKekQdgbMtwoz7M__ocSHQLCgwOelA,9898
|
|
8
|
+
clean_data_tools-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
9
|
+
clean_data_tools-0.1.0.dist-info/top_level.txt,sha256=Aeh0-TH-86FG7nBEMjYyK7ZzxgYRnHO_y27aZkEAITU,10
|
|
10
|
+
clean_data_tools-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Hasan Bagheri
|
|
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.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cleandata
|
cleandata/__init__.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Clean-Data - ابزارهای تمیزکاری و پیشپردازش دادهها
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .cleaner import DataCleaner
|
|
6
|
+
from .normalizer import Normalizer
|
|
7
|
+
from .outlier import OutlierDetector
|
|
8
|
+
from .utils import get_data_quality_report
|
|
9
|
+
|
|
10
|
+
__version__ = "0.1.0"
|
|
11
|
+
__all__ = [
|
|
12
|
+
"DataCleaner",
|
|
13
|
+
"Normalizer",
|
|
14
|
+
"OutlierDetector",
|
|
15
|
+
"get_data_quality_report"
|
|
16
|
+
]
|
cleandata/cleaner.py
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""
|
|
2
|
+
کلاس اصلی برای تمیزکاری دادهها
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import numpy as np
|
|
7
|
+
from typing import Union, Optional, List, Any
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
class DataCleaner:
|
|
11
|
+
"""
|
|
12
|
+
کلاس اصلی برای تمیزکاری دادهها
|
|
13
|
+
|
|
14
|
+
Examples:
|
|
15
|
+
>>> cleaner = DataCleaner(df)
|
|
16
|
+
>>> cleaner.remove_duplicates()
|
|
17
|
+
>>> cleaner.fill_missing("mean")
|
|
18
|
+
>>> df_clean = cleaner.get_data()
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, data: Union[pd.DataFrame, str, Path]):
|
|
22
|
+
"""
|
|
23
|
+
مقداردهی اولیه
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
data: دیتافریم پانداس یا مسیر فایل CSV/Excel
|
|
27
|
+
"""
|
|
28
|
+
if isinstance(data, (str, Path)):
|
|
29
|
+
self.df = self._load_data(data)
|
|
30
|
+
elif isinstance(data, pd.DataFrame):
|
|
31
|
+
self.df = data.copy()
|
|
32
|
+
else:
|
|
33
|
+
raise TypeError("ورودی باید دیتافریم پانداس یا مسیر فایل باشد")
|
|
34
|
+
|
|
35
|
+
self.original_df = self.df.copy()
|
|
36
|
+
self._changes_log = []
|
|
37
|
+
|
|
38
|
+
def _load_data(self, path: Union[str, Path]) -> pd.DataFrame:
|
|
39
|
+
"""بارگذاری داده از فایل"""
|
|
40
|
+
path = Path(path)
|
|
41
|
+
if path.suffix == '.csv':
|
|
42
|
+
return pd.read_csv(path)
|
|
43
|
+
elif path.suffix in ['.xlsx', '.xls']:
|
|
44
|
+
return pd.read_excel(path)
|
|
45
|
+
else:
|
|
46
|
+
raise ValueError("فرمت فایل پشتیبانی نمیشود. فقط CSV و Excel")
|
|
47
|
+
|
|
48
|
+
def get_data(self) -> pd.DataFrame:
|
|
49
|
+
"""دریافت دیتافریم تمیز شده"""
|
|
50
|
+
return self.df
|
|
51
|
+
|
|
52
|
+
def get_original(self) -> pd.DataFrame:
|
|
53
|
+
"""دریافت دیتافریم اصلی"""
|
|
54
|
+
return self.original_df
|
|
55
|
+
|
|
56
|
+
def get_changes_log(self) -> List[str]:
|
|
57
|
+
"""دریافت گزارش تغییرات"""
|
|
58
|
+
return self._changes_log
|
|
59
|
+
|
|
60
|
+
def _log_change(self, message: str):
|
|
61
|
+
"""ثبت تغییر در گزارش"""
|
|
62
|
+
self._changes_log.append(message)
|
|
63
|
+
|
|
64
|
+
def remove_duplicates(self, subset: Optional[List[str]] = None,
|
|
65
|
+
keep: str = 'first') -> 'DataCleaner':
|
|
66
|
+
"""
|
|
67
|
+
حذف رکوردهای تکراری
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
subset: لیست ستونها برای بررسی تکراری بودن
|
|
71
|
+
keep: 'first', 'last', یا False
|
|
72
|
+
"""
|
|
73
|
+
before = len(self.df)
|
|
74
|
+
self.df = self.df.drop_duplicates(subset=subset, keep=keep)
|
|
75
|
+
after = len(self.df)
|
|
76
|
+
self._log_change(f"حذف {before - after} رکورد تکراری")
|
|
77
|
+
return self
|
|
78
|
+
|
|
79
|
+
def fill_missing(self, method: Union[str, dict, int, float],
|
|
80
|
+
columns: Optional[List[str]] = None) -> 'DataCleaner':
|
|
81
|
+
"""
|
|
82
|
+
پر کردن مقادیر خالی
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
method: 'mean', 'median', 'mode', 'zero', یا مقدار دلخواه
|
|
86
|
+
columns: لیست ستونها (اگر None باشد، همه ستونها)
|
|
87
|
+
"""
|
|
88
|
+
if columns is None:
|
|
89
|
+
columns = self.df.columns
|
|
90
|
+
|
|
91
|
+
for col in columns:
|
|
92
|
+
if col not in self.df.columns:
|
|
93
|
+
continue
|
|
94
|
+
|
|
95
|
+
missing_count = self.df[col].isna().sum()
|
|
96
|
+
if missing_count == 0:
|
|
97
|
+
continue
|
|
98
|
+
|
|
99
|
+
if isinstance(method, dict):
|
|
100
|
+
fill_value = method.get(col, 0)
|
|
101
|
+
elif method == 'mean':
|
|
102
|
+
fill_value = self.df[col].mean()
|
|
103
|
+
elif method == 'median':
|
|
104
|
+
fill_value = self.df[col].median()
|
|
105
|
+
elif method == 'mode':
|
|
106
|
+
fill_value = self.df[col].mode()[0] if not self.df[col].mode().empty else 0
|
|
107
|
+
elif method == 'zero':
|
|
108
|
+
fill_value = 0
|
|
109
|
+
else:
|
|
110
|
+
fill_value = method
|
|
111
|
+
|
|
112
|
+
self.df[col] = self.df[col].fillna(fill_value)
|
|
113
|
+
self._log_change(f"پر کردن {missing_count} مقدار خالی در ستون '{col}'")
|
|
114
|
+
|
|
115
|
+
return self
|
|
116
|
+
|
|
117
|
+
def remove_missing(self, threshold: float = 0.5,
|
|
118
|
+
axis: int = 0) -> 'DataCleaner':
|
|
119
|
+
"""
|
|
120
|
+
حذف سطرها یا ستونهای با مقدار خالی زیاد
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
threshold: حداقل درصد دادههای غیر خالی (بین 0 تا 1)
|
|
124
|
+
axis: 0 برای سطر، 1 برای ستون
|
|
125
|
+
"""
|
|
126
|
+
before = len(self.df) if axis == 0 else len(self.df.columns)
|
|
127
|
+
self.df = self.df.dropna(thresh=int(threshold * len(self.df)), axis=axis)
|
|
128
|
+
after = len(self.df) if axis == 0 else len(self.df.columns)
|
|
129
|
+
self._log_change(f"حذف {before - after} {'سطر' if axis == 0 else 'ستون'}")
|
|
130
|
+
return self
|
|
131
|
+
|
|
132
|
+
def convert_types(self, columns: Optional[List[str]] = None) -> 'DataCleaner':
|
|
133
|
+
"""
|
|
134
|
+
تبدیل خودکار نوع ستونها (عددی، تاریخ، رشته)
|
|
135
|
+
"""
|
|
136
|
+
if columns is None:
|
|
137
|
+
columns = self.df.columns
|
|
138
|
+
|
|
139
|
+
for col in columns:
|
|
140
|
+
if col not in self.df.columns:
|
|
141
|
+
continue
|
|
142
|
+
|
|
143
|
+
try:
|
|
144
|
+
# تلاش برای تبدیل به عدد
|
|
145
|
+
self.df[col] = pd.to_numeric(self.df[col], errors='ignore')
|
|
146
|
+
except:
|
|
147
|
+
pass
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
# تلاش برای تبدیل به تاریخ
|
|
151
|
+
self.df[col] = pd.to_datetime(self.df[col], errors='ignore')
|
|
152
|
+
except:
|
|
153
|
+
pass
|
|
154
|
+
|
|
155
|
+
self._log_change("تبدیل خودکار انواع داده")
|
|
156
|
+
return self
|
|
157
|
+
|
|
158
|
+
def strip_strings(self, columns: Optional[List[str]] = None) -> 'DataCleaner':
|
|
159
|
+
"""حذف فاصلههای اضافی از رشتهها"""
|
|
160
|
+
if columns is None:
|
|
161
|
+
columns = self.df.select_dtypes(include=['object']).columns
|
|
162
|
+
|
|
163
|
+
for col in columns:
|
|
164
|
+
if col in self.df.columns and self.df[col].dtype == 'object':
|
|
165
|
+
self.df[col] = self.df[col].str.strip()
|
|
166
|
+
self._log_change("حذف فاصلههای اضافی از رشتهها")
|
|
167
|
+
return self
|
|
168
|
+
|
|
169
|
+
def rename_columns(self, mapping: dict) -> 'DataCleaner':
|
|
170
|
+
"""تغییر نام ستونها"""
|
|
171
|
+
self.df = self.df.rename(columns=mapping)
|
|
172
|
+
self._log_change(f"تغییر نام {len(mapping)} ستون")
|
|
173
|
+
return self
|
|
174
|
+
|
|
175
|
+
def filter_rows(self, condition: Any) -> 'DataCleaner':
|
|
176
|
+
"""فیلتر کردن سطرها بر اساس شرط"""
|
|
177
|
+
before = len(self.df)
|
|
178
|
+
self.df = self.df[condition]
|
|
179
|
+
after = len(self.df)
|
|
180
|
+
self._log_change(f"فیلتر کردن: {before - after} سطر حذف شد")
|
|
181
|
+
return self
|
|
182
|
+
|
|
183
|
+
def reset(self) -> 'DataCleaner':
|
|
184
|
+
"""بازگشت به دادههای اصلی"""
|
|
185
|
+
self.df = self.original_df.copy()
|
|
186
|
+
self._changes_log = []
|
|
187
|
+
self._log_change("بازگشت به دادههای اصلی")
|
|
188
|
+
return self
|
cleandata/normalizer.py
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""
|
|
2
|
+
توابع نرمالسازی دادهها
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import numpy as np
|
|
7
|
+
from typing import List, Optional, Union
|
|
8
|
+
|
|
9
|
+
class Normalizer:
|
|
10
|
+
"""
|
|
11
|
+
کلاس نرمالسازی دادهها
|
|
12
|
+
|
|
13
|
+
Examples:
|
|
14
|
+
>>> normalizer = Normalizer(df)
|
|
15
|
+
>>> df_scaled = normalizer.min_max_scale()
|
|
16
|
+
>>> df_standard = normalizer.standardize()
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, data: pd.DataFrame):
|
|
20
|
+
self.df = data.copy()
|
|
21
|
+
self._params = {}
|
|
22
|
+
|
|
23
|
+
def min_max_scale(self, columns: Optional[List[str]] = None,
|
|
24
|
+
feature_range: tuple = (0, 1)) -> pd.DataFrame:
|
|
25
|
+
"""
|
|
26
|
+
نرمالسازی Min-Max (مقیاسسازی به بازه مشخص)
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
columns: لیست ستونها (اگر None باشد، همه ستونهای عددی)
|
|
30
|
+
feature_range: بازه مورد نظر (min, max)
|
|
31
|
+
"""
|
|
32
|
+
if columns is None:
|
|
33
|
+
columns = self.df.select_dtypes(include=[np.number]).columns
|
|
34
|
+
|
|
35
|
+
result = self.df.copy()
|
|
36
|
+
for col in columns:
|
|
37
|
+
if col not in self.df.columns:
|
|
38
|
+
continue
|
|
39
|
+
|
|
40
|
+
min_val = self.df[col].min()
|
|
41
|
+
max_val = self.df[col].max()
|
|
42
|
+
|
|
43
|
+
if max_val - min_val == 0:
|
|
44
|
+
result[col] = 0
|
|
45
|
+
else:
|
|
46
|
+
result[col] = (self.df[col] - min_val) / (max_val - min_val) * (feature_range[1] - feature_range[0]) + feature_range[0]
|
|
47
|
+
|
|
48
|
+
self._params[col] = {'min': min_val, 'max': max_val}
|
|
49
|
+
|
|
50
|
+
return result
|
|
51
|
+
|
|
52
|
+
def standardize(self, columns: Optional[List[str]] = None) -> pd.DataFrame:
|
|
53
|
+
"""
|
|
54
|
+
استانداردسازی (میانگین صفر، انحراف معیار یک)
|
|
55
|
+
"""
|
|
56
|
+
if columns is None:
|
|
57
|
+
columns = self.df.select_dtypes(include=[np.number]).columns
|
|
58
|
+
|
|
59
|
+
result = self.df.copy()
|
|
60
|
+
for col in columns:
|
|
61
|
+
if col not in self.df.columns:
|
|
62
|
+
continue
|
|
63
|
+
|
|
64
|
+
mean = self.df[col].mean()
|
|
65
|
+
std = self.df[col].std()
|
|
66
|
+
|
|
67
|
+
if std == 0:
|
|
68
|
+
result[col] = 0
|
|
69
|
+
else:
|
|
70
|
+
result[col] = (self.df[col] - mean) / std
|
|
71
|
+
|
|
72
|
+
self._params[col] = {'mean': mean, 'std': std}
|
|
73
|
+
|
|
74
|
+
return result
|
|
75
|
+
|
|
76
|
+
def robust_scale(self, columns: Optional[List[str]] = None) -> pd.DataFrame:
|
|
77
|
+
"""
|
|
78
|
+
مقیاسسازی مقاوم به دادههای پرت (با استفاده از میانه و IQR)
|
|
79
|
+
"""
|
|
80
|
+
if columns is None:
|
|
81
|
+
columns = self.df.select_dtypes(include=[np.number]).columns
|
|
82
|
+
|
|
83
|
+
result = self.df.copy()
|
|
84
|
+
for col in columns:
|
|
85
|
+
if col not in self.df.columns:
|
|
86
|
+
continue
|
|
87
|
+
|
|
88
|
+
median = self.df[col].median()
|
|
89
|
+
q1 = self.df[col].quantile(0.25)
|
|
90
|
+
q3 = self.df[col].quantile(0.75)
|
|
91
|
+
iqr = q3 - q1
|
|
92
|
+
|
|
93
|
+
if iqr == 0:
|
|
94
|
+
result[col] = 0
|
|
95
|
+
else:
|
|
96
|
+
result[col] = (self.df[col] - median) / iqr
|
|
97
|
+
|
|
98
|
+
self._params[col] = {'median': median, 'iqr': iqr}
|
|
99
|
+
|
|
100
|
+
return result
|
|
101
|
+
|
|
102
|
+
def log_transform(self, columns: Optional[List[str]] = None) -> pd.DataFrame:
|
|
103
|
+
"""
|
|
104
|
+
تبدیل لگاریتمی (برای دادههای با توزیع چوله)
|
|
105
|
+
"""
|
|
106
|
+
if columns is None:
|
|
107
|
+
columns = self.df.select_dtypes(include=[np.number]).columns
|
|
108
|
+
|
|
109
|
+
result = self.df.copy()
|
|
110
|
+
for col in columns:
|
|
111
|
+
if col not in self.df.columns:
|
|
112
|
+
continue
|
|
113
|
+
|
|
114
|
+
# اطمینان از مثبت بودن دادهها
|
|
115
|
+
if (self.df[col] <= 0).any():
|
|
116
|
+
shift = abs(self.df[col].min()) + 1
|
|
117
|
+
result[col] = np.log1p(self.df[col] + shift)
|
|
118
|
+
else:
|
|
119
|
+
result[col] = np.log(self.df[col])
|
|
120
|
+
|
|
121
|
+
return result
|
cleandata/outlier.py
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""
|
|
2
|
+
تشخیص و حذف دادههای پرت (Outlier)
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import numpy as np
|
|
7
|
+
from typing import List, Optional, Union
|
|
8
|
+
from scipy import stats
|
|
9
|
+
|
|
10
|
+
class OutlierDetector:
|
|
11
|
+
"""
|
|
12
|
+
کلاس تشخیص و مدیریت دادههای پرت
|
|
13
|
+
|
|
14
|
+
Examples:
|
|
15
|
+
>>> detector = OutlierDetector(df)
|
|
16
|
+
>>> outliers = detector.detect_iqr()
|
|
17
|
+
>>> df_clean = detector.remove_outliers()
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, data: pd.DataFrame):
|
|
21
|
+
self.df = data.copy()
|
|
22
|
+
self.outliers_info = {}
|
|
23
|
+
|
|
24
|
+
def detect_iqr(self, columns: Optional[List[str]] = None,
|
|
25
|
+
multiplier: float = 1.5) -> dict:
|
|
26
|
+
"""
|
|
27
|
+
تشخیص دادههای پرت با روش IQR
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
columns: لیست ستونها
|
|
31
|
+
multiplier: ضریب (پیشفرض 1.5)
|
|
32
|
+
"""
|
|
33
|
+
if columns is None:
|
|
34
|
+
columns = self.df.select_dtypes(include=[np.number]).columns
|
|
35
|
+
|
|
36
|
+
outliers = {}
|
|
37
|
+
for col in columns:
|
|
38
|
+
if col not in self.df.columns:
|
|
39
|
+
continue
|
|
40
|
+
|
|
41
|
+
q1 = self.df[col].quantile(0.25)
|
|
42
|
+
q3 = self.df[col].quantile(0.75)
|
|
43
|
+
iqr = q3 - q1
|
|
44
|
+
|
|
45
|
+
lower_bound = q1 - multiplier * iqr
|
|
46
|
+
upper_bound = q3 + multiplier * iqr
|
|
47
|
+
|
|
48
|
+
mask = (self.df[col] < lower_bound) | (self.df[col] > upper_bound)
|
|
49
|
+
outliers[col] = {
|
|
50
|
+
'count': mask.sum(),
|
|
51
|
+
'indices': self.df.index[mask].tolist(),
|
|
52
|
+
'lower_bound': lower_bound,
|
|
53
|
+
'upper_bound': upper_bound
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
self.outliers_info = outliers
|
|
57
|
+
return outliers
|
|
58
|
+
|
|
59
|
+
def detect_zscore(self, columns: Optional[List[str]] = None,
|
|
60
|
+
threshold: float = 3) -> dict:
|
|
61
|
+
"""
|
|
62
|
+
تشخیص دادههای پرت با روش Z-Score
|
|
63
|
+
"""
|
|
64
|
+
if columns is None:
|
|
65
|
+
columns = self.df.select_dtypes(include=[np.number]).columns
|
|
66
|
+
|
|
67
|
+
outliers = {}
|
|
68
|
+
for col in columns:
|
|
69
|
+
if col not in self.df.columns:
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
z_scores = np.abs(stats.zscore(self.df[col].dropna()))
|
|
73
|
+
mask = z_scores > threshold
|
|
74
|
+
|
|
75
|
+
outliers[col] = {
|
|
76
|
+
'count': mask.sum(),
|
|
77
|
+
'indices': self.df.index[mask].tolist() if not mask.empty else []
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
self.outliers_info = outliers
|
|
81
|
+
return outliers
|
|
82
|
+
|
|
83
|
+
def remove_outliers(self, columns: Optional[List[str]] = None,
|
|
84
|
+
method: str = 'iqr',
|
|
85
|
+
threshold: float = 1.5) -> pd.DataFrame:
|
|
86
|
+
"""
|
|
87
|
+
حذف رکوردهای حاوی دادههای پرت
|
|
88
|
+
"""
|
|
89
|
+
result = self.df.copy()
|
|
90
|
+
|
|
91
|
+
if columns is None:
|
|
92
|
+
columns = self.df.select_dtypes(include=[np.number]).columns
|
|
93
|
+
|
|
94
|
+
mask = pd.Series([False] * len(result), index=result.index)
|
|
95
|
+
|
|
96
|
+
for col in columns:
|
|
97
|
+
if col not in self.df.columns:
|
|
98
|
+
continue
|
|
99
|
+
|
|
100
|
+
if method == 'iqr':
|
|
101
|
+
q1 = self.df[col].quantile(0.25)
|
|
102
|
+
q3 = self.df[col].quantile(0.75)
|
|
103
|
+
iqr = q3 - q1
|
|
104
|
+
lower = q1 - threshold * iqr
|
|
105
|
+
upper = q3 + threshold * iqr
|
|
106
|
+
mask |= (self.df[col] < lower) | (self.df[col] > upper)
|
|
107
|
+
|
|
108
|
+
elif method == 'zscore':
|
|
109
|
+
z_scores = np.abs(stats.zscore(self.df[col].dropna()))
|
|
110
|
+
mask |= pd.Series(z_scores > threshold, index=self.df.index).fillna(False)
|
|
111
|
+
|
|
112
|
+
result = result[~mask]
|
|
113
|
+
return result
|
|
114
|
+
|
|
115
|
+
def replace_outliers(self, columns: Optional[List[str]] = None,
|
|
116
|
+
method: str = 'median',
|
|
117
|
+
multiplier: float = 1.5) -> pd.DataFrame:
|
|
118
|
+
"""
|
|
119
|
+
جایگزینی دادههای پرت با میانگین، میانه یا مقدار دلخواه
|
|
120
|
+
"""
|
|
121
|
+
result = self.df.copy()
|
|
122
|
+
|
|
123
|
+
if columns is None:
|
|
124
|
+
columns = self.df.select_dtypes(include=[np.number]).columns
|
|
125
|
+
|
|
126
|
+
for col in columns:
|
|
127
|
+
if col not in self.df.columns:
|
|
128
|
+
continue
|
|
129
|
+
|
|
130
|
+
q1 = self.df[col].quantile(0.25)
|
|
131
|
+
q3 = self.df[col].quantile(0.75)
|
|
132
|
+
iqr = q3 - q1
|
|
133
|
+
lower = q1 - multiplier * iqr
|
|
134
|
+
upper = q3 + multiplier * iqr
|
|
135
|
+
|
|
136
|
+
mask = (self.df[col] < lower) | (self.df[col] > upper)
|
|
137
|
+
|
|
138
|
+
if method == 'mean':
|
|
139
|
+
replacement = self.df[col].mean()
|
|
140
|
+
elif method == 'median':
|
|
141
|
+
replacement = self.df[col].median()
|
|
142
|
+
else:
|
|
143
|
+
replacement = method
|
|
144
|
+
|
|
145
|
+
result.loc[mask, col] = replacement
|
|
146
|
+
|
|
147
|
+
return result
|
cleandata/utils.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""
|
|
2
|
+
توابع کمکی برای گزارشگیری از کیفیت داده
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import numpy as np
|
|
7
|
+
from typing import Dict, Any
|
|
8
|
+
|
|
9
|
+
def get_data_quality_report(df: pd.DataFrame) -> Dict[str, Any]:
|
|
10
|
+
"""
|
|
11
|
+
دریافت گزارش کامل از کیفیت دادهها
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
دیکشنری شامل: تعداد سطرها، ستونها، مقادیر خالی، تکراریها، نوع دادهها، و ...
|
|
15
|
+
"""
|
|
16
|
+
report = {
|
|
17
|
+
'shape': {
|
|
18
|
+
'rows': len(df),
|
|
19
|
+
'columns': len(df.columns)
|
|
20
|
+
},
|
|
21
|
+
'missing': {},
|
|
22
|
+
'duplicates': {
|
|
23
|
+
'count': df.duplicated().sum(),
|
|
24
|
+
'percentage': (df.duplicated().sum() / len(df)) * 100
|
|
25
|
+
},
|
|
26
|
+
'data_types': df.dtypes.to_dict(),
|
|
27
|
+
'statistics': {},
|
|
28
|
+
'memory_usage': df.memory_usage(deep=True).sum() / 1024 # KB
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# بررسی مقادیر خالی
|
|
32
|
+
for col in df.columns:
|
|
33
|
+
missing_count = df[col].isna().sum()
|
|
34
|
+
report['missing'][col] = {
|
|
35
|
+
'count': missing_count,
|
|
36
|
+
'percentage': (missing_count / len(df)) * 100
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# آمار توصیفی برای ستونهای عددی
|
|
40
|
+
numeric_cols = df.select_dtypes(include=[np.number]).columns
|
|
41
|
+
for col in numeric_cols:
|
|
42
|
+
report['statistics'][col] = {
|
|
43
|
+
'min': df[col].min(),
|
|
44
|
+
'max': df[col].max(),
|
|
45
|
+
'mean': df[col].mean(),
|
|
46
|
+
'median': df[col].median(),
|
|
47
|
+
'std': df[col].std(),
|
|
48
|
+
'unique': df[col].nunique()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return report
|
|
52
|
+
|
|
53
|
+
def get_column_info(df: pd.DataFrame, column: str) -> Dict[str, Any]:
|
|
54
|
+
"""دریافت اطلاعات کامل یک ستون خاص"""
|
|
55
|
+
if column not in df.columns:
|
|
56
|
+
raise ValueError(f"ستون '{column}' در دیتافریم وجود ندارد")
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
'name': column,
|
|
60
|
+
'dtype': str(df[column].dtype),
|
|
61
|
+
'missing_count': df[column].isna().sum(),
|
|
62
|
+
'missing_percentage': (df[column].isna().sum() / len(df)) * 100,
|
|
63
|
+
'unique_values': df[column].nunique(),
|
|
64
|
+
'memory_usage': df[column].memory_usage(deep=True) / 1024 # KB
|
|
65
|
+
}
|