0Pricing
Pandas & NumPy Academy · درس

توحيد الفئات غير المتسقة

وحّد أعمدة الفئات ذات النص الحر عبر تعيين الأسماء البديلة وتصحيح الأخطاء الإملائية بالمطابقة التقريبية وفرض قائمة معيارية.

توحيد الفئات غير المتسقة درس مجاني في Pandas & NumPy Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Pandas & NumPy Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Pandas & NumPy Academy 4 دروس في المجموع.

بعض أجزاء هذا الدرس لم تُترجم بعد وتظهر باللغة الإنجليزية.

The Problem of Inconsistent Categories

When category data is entered by humans, the same concept appears under many different spellings: Electronics, electronics, ELECTRONICS, Electronicss. A groupby on this column produces dozens of tiny groups instead of one meaningful group. Standardising categories into a canonical list is one of the most important cleaning steps before any aggregation or machine learning feature creation.

import pandas as pd

df = pd.read_csv('products.csv')
print(df['category'].value_counts().head(20))

Normalising Case and Whitespace

The first and easiest standardisation step is normalising case and whitespace. Apply .str.strip().str.lower() to remove leading/trailing spaces and convert everything to lowercase before any other comparison. This single step collapses many variants: Electronics, electronics, and ' Electronics ' all become electronics after normalisation.

df['category_clean'] = df['category'].str.strip().str.lower()

print('Before:', df['category'].nunique())
print('After:', df['category_clean'].nunique())

Mapping Aliases with a Dict

After case normalisation, many variants are still distinct due to abbreviations, synonyms, or legacy names. Build an alias mapping dictionary where keys are variant spellings and values are the canonical form. Apply it with df['category_clean'].map(alias_map).fillna(df['category_clean']) — the fillna preserves values not in the dictionary rather than replacing them with NaN.

alias_map = {
    'elect': 'electronics',
    'elec': 'electronics',
    'tech': 'electronics',
    'clothing': 'apparel',
    'clothes': 'apparel',
    'garments': 'apparel'
}

df['category_clean'] = df['category_clean'].map(alias_map).fillna(df['category_clean'])
print(df['category_clean'].value_counts().head())

Using str.replace for Pattern Fixes

Some category names have consistent formatting errors like double spaces or trailing numbers. Use .str.replace() with a regular expression to fix these patterns across all rows at once. For example, .str.replace(r'\s+', ' ', regex=True) collapses multiple spaces into one, and .str.replace(r'\d+$', '', regex=True) strips trailing digits from category names.

df['category_clean'] = (
    df['category_clean']
    .str.replace(r'\s+', ' ', regex=True)  # collapse spaces
    .str.replace(r'\d+$', '', regex=True)   # strip trailing numbers
    .str.strip()
)

print(df['category_clean'].value_counts())

Fuzzy Matching with difflib

When typos are unpredictable, use fuzzy matching to find the closest canonical category for each variant. Python's built-in difflib.get_close_matches() returns the best matches from a list of valid categories based on string similarity. Apply it as a helper function via df['category'].apply() to resolve variants that map() alone cannot catch.

from difflib import get_close_matches

CANONICAL = ['electronics', 'apparel', 'home', 'sports', 'beauty']

def fuzzy_fix(val):
    matches = get_close_matches(str(val).lower().strip(), CANONICAL, n=1, cutoff=0.7)
    return matches[0] if matches else val

df['category_fuzzy'] = df['category_clean'].apply(fuzzy_fix)
print(df[['category_clean', 'category_fuzzy']].head(10))

Building a Canonical Category List

Define your canonical categories explicitly rather than inferring them from the data. A hard-coded list forces every value through a validation gate; anything not in the list is flagged as unknown. Maintain the canonical list in a config file or a separate DataFrame column so it is easy to update when the business adds a new product category without touching the cleaning code.

CANONICAL_CATEGORIES = {
    'electronics', 'apparel', 'home', 'sports',
    'beauty', 'food', 'toys', 'automotive'
}

df['is_known_category'] = df['category_fuzzy'].isin(CANONICAL_CATEGORIES)
unknown = df[~df['is_known_category']]['category_fuzzy'].unique()
print('Unknown categories remaining:', unknown)

Handling Unknown Categories

Unknown categories that do not match any canonical value after fuzzy fixing should be grouped under an Other label rather than dropped, so you do not silently lose rows. Set them to 'other' with np.where() or a simple conditional assignment. Log how many rows were mapped to 'other' and review them for patterns that might warrant a new canonical category.

import numpy as np

df['category_final'] = np.where(
    df['category_fuzzy'].isin(CANONICAL_CATEGORIES),
    df['category_fuzzy'],
    'other'
)

print(df['category_final'].value_counts())

Enforcing a Categorical Dtype

After standardisation, convert the clean category column to a Pandas Categorical dtype with an explicit list of valid categories. This enforces the schema: any attempt to assign an invalid category raises an error. It also reduces memory by storing category strings as integer codes internally, and speeds up groupby operations on large DataFrames.

df['category_final'] = pd.Categorical(
    df['category_final'],
    categories=list(CANONICAL_CATEGORIES) + ['other']
)

print(df['category_final'].dtype)
print(df['category_final'].cat.categories)

Validating the Clean Column

After all standardisation steps, run a final validation: assert that no value outside the canonical set exists in the cleaned column. Use assert df['category_final'].isin(valid_set).all(). Place this assertion at the end of the cleaning function so it runs every time the pipeline executes, catching regressions when new raw data contains previously unseen category labels.

valid_set = set(CANONICAL_CATEGORIES) | {'other'}

assert df['category_final'].isin(valid_set).all(), 'Invalid category found'
print('All categories valid. Distribution:')
print(df['category_final'].value_counts())

Tracking the Standardisation Changes

Build a diff table showing the original value and its cleaned replacement for every row that changed. This audit trail lets data owners review and approve or reject specific mappings. Use a boolean mask to select changed rows and compare the original and final columns side by side. Export the diff as a CSV for non-technical stakeholders to review.

changed = df['category'] != df['category_final']
diff_table = df[changed][['category', 'category_final']].drop_duplicates()
diff_table.columns = ['original', 'mapped_to']
print(f'Unique mappings applied: {len(diff_table)}')
print(diff_table)

Saving the Standardised Dataset

Replace the original messy category column with the standardised one and drop intermediate working columns before saving. Store the alias mapping dictionary and the fuzzy-fix cutoff threshold in the pipeline config so the standardisation is fully reproducible. A cleaning run two months later on a new data dump should produce identical results for the same input values.

df_out = df.drop(columns=['category_clean', 'category_fuzzy', 'is_known_category'])
df_out = df_out.rename(columns={'category_final': 'category'})

df_out.to_parquet('products_clean.parquet', index=False)
print('Saved. Category distribution:')
print(df_out['category'].value_counts())

Quick Check

Test your understanding of Data Analysis concepts from this lesson.

Lesson Recap

In this lesson you learned: normalising case and whitespace as a first standardisation step, mapping aliases and applying fuzzy matching for typo correction, and enforcing a canonical category list with Categorical dtype and assertions. Next up we explore schema validation and runtime assertions to guard every pipeline stage.

الأسئلة الشائعة

هل درس «توحيد الفئات غير المتسقة» مجاني؟

نعم — نص درس «توحيد الفئات غير المتسقة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Pandas & NumPy Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Pandas & NumPy Academy 4 دروس في المجموع.

ماذا ستتعلم في «توحيد الفئات غير المتسقة»؟

وحّد أعمدة الفئات ذات النص الحر عبر تعيين الأسماء البديلة وتصحيح الأخطاء الإملائية بالمطابقة التقريبية وفرض قائمة معيارية. تتمرن على Pandas & NumPy Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Pandas & NumPy Academy؟

لا تُشترط خبرة سابقة. Pandas & NumPy Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.

كم من الوقت يستغرق درس «توحيد الفئات غير المتسقة»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Pandas & NumPy Academy هذا؟

نعم. كل درس في Pandas & NumPy Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. اكتشاف التكرارات وإزالتها
  2. اكتشاف القيم الشاذة ومعالجتها
  3. توحيد الفئات غير المتسقة
  4. التحقق من المخطط والتأكيدات
← العودة إلى Pandas & NumPy Academy