Pandas: أنواع البيانات
آخر تحديث: 2026-08-26
يحدد نوع البيانات (dtype) كيفية تخزين Pandas لبياناتك والتعامل معها. اختر النوع الصحيح من dtype وستتمكن من تشغيل كودك بسرعة أكبر 10 مرات مع استخدام ذاكرة أقل بنسبة 80%؛ أما اختيار النوع الخطأ فيواجهك فقدان الدقة، وأخطاء في العمليات، وانفجارات في استهلاك الذاكرة. يأخذك هذا القسم في جولة عبر نظام dtype في Pandas، ليساعدك على فهم خصائص كل نوع وطرق التحويل بينها، بالإضافة إلى أكثر تقنيات تحسين الذاكرة عملية.
1. ما ستتعلمه
- ❶ الفرق بين نظام أنواع البيانات في Pandas وأنواع بيانات NumPy
- ❷ الاختيار بين كائن و StringDtype و category
- ❸ تحويل الأنواع باستخدام astype / convert_dtypes / infer_objects
- ❹ الأنواع القابلة للقيم المفقودة (Int64 / Float64 / منطقي)
- ❺ استراتيجيات تحسين استخدام الذاكرة (category / downcast)
2. أزمة انفجار ذاكرة بوب
(1) نقطة الألم: جدول عملاء بحجم 500 ميجابايت
حمل بوب مجموعة بيانات العملاء في DataFrame وفحص استخدام الذاكرة — 500 ميجابايت! 100 ألف صف لا ينبغي أن يشغل كل هذا المساحة:
import pandas as pd
# Load customer data (simulated)
df = pd.DataFrame({
'customer_id': range(100000),
'name': ['Customer_' + str(i) for i in range(100000)],
'city': ['New York', 'London', 'Tokyo', 'Paris', 'Sydney'] * 20000,
'age': [25 + i % 50 for i in range(100000)],
'loyalty_points': [100 + i * 10 for i in range(100000)]
})
print(f"Memory before optimization: {df.memory_usage(deep=True).sum() / 1024 / 1024:.1f} MB")
# Typical output: ~18 MB (this example is small)
# Real 100K-row dataset with many string columns can reach 500+ MB
> **المخرجات:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليًلا اعتمادًا على إصدار pandas الخاص بك.
المتسبب: نوع الكائن. بشكل افتراضي، يقوم Pandas بأعمدة النصوص بتخزينها كـ كائن (مؤشرات كائنات Python)، حيث يكون كل عنصر كائن نص Python كامل — وهو عبء ضخم على الذاكرة.
(2) الحل: ضغط 10 أضعاف باستخدام النوع category
▶ مثال
> **المخرجات:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليًلا اعتمادًا على إصدار pandas الخاص بك.
: تحسين الذاكرة باستخدام category (الصعوبة ⭐⭐)
import pandas as pd
df = pd.DataFrame({
'customer_id': range(100000),
'name': ['Customer_' + str(i) for i in range(100000)],
'city': ['New York', 'London', 'Tokyo', 'Paris', 'Sydney'] * 20000,
'age': [25 + i % 50 for i in range(100000)],
'loyalty_points': [100 + i * 10 for i in range(100000)]
})
# Check memory before optimization
mem_before = df.memory_usage(deep=True).sum() / 1024 / 1024
# Optimize: city has only 5 unique values → category
df['city'] = df['city'].astype('category')
# Optimize: age range 25-74 → int8 is enough (max 127)
df['age'] = df['age'].astype('int8')
# Optimize: loyalty_points range → int32 is enough
df['loyalty_points'] = df['loyalty_points'].astype('int32')
mem_after = df.memory_usage(deep=True).sum() / 1024 / 1024
print(f"Before: {mem_before:.1f} MB")
print(f"After: {mem_after:.1f} MB")
print(f"Saved: {(1 - mem_after/mem_before)*100:.0f}%")
# Before: ~18 MB
# After: ~5 MB
# Saved: ~72%
> **المخرجات:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليًلا اعتمادًا على إصدار pandas الخاص بك.
(3) العائد: 3 تقنيات تحسين أساسية
| التقنية | التأثير | متى تُستخدم |
|---|---|---|
| كائن→category | تقليل الذاكرة بنسبة 90%+ | سلاسل منخفضة التعددية (القيم الفريدة < 50% من عدد الصفوف) |
| int64→int8/int16/int32 | تقليل الذاكرة بنسبة ~75% | نطاقات عددية صغيرة |
| float64→float32 | تقليل الذاكرة بنسبة 50% | متطلبات دقة منخفضة |
3. نظام أنواع البيانات (dtype) في Pandas
(1) المشهد الكامل للأنواع
graph TB
DT["Pandas dtype"] --> NUM["Numeric"]
DT --> STR["String-like"]
DT --> DT_TYPE["Datetime"]
DT --> BOOL["Boolean"]
DT --> CAT["Categorical"]
DT --> NULL["Nullable"]
NUM --> I["int8/16/32/64"]
NUM --> UI["uint8/16/32/64"]
NUM --> F["float32/float64"]
STR --> O["object (legacy)"]
STR --> SD["StringDtype (new)"]
DT_TYPE --> DT64["datetime64[ns]"]
DT_TYPE --> TD64["timedelta64[ns]"]
BOOL --> PB["bool (NumPy)"]
BOOL --> NB["boolean (Nullable)"]
NULL --> NI["Int8/16/32/64"]
NULL --> NF["Float32/64"]
NULL --> NBO["boolean"]
NULL --> NS["string"]
> **الخرج:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). لا يحتوي خادم Pandas على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعليّة قليلاً اعتماداً على إصدار pandas لديك.
(2) نوع بيانات Pandas مقابل نوع بيانات NumPy
| الميزة | نوع بيانات NumPy | نوع بيانات Pandas |
|---|---|---|
| الأنواع الرقمية | int8~64 / float32~64 | نفس NumPy + الأنواع القابلة للتعليق (Int64/Float64) |
| السلاسل النصية | كائن | كائن / StringDtype / سلسلة |
| القيم المنطقية (Boolean) | bool | bool / منطقي (قابل للتعليق) |
| القيم المفقودة | np.nan (float فقط) | NaN / NaT / pd.NA (تغطية كاملة) |
| الفئات (Categorical) | لا يوجد | category |
| الوقت | datetime64 | datetime64[ns] / timedelta64[ns] |
| الامتداد (Extension) | لا يوجد | ExtensionDtype (مخصص) |
pd.NA لتمثيل القيم المفقودة بشكل موحد، مما حل المشكلة القديمة المتمثلة في أن "أعمدة الأعداد الصحيحة لا يمكنها احتواء NaN."
4. كائن مقابل StringDtype مقابل category
(1) مقارنة بين الثلاثة
| الميزة | كائن | StringDtype | category |
|---|---|---|---|
| التخزين الأساسي | مؤشرات كائنات بايثون | تخزين سلاسل نصية مخصص | أكواد عددية كاملة + جدول بحث |
| القيم المفقودة | None / np.nan | pd.NA | pd.NA |
| الذاكرة | الأعلى | المتوسطة | الأقل (لعدد منخفض من القيم الفريدة) |
| الطرق النصية | مُوصِل .str accessor | مُوصِل .str accessor | مُوصِل .str accessor |
| المقارنات | قد تكون غير متسقة | متسقة | متسقة |
| الترتيب | المعجمي (Lexicographic) | المعجمي | يدعم ترتيب مخصص |
| الأفضل لـ | التوافق مع الكود القديم | مُوصى به للمشاريع الجديدة | الأعمدة ذات عدد منخفض من القيم الفريدة |
▶ مثال
> **الخرج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مُثبَّتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) لاتباع المثال. قد تختلف القيم الفعلية قليًًا حسب إصدار pandas الخاص بك.
: مقارنة استهلاك الذاكرة بين الأنواع الثلاثة (الصعوبة ⭐⭐)
import pandas as pd
import numpy as np
# 1000 صف، 5 مدن فريدة
cities = ['New York', 'London', 'Tokyo', 'Paris', 'Sydney']
data = [cities[i % 5] for i in range(1000)]
s_object = pd.Series(data, dtype='object')
s_string = pd.Series(data, dtype='string')
s_category = pd.Series(data, dtype='category')
print(f"object: {s_object.memory_usage(deep=True) / 1024:.1f} KB")
print(f"string: {s_string.memory_usage(deep=True) / 1024:.1f} KB")
print(f"category: {s_category.memory_usage(deep=True) / 1024:.1f} KB")
# object: ~62 KB
# string: ~55 KB
# category: ~5 KB ← أصغر بـ 12 مرة!
> **الخرج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مُثبَّتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) لاتباع المثال. قد تختلف القيم الفعلية قليًًا حسب إصدار pandas الخاص بك.
category يستخدم فعليًا ذاكرة أكثر من object — لأنه يحتاج إلى الحفاظ على جدول تعيين كامل. القاعدة العامة: تكون category مفيدة عندما تكون القيم الفريدة أقل من 50% من عدد الصفوف.
5. طرق تحويل الأنواع
(1) astype: التحويل الصريح
▶ مثال
> **الإخراج:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعليّة قليلًا اعتمادًا على إصدار pandas الخاص بك.
: astype تحويل الأنواع (الصعوبة ⭐)
import pandas as pd
df = pd.DataFrame({
'price_str': ['9.99', '19.99', '29.99'],
'quantity_int': [1, 3, 5],
'flag_str': ['True', 'False', 'True']
})
# من سلسلة نصية إلى عدد عشري
df['price'] = df['price_str'].astype(float)
# من عدد صحيح إلى سلسلة نصية (لأعمدة المعرّفات)
df['qty_str'] = df['quantity_int'].astype(str)
# من سلسلة نصية إلى قيمة منطقية (انتبه: 'True'/'False' كنصوص → bool)
df['flag'] = df['flag_str'].map({'True': True, 'False': False})
print(df.dtypes)
# price_str object
# quantity_int int64
# flag_str object
# price float64
# qty_str object
# flag bool
> **الإخراج:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعليّة قليلًا اعتمادًا على إصدار pandas الخاص بك.
(2) convert_dtypes: استنتاج أفضل نوع تلقائيًا
▶ مثال
> **الإخراج:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعليّة قليلًا اعتمادًا على إصدار pandas الخاص بك.
: convert_dtypes التحويل التلقائي (الصعوبة ⭐⭐)
import pandas as pd
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie'],
'age': [28, 34, 25],
'score': [85.5, 92.0, 78.3],
'active': [True, True, False]
})
# التحويل إلى أفضل أنواع قابلة لل null
df_converted = df.convert_dtypes()
print(df_converted.dtypes)
# name string ← object → StringDtype
# age Int64 ← int64 → nullable Int64
# score Float64 ← float64 → nullable Float64
# active boolean ← bool → nullable boolean
> **الإخراج:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعليّة قليلًا اعتمادًا على إصدار pandas الخاص بك.
(3) infer_objects: استنتاج أفضل نوع لأعمدة الكائنات
▶ مثال
> **الإخراج:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعليّة قليلًا اعتمادًا على إصدار pandas الخاص بك.
: infer_objects الاستنتاج (الصعوبة ⭐)
import pandas as pd
df = pd.DataFrame({
'a': [1, 2, 3], # مخزن كـ object
'b': ['x', 'y', 'z'] # يبقى كـ object
}, dtype='object')
print(df.dtypes)
# a object
# b object
df_inferred = df.infer_objects()
print(df_inferred.dtypes)
# a int64 ← تم استنتاجه من المحتوى
# b object ← لا يزال object (النصوص تبقى)
> **الإخراج:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعليّة قليلًا اعتمادًا على إصدار pandas الخاص بك.
(4) مقارنة طرق التحويل
| الطريقة | الغرض | تلقائي/يدوي | قابل للـ فارغ |
|---|---|---|---|
| astype() | إجبار التحويل إلى نوع محدد | يدوي | ليس تلقائيًا |
| convert_dtypes() | استنتاج أفضل نوع قابل للـ فارغ | تلقائي | نعم |
| infer_objects() | استنتاج نوع أعمدة الكائنات | تلقائي | ليس تلقائيًا |
6. أنواع Nullable: حل مشكلة القيم المفقودة في الأعداد الصحيحة
(1) لماذا تحتاج أنواع Nullable
لا يمكن لـ int64 في NumPy تخزين NaN — عندما يحتوي عمود من الأعداد الصحيحة على قيم مفقودة، يُضطر Pandas إلى ترقية العمود بالكامل إلى float64، مما يفقد النوع الأصلي.
▶ مثال
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
: Nullable مقابل الأنواع التقليدية (الصعوبة ⭐⭐)
import pandas as pd
import numpy as np
# Traditional: int column with NaN → forced to float
s_trad = pd.Series([1, 2, np.nan, 4])
print(s_trad) # 1.0, 2.0, NaN, 4.0 — floats!
print(s_trad.dtype) # float64
# Nullable: Int64 keeps integer type with <NA>
s_null = pd.Series([1, 2, pd.NA, 4], dtype='Int64')
print(s_null) # 1, 2, <NA>, 4 — integers!
print(s_null.dtype) # Int64
# Nullable boolean
b_null = pd.Series([True, False, pd.NA], dtype='boolean')
print(b_null)
# Nullable string
str_null = pd.Series(['Alice', pd.NA, 'Charlie'], dtype='string')
print(str_null)
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
(2) لمحة عن أنواع Nullable
| النوع القابل لل-فارغ | المقابل التقليدي | علامة القيمة المفقودة | متى تُستخدم |
|---|---|---|---|
| Int8/16/32/64 | int8/16/32/64 | pd.NA | أعمدة الأعداد الصحيحة التي تحتوي على قيم مفقودة |
| Float32/64 | float32/64 | pd.NA | أعمدة الأعداد العشرية التي تحتوي على قيم مفقودة |
| منطقي | bool | pd.NA | أعمدة القيم المنطقية (Boolean) التي تحتوي على قيم مفقودة |
| سلسلة | كائن | pd.NA | أعمدة النصوص (تستبدل كائن) |
pd.NA لتمثيل القيم المفقودة بشكل موحد، مما يحل محل المزيج الفوضوي من np.nan / None / NaT. أثناء العمليات، يتبع pd.NA "قاعدة الانتشار" — أي عملية تتضمن pd.NA تُرجع pd.NA.
7. تحسين الذاكرة في الممارسة العملية
(1) التحقق من استخدام الذاكرة
▶ مثال
> **الخرج:** قم بتشغيل هذا في بيئة Python المحلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليلاً حسب إصدار pandas الخاص بك.
: تحليل memory_usage (الصعوبة ⭐)
import pandas as pd
df = pd.DataFrame({
'id': range(10000),
'city': ['New York', 'London', 'Tokyo', 'Paris', 'Sydney'] * 2000,
'score': [85.5 + i * 0.1 for i in range(10000)],
'status': ['Active', 'Inactive', 'Pending'] * 3333 + ['Active']
})
# استخدام الذاكرة لكل عمود (deep=True لأعمدة الكائنات)
print(df.memory_usage(deep=True))
# Index 80
# id 80000 ← int64 لـ 10 آلاف صف
# city 630000 ← كائن (ضخم!)
# score 80000 ← float64
# status 460000 ← كائن (ضخم!)
# الإجمالي
total = df.memory_usage(deep=True).sum() / 1024 / 1024
print(f"الإجمالي: {total:.1f} ميجابايت")
> **الخرج:** قم بتشغيل هذا في بيئة Python المحلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليلاً حسب إصدار pandas الخاص بك.
(2) استراتيجيات التحسين
▶ مثال
> **الخرج:** قم بتشغيل هذا في بيئة Python المحلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليلاً حسب إصدار pandas الخاص بك.
: تحسين الذاكرة من البداية للنهاية (الصعوبة ⭐⭐⭐)
import pandas as pd
df = pd.DataFrame({
'id': range(10000),
'city': ['New York', 'London', 'Tokyo', 'Paris', 'Sydney'] * 2000,
'score': [85.5 + i * 0.1 for i in range(10000)],
'status': ['Active', 'Inactive', 'Pending'] * 3333 + ['Active']
})
mem_before = df.memory_usage(deep=True).sum() / 1024 / 1024
# 1. أعمدة النص ذات الحد الأدنى من القيم الفريدة → فئة
df['city'] = df['city'].astype('category')
df['status'] = df['status'].astype('category')
# 2. تقليص النطاق العددي
df['id'] = pd.to_numeric(df['id'], downcast='integer') # int64 → int16
df['score'] = pd.to_numeric(df['score'], downcast='float') # float64 → float32
mem_after = df.memory_usage(deep=True).sum() / 1024 / 1024
print(f"قبل: {mem_before:.1f} ميجابايت")
print(f"بعد: {mem_after:.1f} ميجابايت")
print(f"وفّر: {(1 - mem_after/mem_before)*100:.0f}%")
print(f"\nأنواع البيانات المحسّنة:")
print(df.dtypes)
> **الخرج:** قم بتشغيل هذا في بيئة Python المحلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليلاً حسب إصدار pandas الخاص بك.
(3) جدول مرجعي لتقليص النطاق
| النوع الأصلي | downcast='integer' | downcast='float' | التوفير |
|---|---|---|---|
| int64 | int8/int16/int32 (يختار الأصغر تلقائيًا) | — | 50%~75% |
| float64 | — | float32 | 50% |
| uint64 | uint8/uint16/uint32 | — | 50%~75% |
8. مثال كامل: تحسين جدول عملاء كبير
▶ مثال
> **الإخراج:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبته مسبقاً — قم بتثبيته محلياً (`pip install pandas`) للمتابعة. قد تتغير القيم الفعليبة قليلاً حسب إصدار pandas الخاص بك.
: خط أنابيب تحسين كامل لجدول العملاء (الصعوبة ⭐⭐⭐)
import pandas as pd
import numpy as np
# ============================================
# مثال شامل: جدول العملاء
# خط أنابيب التحسين الكامل
# ============================================
# 1. إنشاء بيانات عملاء واقعية
n = 50000
df = pd.DataFrame({
'customer_id': range(n),
'name': [f'Customer_{i:05d}' for i in range(n)],
'city': np.random.choice(['New York', 'London', 'Tokyo', 'Paris',
'Sydney', 'Berlin', 'Toronto', 'Seoul'], n),
'age': np.random.randint(18, 80, n),
'membership': np.random.choice(['Basic', 'Silver', 'Gold', 'Platinum'], n),
'points': np.random.randint(0, 100000, n),
'satisfaction': np.random.choice([1, 2, 3, 4, 5, np.nan], n, p=[0.05,0.1,0.2,0.3,0.3,0.05])
})
# 2. التحليل قبل التحسين
print("=== BEFORE Optimization ===")
print(df.dtypes)
mem_before = df.memory_usage(deep=True).sum() / 1024 / 1024
print(f"Total memory: {mem_before:.1f} MB")
# 3. التحسين
# سلاسل نصية منخفضة البطاقة → فئة
for col in ['city', 'membership']:
df[col] = df[col].astype('category')
# تخفيض الأعداد الصحيحة
for col in ['customer_id', 'age', 'points']:
df[col] = pd.to_numeric(df[col], downcast='integer')
# عدد عشري مع NaN → Int64 قابل للnull
df['satisfaction'] = df['satisfaction'].astype('Int8')
# 4. التحليل بعد التحسين
print("\n=== AFTER Optimization ===")
print(df.dtypes)
mem_after = df.memory_usage(deep=True).sum() / 1024 / 1024
print(f"Total memory: {mem_after:.1f} MB")
print(f"Saved: {(1 - mem_after/mem_before)*100:.0f}%")
# 5. التحقق من سلامة البيانات
print(f"\n=== Integrity Check ===")
print(f"Rows: {len(df)}")
print(f"Satisfaction with NaN: {df['satisfaction'].isna().sum()}")
print(f"Unique cities: {df['city'].nunique()}")
> **الإخراج:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبته مسبقاً — قم بتثبيته محلياً (`pip install pandas`) للمتابعة. قد تتغير القيم الفعليبة قليلاً حسب إصدار pandas الخاص بك.
❓ أسئلة شائعة
astype('int64'))، بينما convert_dtypes يستنتج تلقائيًا أفضل نوع Nullable (كائن→سلسلة، int64→Int64، float64→Float64). astype أكثر دقة؛ convert_dtypes أكثر راحة.df.memory_usage(deep=True) عدد البايتات لكل عمود. يحسب deep=True الذاكرة الفعلية للسلاسل النصية في أعمدة كائن (وليس فقط أحجام المؤشرات). df.info(memory_usage='deep') يُظهر أيضًا الذاكرة الإجمالية.pd.to_numeric(downcast=...) تلقائيًا أصغر نوع يمكنه استيعاب نطاق البيانات. على سبيل المثال، الأعداد الصحيحة من 0-100 ستختار uint8 (0-255) بدون فيض. ولكن إذا أضفت لاحقًا بيانات خارج هذا النطاق، فقد يتم اقتصاصها أو ترقيتها بهدوء. من الأفضل تشغيل تخفيض الدقة كخطوة نهائية بعد اكتمال تنظيف البيانات.📖 ملخص
- نظام dtype في Pandas أكثر غنى من NumPy: فهو يضيف أنواع Nullable، وفئة (category)، وStringDtype
- كائن يستهلك ذاكرة بشكل كبير — يجب تحويل أعمدة السلاسل النصية ذات الكاردينالية المنخفضة إلى category (تخفيض ذاكرة بنسبة 90%+)
- أنواع Nullable (Int64/Float64/منطقي/سلسلة) تستخدم pd.NA لتوحيد القيم المفقودة، مما يحل مشكلة "أعمدة الأعداد الصحيحة لا تستطيع استيعاب NaN"
astypeيحول الأنواع يدويًا، وconvert_dtypesيستنتج أنواع Nullable تلقائيًا، وinfer_objectsيستنتج الأنواع لأعمدة كائن- ثلاث خطط لتحسين الذاكرة: سلاسل نصية ذات كاردينالية منخفضة → category → تقليص حجم الأنواع الرقمية (downcast) → float64→float32
- استخدم
memory_usage(deep=True)لرؤية استخدام الذاكرة الحقيقي — الذاكرة الفعلية لأعمدة كائن تتجاوز بكثير حجم المؤشر - قم بتشغيل
downcastبعد اكتمال تنظيف البيانات لتجنب تجاوز البيانات لاحقًا لنطاق النوع
📝 تمارين
- أساسي (صعوبة ⭐): قم بإنشاء DataFrame يحتوي على 3 أعمدة (سلسلة نصية/عدد صحيح/عدد عشري). تحقق من الأنواع باستخدام
dtypes، ثم استخدمastypeلتحويل العمود الصحيح إلىint8والعمود العشري إلىfloat32. قارن التغيير فيmemory_usage. - متوسط (صعوبة ⭐⭐): أنشئ Series عددية صحيحة تحتوي على NaN. تعامل معها بالطريقة التقليدية (التي يتم تحويلها تلقائيًا إلى
float64) ومع نوعNullable Int64، ثم قارن بينdtypeوسلوك العمليات. بعد ذلك، قم بتحسين عمود سلسلة نصية يحتوي على 5 قيم فريدة باستخدام نوعcategory. - تحدي (صعوبة ⭐⭐⭐): قم بإنشاء DataFrame محاكٍ يحتوي على 10,000 صف و 4 أعمدة (سلسلة نصية ذات بطاقة منخفضة / سلسلة نصية ذات بطاقة عالية / عدد صحيح / عدد عشري). قم بتشغيل خطوة تحسين الذاكرة الكاملة: فحص → بطاقة منخفضة → category → downcast → Nullable → تحقق. اطبع تغيير الذاكرة في كل خطوة ونسبة التوفير النهائية.