Σημειωματάριο-cheat φύλλο για γρήγορη προεπεξεργασία δεδομένων

Συχνά οι άνθρωποι που εισέρχονται στον τομέα της Επιστήμης Δεδομένων έχουν λιγότερο από ρεαλιστικές προσδοκίες για το τι τους περιμένει. Πολλοί άνθρωποι πιστεύουν ότι τώρα θα γράψουν δροσερά νευρωνικά δίκτυα, θα δημιουργήσουν έναν φωνητικό βοηθό από τον Iron Man ή θα κερδίσουν τους πάντες στις χρηματοπιστωτικές αγορές.
Αλλά δουλειά ημερομηνία Ο επιστήμονας βασίζεται στα δεδομένα και μία από τις πιο σημαντικές και χρονοβόρες πτυχές είναι η επεξεργασία των δεδομένων πριν τα τροφοδοτήσει σε ένα νευρωνικό δίκτυο ή πριν τα αναλύσει με συγκεκριμένο τρόπο.

Σε αυτό το άρθρο, η ομάδα μας θα περιγράψει πώς μπορείτε να επεξεργάζεστε δεδομένα γρήγορα και εύκολα με οδηγίες και κώδικα βήμα προς βήμα. Προσπαθήσαμε να κάνουμε τον κώδικα αρκετά ευέλικτο και να μπορεί να χρησιμοποιηθεί για διαφορετικά σύνολα δεδομένων.

Πολλοί επαγγελματίες μπορεί να μην βρουν τίποτα το ασυνήθιστο σε αυτό το άρθρο, αλλά οι αρχάριοι θα μπορούν να μάθουν κάτι νέο, και όποιος ονειρεύεται από καιρό να φτιάξει ένα ξεχωριστό σημειωματάριο για γρήγορη και δομημένη επεξεργασία δεδομένων μπορεί να αντιγράψει τον κώδικα και να τον μορφοποιήσει για τον εαυτό του ή κατεβάστε το έτοιμο σημειωματάριο από το Github.

Λάβαμε το σύνολο δεδομένων. Τι να κάνω μετά?

Άρα, το πρότυπο: πρέπει να καταλάβουμε με τι έχουμε να κάνουμε, τη συνολική εικόνα. Για να το κάνουμε αυτό, χρησιμοποιούμε panda για να ορίσουμε απλώς διαφορετικούς τύπους δεδομένων.

import pandas as pd #импортируем pandas
import numpy as np  #импортируем numpy
df = pd.read_csv("AB_NYC_2019.csv") #читаем датасет и записываем в переменную df

df.head(3) #смотрим на первые 3 строчки, чтобы понять, как выглядят значения

Σημειωματάριο-cheat φύλλο για γρήγορη προεπεξεργασία δεδομένων

df.info() #Демонстрируем информацию о колонках

Σημειωματάριο-cheat φύλλο για γρήγορη προεπεξεργασία δεδομένων

Ας δούμε τις τιμές των στηλών:

  1. Ο αριθμός των γραμμών σε κάθε στήλη αντιστοιχεί στον συνολικό αριθμό των γραμμών;
  2. Ποια είναι η ουσία των δεδομένων σε κάθε στήλη;
  3. Ποια στήλη θέλουμε να στοχεύσουμε για να κάνουμε προβλέψεις για αυτήν;

Οι απαντήσεις σε αυτές τις ερωτήσεις θα σας επιτρέψουν να αναλύσετε το σύνολο δεδομένων και να σχεδιάσετε κατά προσέγγιση ένα σχέδιο για τις επόμενες ενέργειές σας.

Επίσης, για μια βαθύτερη ματιά στις τιμές σε κάθε στήλη, μπορούμε να χρησιμοποιήσουμε τη συνάρτηση pandas describe(). Ωστόσο, το μειονέκτημα αυτής της συνάρτησης είναι ότι δεν παρέχει πληροφορίες για στήλες με τιμές συμβολοσειρών. Θα ασχοληθούμε αργότερα μαζί τους.

df.describe()

Σημειωματάριο-cheat φύλλο για γρήγορη προεπεξεργασία δεδομένων

Μαγική οπτικοποίηση

Ας δούμε πού δεν έχουμε καθόλου αξίες:

import seaborn as sns
sns.heatmap(df.isnull(),yticklabels=False,cbar=False,cmap='viridis')

Σημειωματάριο-cheat φύλλο για γρήγορη προεπεξεργασία δεδομένων

Αυτή ήταν μια σύντομη ματιά από ψηλά, τώρα θα προχωρήσουμε σε πιο ενδιαφέροντα πράγματα

Ας προσπαθήσουμε να βρούμε και, αν είναι δυνατόν, να αφαιρέσουμε στήλες που έχουν μόνο μία τιμή σε όλες τις σειρές (δεν θα επηρεάσουν το αποτέλεσμα με κανέναν τρόπο):

df = df[[c for c
        in list(df)
        if len(df[c].unique()) > 1]] #Перезаписываем датасет, оставляя только те колонки, в которых больше одного уникального значения

Τώρα προστατεύουμε τον εαυτό μας και την επιτυχία του έργου μας από διπλές γραμμές (γραμμές που περιέχουν τις ίδιες πληροφορίες με την ίδια σειρά με μία από τις υπάρχουσες γραμμές):

df.drop_duplicates(inplace=True) #Делаем это, если считаем нужным.
                                 #В некоторых проектах удалять такие данные с самого начала не стоит.

Χωρίζουμε το σύνολο δεδομένων σε δύο: το ένα με ποιοτικές τιμές και το άλλο με ποσοτικές

Εδώ πρέπει να κάνουμε μια μικρή διευκρίνιση: εάν οι γραμμές με ελλείποντα δεδομένα σε ποιοτικά και ποσοτικά δεδομένα δεν συσχετίζονται πολύ μεταξύ τους, τότε θα πρέπει να αποφασίσουμε τι θα θυσιάσουμε - όλες οι γραμμές με στοιχεία που λείπουν, μόνο ένα μέρος τους, ή ορισμένες στήλες. Εάν οι γραμμές συσχετίζονται, τότε έχουμε κάθε δικαίωμα να χωρίσουμε το σύνολο δεδομένων στα δύο. Διαφορετικά, θα πρέπει πρώτα να ασχοληθείτε με τις γραμμές που δεν συσχετίζουν τα δεδομένα που λείπουν σε ποιοτική και ποσοτική άποψη και μόνο στη συνέχεια να διαιρέσετε το σύνολο δεδομένων στα δύο.

df_numerical = df.select_dtypes(include = [np.number])
df_categorical = df.select_dtypes(exclude = [np.number])

Αυτό το κάνουμε για να διευκολυνθεί η επεξεργασία αυτών των δύο διαφορετικών τύπων δεδομένων - αργότερα θα καταλάβουμε πόσο πιο εύκολη γίνεται η ζωή μας.

Δουλεύουμε με ποσοτικά δεδομένα

Το πρώτο πράγμα που πρέπει να κάνουμε είναι να προσδιορίσουμε εάν υπάρχουν «στήλες κατασκοπείας» στα ποσοτικά δεδομένα. Ονομάζουμε αυτές τις στήλες επειδή παρουσιάζονται ως ποσοτικά δεδομένα, αλλά λειτουργούν ως ποιοτικά δεδομένα.

Πώς μπορούμε να τους αναγνωρίσουμε; Φυσικά, όλα εξαρτώνται από τη φύση των δεδομένων που αναλύετε, αλλά γενικά τέτοιες στήλες μπορεί να έχουν λίγα μοναδικά δεδομένα (στην περιοχή των 3-10 μοναδικών τιμών).

print(df_numerical.nunique())

Αφού εντοπίσουμε τις στήλες κατασκοπείας, θα τις μετακινήσουμε από τα ποσοτικά δεδομένα στα ποιοτικά δεδομένα:

spy_columns = df_numerical[['колонка1', 'колока2', 'колонка3']]#выделяем колонки-шпионы и записываем в отдельную dataframe
df_numerical.drop(labels=['колонка1', 'колока2', 'колонка3'], axis=1, inplace = True)#вырезаем эти колонки из количественных данных
df_categorical.insert(1, 'колонка1', spy_columns['колонка1']) #добавляем первую колонку-шпион в качественные данные
df_categorical.insert(1, 'колонка2', spy_columns['колонка2']) #добавляем вторую колонку-шпион в качественные данные
df_categorical.insert(1, 'колонка3', spy_columns['колонка3']) #добавляем третью колонку-шпион в качественные данные

Τέλος, διαχωρίσαμε πλήρως τα ποσοτικά δεδομένα από τα ποιοτικά και πλέον μπορούμε να εργαστούμε σωστά με αυτά. Το πρώτο πράγμα είναι να καταλάβουμε πού έχουμε κενές τιμές (NaN, και σε ορισμένες περιπτώσεις το 0 θα γίνει αποδεκτό ως κενές τιμές).

for i in df_numerical.columns:
    print(i, df[i][df[i]==0].count())

Σε αυτό το σημείο, είναι σημαντικό να κατανοήσουμε σε ποιες στήλες τα μηδενικά μπορεί να υποδεικνύουν τιμές που λείπουν: αυτό οφείλεται στον τρόπο συλλογής των δεδομένων; Ή θα μπορούσε να σχετίζεται με τις τιμές δεδομένων; Αυτά τα ερωτήματα πρέπει να απαντώνται κατά περίπτωση.

Έτσι, εάν εξακολουθήσουμε να αποφασίσουμε ότι μπορεί να μας λείπουν δεδομένα όπου υπάρχουν μηδενικά, θα πρέπει να αντικαταστήσουμε τα μηδενικά με NaN για να διευκολύνουμε την εργασία με αυτά τα χαμένα δεδομένα αργότερα:

df_numerical[["колонка 1", "колонка 2"]] = df_numerical[["колонка 1", "колонка 2"]].replace(0, nan)

Τώρα ας δούμε πού μας λείπουν δεδομένα:

sns.heatmap(df_numerical.isnull(),yticklabels=False,cbar=False,cmap='viridis') # Можно также воспользоваться df_numerical.info()

Σημειωματάριο-cheat φύλλο για γρήγορη προεπεξεργασία δεδομένων

Εδώ αυτές οι τιμές μέσα στις στήλες που λείπουν θα πρέπει να σημειωθούν με κίτρινο χρώμα. Και τώρα αρχίζει η διασκέδαση - πώς να αντιμετωπίσετε αυτές τις αξίες; Πρέπει να διαγράψω σειρές με αυτές τις τιμές ή στήλες; Ή να συμπληρώσετε αυτές τις κενές τιμές με κάποιες άλλες;

Ακολουθεί ένα κατά προσέγγιση διάγραμμα που μπορεί να σας βοηθήσει να αποφασίσετε τι μπορεί, καταρχήν, να γίνει με κενές τιμές:

Σημειωματάριο-cheat φύλλο για γρήγορη προεπεξεργασία δεδομένων

0. Αφαιρέστε τις περιττές στήλες

df_numerical.drop(labels=["колонка1","колонка2"], axis=1, inplace=True)

1. Ο αριθμός των κενών τιμών σε αυτήν τη στήλη είναι μεγαλύτερος από 50%;

print(df_numerical.isnull().sum() / df_numerical.shape[0] * 100)

df_numerical.drop(labels=["колонка1","колонка2"], axis=1, inplace=True)#Удаляем, если какая-то колонка имеет больше 50 пустых значений

2. Διαγράψτε γραμμές με κενές τιμές

df_numerical.dropna(inplace=True)#Удаляем строчки с пустыми значениями, если потом останется достаточно данных для обучения

3.1. Εισαγωγή τυχαίας τιμής

import random #импортируем random
df_numerical["колонка"].fillna(lambda x: random.choice(df[df[column] != np.nan]["колонка"]), inplace=True) #вставляем рандомные значения в пустые клетки таблицы

3.2. Εισαγωγή σταθερής τιμής

from sklearn.impute import SimpleImputer #импортируем SimpleImputer, который поможет вставить значения
imputer = SimpleImputer(strategy='constant', fill_value="<Ваше значение здесь>") #вставляем определенное значение с помощью SimpleImputer
df_numerical[["новая_колонка1",'новая_колонка2','новая_колонка3']] = imputer.fit_transform(df_numerical[['колонка1', 'колонка2', 'колонка3']]) #Применяем это для нашей таблицы
df_numerical.drop(labels = ["колонка1","колонка2","колонка3"], axis = 1, inplace = True) #Убираем колонки со старыми значениями

3.3. Εισαγάγετε τη μέση ή την πιο συχνή τιμή

from sklearn.impute import SimpleImputer #импортируем SimpleImputer, который поможет вставить значения
imputer = SimpleImputer(strategy='mean', missing_values = np.nan) #вместо mean можно также использовать most_frequent
df_numerical[["новая_колонка1",'новая_колонка2','новая_колонка3']] = imputer.fit_transform(df_numerical[['колонка1', 'колонка2', 'колонка3']]) #Применяем это для нашей таблицы
df_numerical.drop(labels = ["колонка1","колонка2","колонка3"], axis = 1, inplace = True) #Убираем колонки со старыми значениями

3.4. Εισαγάγετε την τιμή που υπολογίστηκε από άλλο μοντέλο

Μερικές φορές οι τιμές μπορούν να υπολογιστούν χρησιμοποιώντας μοντέλα παλινδρόμησης χρησιμοποιώντας μοντέλα από τη βιβλιοθήκη sklearn ή άλλες παρόμοιες βιβλιοθήκες. Η ομάδα μας θα αφιερώσει ένα ξεχωριστό άρθρο για το πώς μπορεί να γίνει αυτό στο εγγύς μέλλον.

Έτσι, προς το παρόν, η αφήγηση σχετικά με τα ποσοτικά δεδομένα θα διακοπεί, επειδή υπάρχουν πολλές άλλες αποχρώσεις σχετικά με τον καλύτερο τρόπο προετοιμασίας και προεπεξεργασίας δεδομένων για διαφορετικές εργασίες, και τα βασικά πράγματα για τα ποσοτικά δεδομένα έχουν ληφθεί υπόψη σε αυτό το άρθρο, και τώρα είναι η ώρα να επιστρέψουμε στα ποιοτικά δεδομένα.τα οποία διαχωρίσαμε αρκετά βήματα πίσω από τα ποσοτικά. Μπορείτε να αλλάξετε αυτό το σημειωματάριο όπως θέλετε, προσαρμόζοντάς το σε διαφορετικές εργασίες, έτσι ώστε η προεπεξεργασία δεδομένων να γίνεται πολύ γρήγορα!

Ποιοτικα δεδομενα

Βασικά, για ποιοτικά δεδομένα, χρησιμοποιείται η μέθοδος One-hot-encoding προκειμένου να μορφοποιηθεί από συμβολοσειρά (ή αντικείμενο) σε αριθμό. Πριν προχωρήσουμε σε αυτό το σημείο, ας χρησιμοποιήσουμε το παραπάνω διάγραμμα και τον κώδικα για να αντιμετωπίσουμε τις κενές τιμές.

df_categorical.nunique()

sns.heatmap(df_categorical.isnull(),yticklabels=False,cbar=False,cmap='viridis')

Σημειωματάριο-cheat φύλλο για γρήγορη προεπεξεργασία δεδομένων

0. Αφαιρέστε τις περιττές στήλες

df_categorical.drop(labels=["колонка1","колонка2"], axis=1, inplace=True)

1. Ο αριθμός των κενών τιμών σε αυτήν τη στήλη είναι μεγαλύτερος από 50%;

print(df_categorical.isnull().sum() / df_numerical.shape[0] * 100)

df_categorical.drop(labels=["колонка1","колонка2"], axis=1, inplace=True) #Удаляем, если какая-то колонка 
                                                                          #имеет больше 50% пустых значений

2. Διαγράψτε γραμμές με κενές τιμές

df_categorical.dropna(inplace=True)#Удаляем строчки с пустыми значениями, 
                                   #если потом останется достаточно данных для обучения

3.1. Εισαγωγή τυχαίας τιμής

import random
df_categorical["колонка"].fillna(lambda x: random.choice(df[df[column] != np.nan]["колонка"]), inplace=True)

3.2. Εισαγωγή σταθερής τιμής

from sklearn.impute import SimpleImputer
imputer = SimpleImputer(strategy='constant', fill_value="<Ваше значение здесь>")
df_categorical[["новая_колонка1",'новая_колонка2','новая_колонка3']] = imputer.fit_transform(df_categorical[['колонка1', 'колонка2', 'колонка3']])
df_categorical.drop(labels = ["колонка1","колонка2","колонка3"], axis = 1, inplace = True)

Λοιπόν, επιτέλους έχουμε μια λαβή για τα μηδενικά σε ποιοτικά δεδομένα. Τώρα ήρθε η ώρα να εκτελέσετε μια απλή κωδικοποίηση στις τιμές που βρίσκονται στη βάση δεδομένων σας. Αυτή η μέθοδος χρησιμοποιείται πολύ συχνά για να διασφαλιστεί ότι ο αλγόριθμός σας μπορεί να μάθει από δεδομένα υψηλής ποιότητας.

def encode_and_bind(original_dataframe, feature_to_encode):
    dummies = pd.get_dummies(original_dataframe[[feature_to_encode]])
    res = pd.concat([original_dataframe, dummies], axis=1)
    res = res.drop([feature_to_encode], axis=1)
    return(res)

features_to_encode = ["колонка1","колонка2","колонка3"]
for feature in features_to_encode:
    df_categorical = encode_and_bind(df_categorical, feature))

Έτσι, επιτέλους ολοκληρώσαμε την επεξεργασία ξεχωριστών ποιοτικών και ποσοτικών δεδομένων - καιρός να τα συνδυάσουμε ξανά

new_df = pd.concat([df_numerical,df_categorical], axis=1)

Αφού συνδυάσουμε τα σύνολα δεδομένων μαζί σε ένα, μπορούμε τελικά να χρησιμοποιήσουμε τον μετασχηματισμό δεδομένων χρησιμοποιώντας το MinMaxScaler από τη βιβλιοθήκη sklearn. Αυτό θα κάνει τις τιμές μας μεταξύ 0 και 1, κάτι που θα βοηθήσει κατά την εκπαίδευση του μοντέλου στο μέλλον.

from sklearn.preprocessing import MinMaxScaler
min_max_scaler = MinMaxScaler()
new_df = min_max_scaler.fit_transform(new_df)

Αυτά τα δεδομένα είναι πλέον έτοιμα για οτιδήποτε - νευρωνικά δίκτυα, τυπικοί αλγόριθμοι ML κ.λπ.!

Σε αυτό το άρθρο, δεν λάβαμε υπόψη την εργασία με δεδομένα χρονοσειρών, καθώς για τέτοια δεδομένα θα πρέπει να χρησιμοποιήσετε ελαφρώς διαφορετικές τεχνικές επεξεργασίας, ανάλογα με την εργασία σας. Στο μέλλον, η ομάδα μας θα αφιερώσει ένα ξεχωριστό άρθρο σε αυτό το θέμα και ελπίζουμε ότι θα μπορέσει να φέρει κάτι ενδιαφέρον, νέο και χρήσιμο στη ζωή σας, όπως ακριβώς αυτό.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο