用于快速数据预处理的记事本备忘单

通常,进入数据科学领域的人们对等待他们的事情抱有不太现实的期望。 许多人认为现在他们将编写很酷的神经网络,创建钢铁侠的语音助手,或者击败金融市场上的所有人。
但工作 时间 科学家是数据驱动的,最重要和最耗时的方面之一是在将数据输入神经网络或以某种方式分析之前对其进行处理。

在本文中,我们的团队将介绍如何通过分步说明和代码快速轻松地处理数据。 我们试图使代码非常灵活并且可以用于不同的数据集。

许多专业人士可能不会在本文中发现任何特别之处,但初学者将能够学到新东西,任何长期梦想制作一个单独的笔记本以进行快速结构化数据处理的人都可以复制代码并自行格式化,或者 从 Github 下载完成的笔记本。

我们收到了数据集。 接下来做什么?

所以,标准是:我们需要了解我们正在处理的是什么,整体情况。 为此,我们使用 pandas 来简单地定义不同的数据类型。

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

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

用于快速数据预处理的记事本备忘单

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

用于快速数据预处理的记事本备忘单

让我们看看列值:

  1. 每列的行数是否与总行数相对应?
  2. 每列数据的本质是什么?
  3. 我们想要针对哪一列来进行预测?

这些问题的答案将使您能够分析数据集并粗略地制定下一步行动的计划。

另外,为了更深入地查看每列中的值,我们可以使用 pandas describe() 函数。 但是,此函数的缺点是它不提供有关具有字符串值的列的信息。 我们稍后再处理他们。

df.describe()

用于快速数据预处理的记事本备忘单

神奇的可视化

我们来看看哪里根本没有值:

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

用于快速数据预处理的记事本备忘单

这是上面的简短介绍,现在我们将继续讨论更有趣的事情

让我们尝试查找并在可能的情况下删除所有行中只有一个值的列(它们不会以任何方式影响结果):

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

用于快速数据预处理的记事本备忘单

此处,列内缺失的那些值应标记为黄色。 现在有趣的事情开始了——如何处理这些值? 我应该删除具有这些值或列的行吗? 或者用其他一些值来填充这些空值?

下面是一个近似图,可以帮助您决定原则上可以使用空值做什么:

用于快速数据预处理的记事本备忘单

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 编码方法将其从字符串(或对象)格式化为数字。 在继续讨论这一点之前,让我们使用上面的图表和代码来处理空值。

df_categorical.nunique()

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

用于快速数据预处理的记事本备忘单

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)

因此,我们终于掌握了定性数据中的空值。 现在是时候对数据库中的值执行 one-hot 编码了。 这种方法经常用于确保您的算法可以从高质量数据中学习。

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)

将数据集组合在一起后,我们最终可以使用 sklearn 库中的 MinMaxScaler 进行数据转换。 这将使我们的值在0和1之间,这对于以后训练模型时会有帮助。

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

这些数据现在可以用于任何用途 - 神经网络、标准 ML 算法等!

在本文中,我们没有考虑使用时间序列数据,因为对于此类数据,您应该根据您的任务使用略有不同的处理技术。 未来,我们的团队将专门写一篇文章来讨论这个主题,我们希望它能为您的生活带来一些有趣、新鲜和有用的东西,就像这篇文章一样。

来源: habr.com

添加评论