Pandas: تحويل البيانات
آخر تحديث: 2026-08-26
الخطوة الأخيرة في تنظيف البيانات هي "التحويل" — إعادة تشكيل البيانات الخام إلى الشكل الذي تتطلبه تحليلاتك: تحويل الدرجات إلى تقديرات، والأسعار إلى خصومات، وربط العمليات متعددة الخطوات معًا. توفر أدوات pandas مثل map / apply / pipe / replace / assign / transform مجموعة أدوات تحويل متعددة المستويات تمتد من العناصر الفردية إلى الجداول بأكملها. يتناول هذا القسم حالات الاستخدام والمزالق في الأداء لكل طريقة.
1. What You Will Learn
- ❶ map element mapping
- ❷ apply row/column functions
- ❸ pipe chaining
- ❹ replace value replacement
- ❺ assign new columns
- ❻ transform group transformation
2. تحويل درجات أليس
(1) المشكلة: تحويل الدرجات من مقياس 0-100 إلى درجات حرفية ABCD
أليس لديها درجات 100 طالب على مقياس من 0 إلى 100، وتحتاج إلى تحويلها إلى درجات حرفية:
import pandas as pd
scores = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie', 'Carol', 'David'],
'score': [92, 78, 65, 88, 45]
})
# كيف نحول 0-100 إلى A/B/C/D/F؟
> **المخرجات:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعلية قليلاً اعتماداً على إصدار pandas.
(2) الحل: map + التعيين باستخدام القاموس
▶ مثال
> **المخرجات:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعلية قليلاً اعتماداً على إصدار pandas.
: map التعيين باستخدام القاموس (صعوبة ⭐)
import pandas as pd
scores = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie', 'Carol', 'David'],
'score': [92, 78, 65, 88, 45]
})
# الخطوة 1: تعريف دالة تحويل الدرجة إلى درجة حرفية
def score_to_grade(s):
if s >= 90: return 'A'
elif s >= 80: return 'B'
elif s >= 70: return 'C'
elif s >= 60: return 'D'
else: return 'F'
# الخطوة 2: تطبيق الدالة باستخدام map
scores['grade'] = scores['score'].map(score_to_grade)
print(scores)
# name score grade
# 0 Alice 92 A
# 1 Bob 78 C
# 2 Charlie 65 D
# 3 Carol 88 B
# 4 David 45 F
> **المخرجات:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعلية قليلاً اعتماداً على إصدار pandas.
3. تعيين عنصر map
(1) ثلاث طرق لاستخدام map
▶ مثال
> **Output:** Run in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.
: ثلاث طرق للتعيين باستخدام map (صعوبة ⭐⭐)
import pandas as pd
s = pd.Series([1, 2, 3, 4, 5])
# 1. Dictionary mapping
category_map = {1: 'Low', 2: 'Low', 3: 'Medium', 4: 'High', 5: 'High'}
print(s.map(category_map))
# 0 Low
# 1 Low
# 2 Medium
# 3 High
# 4 High
# 2. Function mapping
print(s.map(lambda x: x ** 2))
# 0 1
# 1 4
# 2 9
# 3 16
# 4 25
# 3. Series mapping (align by index)
other = pd.Series({1: 'One', 2: 'Two', 3: 'Three'})
print(s.map(other))
# 0 NaN ← 1 exists in other → 'One'
# 1 Two
# 2 Three
# 3 NaN ← 4 not in other → NaN
# 4 NaN
> **Output:** Run in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.
(2) متى تستخدم map
| الميزة | map | apply |
|---|---|---|
| يعمل على | عناصر السلسلة الفردية | صفوف/أعمدة السلسلة / إطار البيانات |
| المدخلات | قاموس/دالة/سلسلة | دالة |
| الإرجاعات | سلسلة (تعيين واحد إلى واحد) | أي نوع |
| الأداء | سريع (بحث القاموس O(1)) | أبطئ (استدعاءات لكل عنصر/صف/عمود) |
| الأفضل لـ | تعيين واحد إلى واحد | منطق معقد/عمليات متعددة الأعمدة |
4. تطبيق دوال الصفوف/الأعمدة
(1) تطبيق Series (السلسلة)
▶ مثال
> **الناتج:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). لا يحتوي خادم Pandas على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعليهة قليلاً حسب إصدار pandas.
: تطبيق Series (الصعوبة ⭐⭐)
import pandas as pd
s = pd.Series(['alice@example.com', 'bob@company.org', 'charlie@uni.edu'])
# استخراج النطاق من البريد الإلكتروني
domains = s.apply(lambda email: email.split('@')[1])
print(domains)
# 0 example.com
# 1 company.org
# 2 uni.edu
# منطق معقد: تصنيف نوع البريد الإلكتروني
def classify_email(email):
domain = email.split('@')[1]
if '.edu' in domain: return 'Academic'
elif '.org' in domain: return 'Non-profit'
else: return 'Commercial'
email_type = s.apply(classify_email)
print(email_type)
# 0 Commercial
# 1 Non-profit
# 2 Academic
> **الناتج:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). لا يحتوي خادم Pandas على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعليهة قليلاً حسب إصدار pandas.
(2) تطبيق DataFrame (إطار البيانات)
▶ مثال
> **الناتج:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). لا يحتوي خادم Pandas على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعليهة قليلاً حسب إصدار pandas.
: تطبيق عمليات الصفوف/الأعمدة على DataFrame (الصعوبة ⭐⭐)
import pandas as pd
import numpy as np
df = pd.DataFrame({
'math': [85, 92, 78, 88, 65],
'english': [90, 85, 82, 75, 70],
'science': [88, 95, 80, 90, 60]
}, index=['Alice', 'Bob', 'Charlie', 'Carol', 'David'])
# تطبيق الدالة على كل عمود (axis=0، الافتراضي)
print(df.apply(np.mean))
# math 81.6
# english 80.4
# science 82.6
# تطبيق الدالة على كل صف (axis=1)
df['average'] = df.apply(lambda row: row.mean(), axis=1)
print(df['average'])
# Alice 87.67
# Bob 90.67
# Charlie 80.00
# Carol 84.33
# David 65.00
# إرجاع Series لكل صف (أكثر تنظيمًا)
def score_report(row):
return pd.Series({
'total': row.sum(),
'avg': row.mean(),
'max': row.max(),
'min': row.min()
})
report = df[['math', 'english', 'science']].apply(score_report, axis=1)
print(report)
> **الناتج:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). لا يحتوي خادم Pandas على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعليهة قليلاً حسب إصدار pandas.
apply ليست عملية متوجهة (vectorized) — استدعاء دالة صفًا بصف على DataFrame كبير سيكون بطيئًا جدًا. إذا كنت قادرًا على استخدام العمليات المتوجهة (العمليات الحسابية، طرق str)، فلا تستخدم apply. apply هي "الملاذ الأخير عندما لا يعمل أي شيء آخر."
5. تسلسل الأنابيب (pipe Chaining)
(1) تدفق البيانات المتسلسل
▶ مثال
> **الخرج:** شغّل في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والاتباع. القيم الفعلية قد تختلف قليلاً حسب إصدار pandas.
: عمليات خط أنابيب (الصعوبة ⭐⭐)
import pandas as pd
import numpy as np
# Raw data
df = pd.DataFrame({
'name': [' Alice ', 'BOB', 'Charlie', ' carol ', 'David'],
'age': [28, -1, 25, 30, 999],
'salary': [75000, np.nan, 68000, 88000, np.nan]
})
# Step-by-step without pipe (nested calls)
# result = assign_dept(replace_invalid(clean_names(df)))
# With pipe — readable left-to-right flow
def clean_names(df):
df = df.copy()
df['name'] = df['name'].str.strip().str.title()
return df
def replace_invalid(df):
df = df.copy()
df.loc[df['age'] < 0, 'age'] = np.nan
df.loc[df['age'] > 150, 'age'] = np.nan
return df
def fill_salary(df):
df = df.copy()
df['salary'] = df['salary'].fillna(df['salary'].median())
return df
result = (df
.pipe(clean_names)
.pipe(replace_invalid)
.pipe(fill_salary)
)
print(result)
> **الخرج:** شغّل في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والاتباع. القيم الفعلية قد تختلف قليلاً حسب إصدار pandas.
(2) مقارنة بين pipe و apply
| الميزة | pipe | apply |
|---|---|---|
| المدخلات | إطار البيانات بالكامل | صف/عمود/سلسلة |
| الإرجاع | إطار بيانات (محوّل) | أي نوع |
| الغرض | خط أنابيب متعدد الخطوات | عمليات عنصر/صف/عمود من خطوة واحدة |
| التسلسل | ✅ مدعوم بشكل أصلي | ❌ يتطلب التداخل |
| سهولة القراءة | عالية (تقرأ من الأعلى إلى الأسفل) | متوسطة |
6. استبدال القيمة
(1) الاستبدال الدقيق
▶ مثال
> **Output:** Run in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.
: استبدال القيمة (الصعوبة ⭐)
import pandas as pd
import numpy as np
df = pd.DataFrame({
'status': ['active', 'inactive', 'pending', 'active', 'unknown'],
'priority': [1, 2, 3, 1, 99]
})
# Single value replacement
df['status'] = df['status'].replace('unknown', 'inactive')
print(df['status'])
# Multiple values replacement (dict)
df['status'] = df['status'].replace({
'active': 'Active',
'inactive': 'Inactive',
'pending': 'Pending'
})
print(df['status'])
# Replace invalid sentinel value
df['priority'] = df['priority'].replace(99, np.nan)
print(df['priority'])
# Regex replacement
text = pd.Series(['Phone: 555-0100', 'Email: test@example.com'])
cleaned = text.str.replace(r'[\d-]+', '[REDACTED]', regex=True)
print(cleaned)
> **Output:** Run in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.
(2) مقارنة replace و map
| الميزة | replace | map |
|---|---|---|
| القيم غير المطابقة | تبقى دون تغيير | تصبح NaN |
| استبدال قيم متعددة | ✅ قاموس | ✅ قاموس |
| Regex | ✅ regex=True | ❌ |
| الأنسب لـ | استبدال قيم محددة | تعيين كامل |
7. تعيين أعمدة جديدة
(1) ربط أعمدة جديدة متعددة
▶ مثال
> **الإخراج:** قم بالتشغيل في بيئة Python محلية (pandas 2.x). لا تحتوي خادم Pandas على pandas مثبته مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) واتباع الخطوات. قد تختلف القيم الفعلية قليلاً حسب إصدار pandas.
: تعيين أعمدة جديدة (الصعوبة ⭐⭐)
import pandas as pd
df = pd.DataFrame({
'price': [100, 200, 150, 80, 300],
'quantity': [5, 3, 10, 8, 2],
'discount': [0.1, 0.2, 0.0, 0.15, 0.05]
})
# Add multiple columns in one chain
result = (df
.assign(
discounted_price=lambda x: x['price'] * (1 - x['discount']),
total=lambda x: x['discounted_price'] * x['quantity'],
is_bulk=lambda x: x['quantity'] >= 5
)
)
print(result)
# price quantity discount discounted_price total is_bulk
# 0 100 5 0.10 90.0 450.0 True
# 1 200 3 0.20 160.0 480.0 False
# 2 150 10 0.00 150.0 1500.0 True
# 3 80 8 0.15 68.0 544.0 True
# 4 300 2 0.05 285.0 570.0 False
> **الإخراج:** قم بالتشغيل في بيئة Python محلية (pandas 2.x). لا تحتوي خادم Pandas على pandas مثبته مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) واتباع الخطوات. قد تختلف القيم الفعلية قليلاً حسب إصدار pandas.
assign، استخدم lambda x: للإشارة إلى DataFrame الحالية. يمكنك الإشارة إلى أعمدة تم إنشاؤها مسبقاً ضمن نفس استدعاء assign (على سبيل المثال، total تشير إلى discounted_price). هذا يجعله أكثر ملاءمة للربط مقارنةً بنص df['new_col'] = ....
8. تحويل المجموعة باستخدام transform
(1) transform يحافظ على الشكل الأصلي
▶ مثال
> **Output:** Run in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.
: معايرونة المجموعة باستخدام transform (الصعوبة ⭐⭐)
import pandas as pd
import numpy as np
df = pd.DataFrame({
'student': ['Alice', 'Alice', 'Bob', 'Bob', 'Charlie', 'Charlie'],
'subject': ['Math', 'English', 'Math', 'English', 'Math', 'English'],
'score': [85, 90, 92, 88, 78, 82]
})
# Z-score normalization within each student
df['z_score'] = df.groupby('student')['score'].transform(
lambda x: (x - x.mean()) / x.std()
)
print(df)
# Fill with group mean (instead of global mean)
df['score_filled'] = df.groupby('student')['score'].transform('mean')
print(df[['student', 'score', 'score_filled']])
# Rank within group
df['rank_in_class'] = df.groupby('subject')['score'].transform('rank', method='min')
print(df[['student', 'subject', 'score', 'rank_in_class']])
> **Output:** Run in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.
(2) مقارنة transform و apply
| الميزة | transform | apply |
|---|---|---|
| شكل الإخراج | نفس الإدخال | يمكن أن يتغير |
| بعد groupby | يعيد نتائج بنفس الطول لكل مجموعة | يعيد أي نتيجة لكل مجموعة |
| التجميع | ❌ لا يمكن التجميع | ✅ يمكن |
| البث | ✅ يبث تلقائياً إلى الصفوف الأصلية | ❌ |
| الاستخدامات الشائعة | المعايرونة/الملء/الترتيب | التجميع/الحسابات المعقدة |
9. اختيار طريقة التحويل المناسبة
(1) مرجع سريع لـ 6 طرق تحويل
graph TB
Q["هل تحتاج لتحويل البيانات؟"] --> TYPE{"نوع التحويل؟"}
TYPE -->|"تعيين واحد إلى واحد"| MAP["map()"]
TYPE -->|"دالة على صف/عمود"| APPLY["apply()"]
TYPE -->|"خط خطوات متعدد"| PIPE["pipe()"]
TYPE -->|"استبدال قيم محددة"| REPLACE["replace()"]
TYPE -->|"إضافة أعمدة جديدة"| ASSIGN["assign()"]
TYPE -->|"تحويل على مستوى المجموعة"| TRANS["transform()"]
MAP --> NOTE1["✅ قاموس/دالة<br>❌ غير مُعيّن ← NaN"]
APPLY --> NOTE2["⚠️ بطيء لإطارات البيانات الكبيرة<br>✅ مرن"]
PIPE --> NOTE3["✅ سلسلة قابلة للقراءة<br>✅ خطوات قابلة لإعادة الاستخدام"]
REPLACE --> NOTE4["✅ القيم غير المتطابقة محفوظة<br>✅ يدعم التعبيرات النمطية"]
ASSIGN --> NOTE5["✅ صديق للسلاسل<br>✅ أعمدة متعددة"]
TRANS --> NOTE6["✅ ناتج بنفس الشكل<br>✅ بث للمجموعة"]
> **الناتج:** قم بالتشغيل في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّتًا مسبقًا. يرجى تثبيته محليًا (`pip install pandas`) والمتابعة. قد تختلف القيم الفعلي قليلاً حسب إصدار pandas.
(2) ترتيب الأداء
| الترتيب | الطريقة | الأداء | السبب |
|---|---|---|---|
| 1 | العمليات المُتجسدة | الأسرع | تنفيذ على مستوى C، بدون حلقة بايثون |
| 2 | map (قاموس) | سريع | بحث O(1) |
| 3 | replace | سريع | مُحسّن داخليًا |
| 4 | map (دالة) | متوسط | استدعاءات دوال لكل عنصر |
| 5 | apply | بطيء | استدعاءات بايثون لكل صف/عمود |
| 6 | apply + منطق معقد | الأبطأ | تراكم تكلفة الدوال |
df['col'] * 2، فلا تكتب df['col'].apply(lambda x: x * 2). العمليات المُتجسدة أسرع بـ 10-100 مرة من apply.
10. مثال كامل: خط تحويل بيانات التجارة الإلكترونية
▶ مثال
> **Output:** Run in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.
: خط تحويل بيانات كامل (الصعوبة ⭐⭐⭐)
import pandas as pd
import numpy as np
# ============================================
# مثال شامل: تحويل بيانات التجارة
# الإلكترونية
# ============================================
# 1. البيانات الخام
np.random.seed(42)
df = pd.DataFrame({
'product': [f'Item_{i:03d}' for i in range(1, 21)],
'category': np.random.choice(['Electronics', 'Clothing', 'Home'], 20),
'price': np.round(np.random.uniform(10, 500, 20), 2),
'cost': np.round(np.random.uniform(5, 250, 20), 2),
'quantity_sold': np.random.randint(1, 100, 20),
'rating': np.round(np.random.uniform(2.0, 5.0, 20), 1)
})
# 2. خط معالجة خطوة بخطوة باستخدام pipe
def add_margin(df):
df = df.copy()
df['margin_pct'] = ((df['price'] - df['cost']) / df['price'] * 100).round(1)
return df
def categorize_price(df):
df = df.copy()
df['price_tier'] = df['price'].map(
lambda p: 'Budget' if p < 50 else ('Mid' if p < 200 else 'Premium')
)
return df
def add_revenue(df):
return df.assign(
revenue=lambda x: x['price'] * x['quantity_sold'],
is_top_rated=lambda x: x['rating'] >= 4.0
)
def normalize_rating(df):
df = df.copy()
df['rating_zscore'] = df.groupby('category')['rating'].transform(
lambda x: (x - x.mean()) / x.std()
)
return df
# 3. تنفيذ الخط
result = (df
.pipe(add_margin)
.pipe(categorize_price)
.pipe(add_revenue)
.pipe(normalize_rating)
)
# 4. ملخص
print("=== Transformation Result ===")
print(result[['product', 'category', 'price_tier', 'margin_pct', 'revenue', 'is_top_rated']].head(10))
print(f"\nTotal revenue: ${result['revenue'].sum():,.2f}")
print(f"Top-rated items: {result['is_top_rated'].sum()}")
print(f"Price tier distribution:\n{result['price_tier'].value_counts()}")
> **الخرج:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبته مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. القيم الفعلية قد تختلف قليلاً حسب إصدار pandas.
❓ أسئلة شائعة
df['a'] + df['b']، فلا تكتب df.apply(lambda r: r['a']+r['b'], axis=1). apply هي الملاذ الأخير.f3(f2(f1(df))) إلى df.pipe(f1).pipe(f2).pipe(f3)، حيث يمنحك القراءة من أعلى إلى أسفل ترتيب التنفيذ.df['col']=...؟df['col']=... يُعدّل الأصل مباشرة. داخل assign، يمكنك استخدام lambda للإشارة إلى أعمدة تم إنشاظها في نفس الخطوة، وهو ما لا يمكن للإسناد المباشر فعله. التوصية: استخدم assign للعمليات المتسلسلة؛ في الحالات البسيطة، الإسناد المباشر مقبول.df['a'] + df['b'] هي عملية مُشتَّتة (حساب على مستوى C عبر المصفوفة بأكملها)، بينما df.apply(lambda r: r['a']+r['b'], axis=1) ليست كذلك (استدعاءات Python صفًا بصف). العمليات المُشتَّتة أسرع بـ 10-100 مرة. استخدم العمليات المدمجة كلما أمكن بدلاً من apply.📖 ملخص
- map مخصص لتعيين السلسلة واحد لواحد؛ تعيين القاموس هو الأسرع؛ القيم غير المتطابقة تتحول إلى NaN
- apply يعالج منطقًا معقدًا لكل صف/عمود — مرن لكنه بطيء؛ يُفضل استخدام العمليات المتجهة عند الإمكان
- pipe يبني خطوط أنابيب متعددة الخطوات، محولًا الاستدعاءات المتداخلة إلى سلسلة مقروءة من الأعلى إلى الأسفل
- replace يستبدل قيمًا محددة مع الاحتفاظ بالقيم غير المتطابقة دون تغيير؛ يدعم التعبيرات النمطية
- transform يُجري تحويلات المجموعة مع الحفاظ على الشكل الأصلي؛ مثالي للتوحيد/الملء/الترتيب
- ترتيب الأداء: العمليات المتجهة > map(قاموس) > replace > map(دالة) > apply
📝 تمارين
- أساسي (صعوبة ⭐): أنشئ سلسلة (Series) للدرجات (0-100). استخدم
mapمع قاموس لتصنيف الدرجات إلى عالية (≥70)/متوسطة (≥50)/منخفضة (<50)، ثم استخدمreplaceلتغيير "متوسطة" إلى "متوسط". - متوسط (صعوبة ⭐⭐): أنشئ إطار بيانات (DataFrame) للموظفين (الاسم/الراتب/القسم). استخدم
pipeلبناء خط أنابيب من 3 خطوات: تنظيف الاسم (strip+title) → إضافة عمود للراتب بعد الضريبة → تحديد ما إذا كان كل موظف يكسب أكثر من متوسط قسمه. - تحدي (صعوبة ⭐⭐⭐): أنشئ مجموعة بيانات منتجات تحتوي على 20 صفًا. استخدم
assignلإضافة 3 أعمدة دفعة واحدة (الإيرادات/الهامش/الفئة)، استخدمgroupby+transformلحساب الدرجات المعيارية (z-scores) داخل كل فئة، وأخيرًا استخدمpipeلدمج جميع الخطوات في خط أنابيب واحد.
← Previous: Handling Duplicate Data · Next: Group Aggregation →