ساخت تابع پایتون برای پاکسازی داده ها — راهنمای کاربردی

۲۱۶ بازدید
آخرین به‌روزرسانی: ۳۱ اردیبهشت ۱۴۰۲
زمان مطالعه: ۵ دقیقه
ساخت تابع پایتون برای پاکسازی داده ها — راهنمای کاربردی

در این مطلب، چگونگی ساخت تابع پایتون برای پاکسازی داده ها شرح داده شده است. «تحلیل اکتشافی داده‌ها» (Exploratory Data Analysis | EDA) و «پاک‌سازی داده‌ها» (Data Cleaning) دو گام اساسی پیش از آغاز توسعه یک مدل «یادگیری ماشین» (Machine Learning) محسوب می‌شوند. این دو گام، به ویژه برای افرادی که تازه در حال کسب تجربه در این زمینه‌ها هستند، کاری بسیار زمان‌بر به شمار می‌آید.

ساخت تابع پایتون برای پاکسازی داده ها

تحلیل اکتشافی داده‌ها و پاکسازی داده‌ها، معمولا یک فرایند خطی و تک مرحله‌ای نیست. گاهی کاربر مجبور می‌شود که بارها به بخش‌های پیشین برود و مجموعه داده مورد استفاده برای تحلیل را ویرایش کند. یک راهکار برای سرعت بخشیدن به این فرایند، بازیابی برخی از کدهایی است که فرد ممکن است طی فرایند پاک‌سازی داده‌ها و تحلیل داده اکتشافی، چندین و چند بار از آن‌ها استفاده کند.

به همین دلیل است که باید توابعی برای خودکارسازی فرایند تکرار شونده تحلیل داده اکتشافی و پاک‌سازی داده‌ها ساخته شوند. دیگر مزیت استفاده از توابع برای فرایندهای بیان شده، حذف ناسازگاری ایجاد شده در نتایج به دلیل تفاوت‌هایی است که به طور تصادفی در کدها ایجاد شده‌اند. در این مطلب، توابع پایتونی معرفی و ساخته شده‌اند که برای کارهای تحلیل اکتشافی داده‌ها و پاک‌سازی داده‌ها قابل استفاده هستند. کتابخانه‌ای که حاوی همه این توابع است را می‌توان از مخزن [+] کلون کرد.

توابعی برای مدیریت مقادیر ناموجود یا گم‌شده

یک گام مهم در تحلیل اکتشافی داده‌ها، وارسی مقادیر ناموجود یا گم‌شده (Missing Values) و بررسی این است که آیا الگوی خاصی در مقادیر ناموجود وجود دارد؟ همچنین، باید تصمیمی پیرامون چگونگی مواجهه با این داده‌ها اتخاذ شود.

اولین تابعی که در اینجا وجود دارد، برای دادن یک ایده کلی پیرامون تعداد کل و درصد داده‌ها در هر ستون است.

1def intitial_eda_checks(df):
2    '''
3    Takes df
4    Checks nulls
5    '''
6    if df.isnull().sum().sum() > 0:
7        mask_total = df.isnull().sum().sort_values(ascending=False) 
8        total = mask_total[mask_total > 0]
9
10        mask_percent = df.isnull().mean().sort_values(ascending=False) 
11        percent = mask_percent[mask_percent > 0] 
12
13        missing_data = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])
14    
15        print(f'Total and Percentage of NaN:\n {missing_data}')
16    else: 
17        print('No NaN found.')

پس از وارسی اولیه، می‌توان تصمیم گرفت که آیا نیاز است بررسی نزدیک‌تری روی ستون‌های حاوی مقادیر از دست رفته انجام شود یا خیر. با تعیین آستانه برای درصد مقادیر ناموجود، تابعی که در ادامه می‌آید یک لیست از ستون‌های حاوی مقادیر ناموجود را که تعداد مقادیر ناموجود آن‌ها بیشتر از آستانه است، ارائه می‌کند.

1def view_columns_w_many_nans(df, missing_percent):
2    '''
3    Checks which columns have over specified percentage of missing values
4    Takes df, missing percentage
5    Returns columns as a list
6    '''
7    mask_percent = df.isnull().mean()
8    series = mask_percent[mask_percent > missing_percent]
9    columns = series.index.to_list()
10    print(columns) 
11    return columns

راهکارهای زیادی برای مواجهه با این مقادیر ناموجود وجود دارد. اگر کاربر تصمیم بگیرد که ستون‌های حاوی مقادیر ناموجود زیاد را حذف کند (فراتر از آستانه‌ای که تعریف می‌کند)، می‌تواند از تابعی که در ادامه آمده است برای انجام این کار استفاده کند.

def drop_columns_w_many_nans(df, missing_percent):
    '''
    Takes df, missing percentage
    Drops the columns whose missing value is bigger than missing percentage
    Returns df
    '''
    series = view_columns_w_many_nans(df, missing_percent=missing_percent)
    list_of_cols = series.index.to_list()
    df.drop(columns=list_of_cols)
    print(list_of_cols)
    return df

اگرچه، نقاط ضعف زیادی متوجه حذف کامل مقادیر ناموجود از مجموعه داده است؛ از جمله این موارد می‌توان به کاهش قدرت آماری اشاره کرد. اگر کاربر تصمیم بگیرد که مقادیر ناموجود را جایگزین کند، می‌تواند از راهکارهای گوناگون موجود برای این کار را استفاده و احتمال آسیب زدن به داده‌ها و خروجی نهایی را کاهش دهد.

توابع بصری‌سازی داده‌ها

مغز انسان در شناسایی الگوها بسیار عالی عمل می‌کند و به همین دلیل است که بصری‌سازی داده‌ها در طول فرایند تحلیل اکتشافی داده‌ها و شناسایی الگوها می‌تواند سودمند باشد. برای مثال، «بافت‌نگارها» (Histograms) می‌توانند تحلیل توزیع داده‌ها را آسان‌تر کنند. «نمودار جعبه‌ای» (Boxplot) ابزار خوبی برای شناسایی دورافتادگی‌ها است. «نمودار نقطه‌ای» (Scatter Plot) هنگامی که بحث از بررسی همبستگی بین دو متغیر می‌شود، گزینه بسیار مناسبی است. کتابخانه‌های پایتون «مت‌پلات‌لیب» (Matplotlib) و «سیبورن» (Seaborn) از مهم‌ترین، مفیدترین و کاربردی‌ترین کتابخانه‌ها در بحث بصری‌سازی داده‌ها محسوب می‌شوند.

اگرچه، ساخت نمودارهای جدا برای هر متغیر، می‌تواند کاری خسته کننده باشد؛ به ویژه هنگامی که تعداد زیادی از ویژگی‌ها وجود دارند. در این بخش، به بررسی توابعی برای ساخت یک گروه از نمودارها پرداخته می‌شود که می‌توانند به کاربر برای زدن چند نشان با یک تیر، کمک بسیار زیادی کنند. در این راستا، معمولا نگاهی به توزیع ستون‌ها با مقادیر عددی انداخته می‌شود. تابعی که در ادامه آمده است، یک گروه از نمودارها را برای همه ستون‌های عددی در مجموعه داده می‌سازد.

1def histograms_numeric_columns(df, numerical_columns):
2    '''
3    Takes df, numerical columns as list
4    Returns a group of histagrams
5    '''
6    f = pd.melt(df, value_vars=numerical_columns) 
7    g = sns.FacetGrid(f, col='variable',  col_wrap=4, sharex=False, sharey=False)
8    g = g.map(sns.distplot, 'value')
9    return g

خروجی کامل به صورت زیر خواهد بود.

ساخت تابع پایتون برای پاکسازی داده ها -- راهنمای کاربردی

دیگر ابزار بصری‌سازی مفید، «نقشه حرارتی» (Heatmap) است. نقشه‌های حرارتی برای بررسی همبستگی بین متغیرهای مستقل و غیر مستقل بسیار مناسب است. اغلب اوقات، نمودارهای گرمایشی در صورت وجود تعداد متغیرهای بسیار زیاد، ممکن است شلوغ و به هم ریخته به نظر بیایند. یک راهکار برای جلوگیری از این موضوع، ساخت نقشه گرمایشی برای متغیر وابسته (هدف) و متغیرهای و مسقل (ویژگی‌ها) است. تابع ارائه شده در زیر، می‌تواند به کاربر برای انجام این کار کمک شایان توجهی کند.

1def heatmap_numeric_w_dependent_variable(df, dependent_variable):
2    '''
3    Takes df, a dependant variable as str
4    Returns a heatmap of all independent variables' correlations with dependent variable 
5    '''
6    plt.figure(figsize=(8, 10))
7    g = sns.heatmap(df.corr()[[dependent_variable]].sort_values(by=dependent_variable), 
8                    annot=True, 
9                    cmap='coolwarm', 
10                    vmin=-1,
11                    vmax=1) 
12    return g

ساخت تابع پایتون برای پاکسازی داده ها -- راهنمای کاربردی

توابعی برای تغییر انواع داده‌ها

حصول اطمینان از اینکه ویژگی‌ها دارای نوع داده (Data Type) درستی هستند، یک گام مهم در فرایند تحلیل اکتشافی داده‌ها و پاک‌سازی داده‌ها محسوب می‌شود. این کار معمولا انجام می‌شود، زیرا که متد read_csv()‎. انواع داده‌ها را به صورتی متفاوت از فایل داده‌های اصلی تفسیر می‌کند.

خواندن دیکشنری داده‌ها می‌تواند در این راستا بسیار کمک کننده و شفاف کننده مسأله باشد. علاوه بر آن، اگر کاربر در صدد انجام مهندسی ویژگی‌ها باشد، نیاز به تغییر انواع داده‌ها وجود دارد. دو تابع زیر، دست به دست هم برای تبدیل ویژگی‌های دسته‌ای به عددی (طبقه‌ای) یاری‌گر هستند. اولین تابع، برای خروجی دادن یک تابع است؛ برای مثال، تبدیل کننده (Transformer) هر str در لیست را به یک int تبدیل می‌کند که در آن، int اندیس آن عنصر در لیست است.

1def categorical_to_ordinal_transformer(categories):
2    '''
3    Returns a function that will map categories to ordinal values based on the
4    order of the list of `categories` given. Ex.
5
6    If categories is ['A', 'B', 'C'] then the transformer will map 
7    'A' -> 0, 'B' -> 1, 'C' -> 2.
8    '''
9    return lambda categorical_value: categories.index(categorical_value)

دومین تابع، دارای دو بخش است. اولین بخش، یک دیکشنری به شکل زیر را دریافت می‌کند.

1categorical_numerical_mapping = {
2    'Utilities': ['ELO', 'NoSeWa', 'NoSewr', 'AllPub'],
3    'Exter Qual': ['Po', 'Fa', 'TA', 'Gd', 'Ex'],
4    'Exter Cond': ['Po', 'Fa', 'TA', 'Gd', 'Ex']
5}

با استفاده از تابع قبلی که پیش از این تعریف شده است، دیکشنری به چیزی شبیه به زیر تبدیل می‌شود.

1transformers = {'Utilities': <utilties_transformer>,
2                'Exter Qual': <exter_qual_transformer>,
3                'Exter Cond': <exter_cond_transfomer>}

دومین بخش از این تابع از متد map()‎. برای نگاشت هر تابع مبدل به یک چارچوب داده (دیتافریم) استفاده می‌کند. شایان ذکر است که یک کپی از چارچوب داده اصلی، در طول این تابع ساخته می‌شود.

1def transform_categorical_to_numercial(df, categorical_numerical_mapping):
2    '''
3    Transforms categorical columns to numerical columns
4    Takes a df, a dictionary 
5    Returns df
6    '''
7    transformers = {k: categorical_to_ordinal_transformer(v) 
8                    for k, v in categorical_numerical_mapping.items()}
9    new_df = df.copy()
10    for col, transformer in transformers.items():
11        new_df[col] = new_df[col].map(transformer).astype('int64')
12    return new_df

اگر نوشته بالا برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

^^

بر اساس رای ۴ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
Towards Data Science
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *