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.
@@ -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
+ [![PyPI version](https://badge.fury.io/py/clean-data.svg)](https://badge.fury.io/py/clean-data)
29
+ [![Python 3.7+](https://img.shields.io/badge/python-3.7+-blue.svg)](https://www.python.org/downloads/)
30
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -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
@@ -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
+ }