Full de trucs del portàtil per a un preprocessament ràpid de dades

Sovint, les persones que entren al camp de la ciència de dades tenen expectatives menys que realistes del que els espera. Molta gent pensa que ara escriurà xarxes neuronals interessants, crearà un assistent de veu d'Iron Man o guanyarà a tothom als mercats financers.
Però treball dades El científic es basa en les dades, i un dels aspectes més importants i que consumeixen temps és processar les dades abans d'alimentar-les a una xarxa neuronal o analitzar-les d'una determinada manera.

En aquest article, el nostre equip descriurà com podeu processar dades de manera ràpida i senzilla amb instruccions i codi pas a pas. Vam intentar que el codi fos bastant flexible i es pogués utilitzar per a diferents conjunts de dades.

És possible que molts professionals no trobin res d'extraordinari en aquest article, però els principiants podran aprendre alguna cosa nova, i qualsevol que hagi somiat durant molt de temps amb fer un quadern separat per al processament de dades ràpid i estructurat pot copiar el codi i formatar-lo per si mateix, o descarregar el quadern acabat de Github.

Hem rebut el conjunt de dades. Què fer després?

Per tant, l'estàndard: hem d'entendre amb què estem tractant, la imatge general. Per fer-ho, fem servir pandas per definir simplement diferents tipus de dades.

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

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

Full de trucs del portàtil per a un preprocessament ràpid de dades

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

Full de trucs del portàtil per a un preprocessament ràpid de dades

Vegem els valors de la columna:

  1. El nombre de línies de cada columna correspon al nombre total de línies?
  2. Quina és l'essència de les dades de cada columna?
  3. A quina columna volem orientar-nos per fer-ne prediccions?

Les respostes a aquestes preguntes us permetran analitzar el conjunt de dades i dibuixar aproximadament un pla per a les vostres properes accions.

A més, per a una visió més profunda dels valors de cada columna, podem utilitzar la funció Pandas describe(). Tanmateix, el desavantatge d'aquesta funció és que no proporciona informació sobre columnes amb valors de cadena. Més endavant ens ocuparem.

df.describe()

Full de trucs del portàtil per a un preprocessament ràpid de dades

Visualització màgica

Vegem on no tenim cap valor:

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

Full de trucs del portàtil per a un preprocessament ràpid de dades

Aquesta va ser una petita mirada des de dalt, ara passarem a coses més interessants

Intentem trobar i, si és possible, eliminar columnes que només tenen un valor a totes les files (no afectaran el resultat de cap manera):

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

Ara ens protegim a nosaltres mateixos i a l'èxit del nostre projecte de línies duplicades (línies que contenen la mateixa informació en el mateix ordre que una de les línies existents):

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

Dividim el conjunt de dades en dos: un amb valors qualitatius i l'altre amb valors quantitatius

Aquí hem de fer un petit aclariment: si les línies amb dades que falten en dades qualitatives i quantitatives no estan molt correlacionades entre si, haurem de decidir què sacrifiquem: totes les línies amb dades que falten, només una part, o determinades columnes. Si les línies estan correlacionades, llavors tenim tot el dret de dividir el conjunt de dades en dos. En cas contrari, primer haureu de tractar les línies que no correlacionen les dades que falten en qualitat i quantitat, i només després dividiu el conjunt de dades en dos.

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

Ho fem per facilitar-nos el processament d'aquests dos tipus de dades diferents; més endavant entendrem com això ens facilita la vida.

Treballem amb dades quantitatives

El primer que hem de fer és determinar si hi ha "columnes espia" a les dades quantitatives. Anomenem aquestes columnes així perquè es presenten com a dades quantitatives, però actuen com a dades qualitatives.

Com els podem identificar? Per descomptat, tot depèn de la naturalesa de les dades que esteu analitzant, però, en general, aquestes columnes poden tenir poques dades úniques (entre 3 i 10 valors únics).

print(df_numerical.nunique())

Un cop hem identificat les columnes espia, les passarem de dades quantitatives a dades qualitatives:

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']) #добавляем третью колонку-шпион в качественные данные

Finalment, hem separat completament les dades quantitatives de les qualitatives i ara podem treballar-hi correctament. El primer és entendre on tenim valors buits (NaN, i en alguns casos s'acceptarà 0 com a valors buits).

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

En aquest punt, és important entendre en quines columnes els zeros poden indicar valors que falten: això es deu a com es van recollir les dades? O podria estar relacionat amb els valors de les dades? Aquestes preguntes s'han de respondre cas per cas.

Per tant, si encara decidim que ens poden faltar dades on hi ha zeros, hauríem de substituir els zeros per NaN per facilitar el treball amb aquestes dades perdudes més endavant:

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

Ara vegem on ens falten dades:

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

Full de trucs del portàtil per a un preprocessament ràpid de dades

Aquí els valors dins de les columnes que falten s'han de marcar en groc. I ara comença la diversió: com afrontar aquests valors? He de suprimir files amb aquests valors o columnes? O omplir aquests valors buits amb d'altres?

Aquí teniu un diagrama aproximat que us pot ajudar a decidir què es pot fer, en principi, amb valors buits:

Full de trucs del portàtil per a un preprocessament ràpid de dades

0. Elimina les columnes innecessàries

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

1. El nombre de valors buits d'aquesta columna és superior al 50%?

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

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

2. Elimina les línies amb valors buits

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

3.1. Inserir un valor aleatori

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

3.2. Inserir un valor constant

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. Introduïu el valor mitjà o més freqüent

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. Inseriu el valor calculat per un altre model

De vegades, els valors es poden calcular mitjançant models de regressió utilitzant models de la biblioteca sklearn o altres biblioteques similars. El nostre equip dedicarà un article a part sobre com es pot fer això en un futur proper.

Per tant, de moment, la narració sobre les dades quantitatives s'interromprà, perquè hi ha molts altres matisos sobre com fer millor la preparació i el preprocessament de dades per a diferents tasques, i en aquest article s'han tingut en compte les coses bàsiques de les dades quantitatives, i ara és el moment de tornar a les dades qualitatives que vam separar uns quants passos enrere de les quantitatives. Podeu canviar aquest quadern com vulgueu, adaptant-lo a diferents tasques, perquè el preprocessament de dades vagi molt ràpid!

Dades qualitatives

Bàsicament, per a les dades qualitatives, s'utilitza el mètode One-hot-encoding per formatar-les d'una cadena (o objecte) a un número. Abans de passar a aquest punt, utilitzem el diagrama i el codi anteriors per tractar els valors buits.

df_categorical.nunique()

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

Full de trucs del portàtil per a un preprocessament ràpid de dades

0. Elimina les columnes innecessàries

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

1. El nombre de valors buits d'aquesta columna és superior al 50%?

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

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

2. Elimina les línies amb valors buits

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

3.1. Inserir un valor aleatori

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

3.2. Inserir un valor constant

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)

Per tant, finalment tenim un control sobre els nuls a les dades qualitatives. Ara és el moment de realitzar una codificació en calent als valors que hi ha a la vostra base de dades. Aquest mètode s'utilitza molt sovint per garantir que el vostre algorisme pugui aprendre de dades d'alta qualitat.

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))

Per tant, finalment hem acabat de processar dades qualitatives i quantitatives separades: és hora de tornar-les a combinar

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

Després d'haver combinat els conjunts de dades en un, finalment podem utilitzar la transformació de dades mitjançant MinMaxScaler de la biblioteca sklearn. Això farà que els nostres valors estiguin entre 0 i 1, cosa que ajudarà a l'hora d'entrenar el model en el futur.

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

Aquestes dades ja estan a punt per a qualsevol cosa: xarxes neuronals, algorismes estàndard de ML, etc.!

En aquest article, no hem tingut en compte treballar amb dades de sèries temporals, ja que per a aquestes dades hauríeu d'utilitzar tècniques de processament lleugerament diferents, segons la vostra tasca. En el futur, el nostre equip dedicarà un article a part a aquest tema, i esperem que pugui aportar alguna cosa interessant, nou i útil a la vostra vida, com aquest.

Font: www.habr.com

Afegeix comentari