机器学习:清洁数据

Tavish Aggarwal.
I

n上一篇文章,我们看到如何使用Python中可用的各种包从不同类型的文件源导入数据。如果你没有经历过 使用Python导入数据。我建议在踩到这篇文章之前经历它。 

一旦我们将数据导入数据集,就会在进一步进行之前了解数据非常重要。了解提供的数据集的属性(列)非常重要。

每当我们获取新数据集时,我们的第一项任务是进行探索性分析以更好地了解数据。

当我们认为我们有足够的关于数据集的知识时,我们确定我们期望从数据集期望的答案是可以得到的,我们可以进一步发挥一步。

提供给我们的数据有很高的机会,没有清洁数据。我们的意思是不干净或肮脏的数据?以下是一些要帮助您了解我们必须检查的所有点的部分,以使我们的数据清洁:

  1. 检查列的数据类型
  2. 检查列中的数据。检查我们是否需要拆分列?
  3. 检查列的最大,最小和中位数
  4. 检查数据集中的复制
  5. 重塑数据是必需的?
  6. DataSet是否包含文本之间不必要的白色空格
  7. 我们的数据集是否包含空值?

在这篇文章中,我们将探索上述点,并尝试清理提供的数据集。作为这篇文章的一部分,我们将在数据集上工作 TMDB.牛油果 dataset from Kaggle.

笔记: 我建议下载上面提到的数据集以遵循课程并并排执行手。

正如我们之前讨论的那样,第一步是探索数据集。要探索以下的Pandas数据集是我们可以使用的命令的少量:

  1. 首尾()
  2. 形状
  3. 信息()
  4. 描述()
  5. value_counts.
  6. 中位数

让我们深入了解上面的命令,看看可以揭示什么信息。让我们从Head()和tail()命令开始。

首尾()

默认情况下,HEAD命令将显示数据集和尾部命令的前5行将显示数据集的最后5行。

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')
print(tmdbDataSet.head())
print(tmdbDataSet.tail())

我们还可以将Head和Tail命令限制为我们想要查看的行数。假设如果我想看到DataSet的顶部和最后一行,那么我可以使用具有参数的头和尾函数,如下所示:

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')
print(tmdbDataSet.head(1))
print(tmdbDataSet.tail(1))

我们可以看到我们数据集的所有不同列都有的内容。要查看DataSet中列的代码:

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')
print(tmdbDataSet.columns)

形状

我们还可以看到数据的形状。这意味着行数和数据集的数量。

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')
print(tmdbDataSet.shape)

输出是(行数,列数)的形式。

信息()

该信息描述了我们数据集中每列的数据类型。它还介绍了在每个列中有多少行,其值不为null。

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')
print(tmdbDataSet.info())


# Observation

# Output describes that dataset has rows for which values of homepage column has null values. 
# There is total 3091 rows (4803 - 1712) for which home age has null values.

# Also there is one movie which doesn't have release date.
# Two if the rows doesn't have runtime.

# And 844 rows doesn't have tagline values.

# Its an important observation at this point of time. 
# We have taken good steps to know our dataset.

获取列的数据类型的另一种方法是使用dtypes。

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')
print(tmdbDataSet.dtypes)

我们还可以更改列的数据类型。要更改数据类型,请参阅下面显示的代码:

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')
tmdbDataSet['status'] = tmdbDataSet['status'].astype('category')

# We can also covert to back to string 
tmdbDataSet['status'] = tmdbDataSet['status'].astype(str)

要将列的数据类型转换为数字Pandas提供函数to_numeric。

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')
tmdbDataSet['vote_count'] = pd.to_numeric(tmdbDataSet['vote_count'], errors='coerce')

注意,传递给函数的参数错误。使用Pandas无法转换为数字的任何值,那么它将插入'nan'。如果我们未指定它,则该函数将返回错误。

描述()

描述熊猫的函数返回

  1. 计数 - 数字列中非空条目的计数数为e.g df ['col']。count()
  2. 含义 - 返回忽略空条目的系列的平均值e.g df ['col']。均值()
  3. std - 返回not null值的标准偏差df.std()
  4. min - 返回最小观察列表e.g - df.min()
  5. 25% - 返回数据集的25%或1/4百分位数
  6. 50% - 返回数据集的25%或1/2百分位。此外,注意50%的数据集等于中位数
  7. 75% - 返回数据集的25%或3/4百分位。
  8. max - 返回最大观察列表e.g - df.max()

 结果。描述函数只能用于数字列。看看下面显示的示例:

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')
print(tmdbDataSet.describe())


# Observations

# Describe function can only be used on numeric columns and from info method we know that 
# there are only 7 columns whose value is as integer/float. 
# So output of describe method will be 7 columns.

我们还可以将“介绍”对非整数列的方法。为此,我们需要在列上调用Desigry方法。

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')
print(tmdbDataSet.status.describe())

# Observations
# What we observed is that out of 4803 movies, 4795 movies has been released. 
# And there are total three unique values of status column

此外,请注意,我们可以使用定量函数手动计算百分比的数据。使用此,我们可以计算任何百分点的数据。请参阅下面显示的脚本以计算DataSet的55%。

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')

print(tmdbDataSet.vote_count.quantile([0.55]))


# Observations
# It seems bit confusing how quantile is being calculated
# Easiest way to get this is as shown below
# As we know our dataset has 4803 records
# So 55% of 4803 is 2641
# As we are calculating quantile of vote_count we will sort by column
# Also we will find out first 2641 rows

tempDataSet = tmdbDataSet.sort_values(['vote_count']).head(2641)
print(tempDataSet.vote_count.tail(1))

# You will notice tht output from both print command will match

value_counts..

value_counts.方法返回列中每个唯一值的频率计数。

此方法还具有可选的参数,称为Dropna,默认情况下是真的。如果参数设置为true,则我们将无法获取丢失数据的计数(如果有)。但如果它被设置为false,我们将获得缺失数据的计数以及频率计数。

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')
print(tmdbDataSet.release_date.value_counts(dropna=False))

# Observations

# This is again an important observation. 
# There are 10 movies in dataset which are released on '2006-01-01'
# Also there is one movie which doesn't have release date. 
# This we already know with info() method


print(tmdbDataSet.status.value_counts())

# Observations

# Previously, we observed that there are 4795 movies which have been released.
# Also status doesn't have any null alues so we havn't used dropna flag here.
# There are three different unique values which we saw in describe method.
# The above command reviled different values in status column and its count

中位数

可以使用以下命令计算数据集中中位数:

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')
print(tmdbDataSet.median())

该命令返回系列的中位数。我们只能计算Integer / Float列的中位数。如果我们尝试计算非整数值的中位数,上面的命令将返回错误,这是有意义的。

现在,我们对我们正在处理的数据来了解更多并清洁我们的数据集。

有一个 由'hadley wickham ph.d.'写的在那里他表示通常有两个规则要遵循的数据集以便被称为干净的数据集。这些都是:

  1. 列表示单独的变量
  2. 每行作为单独观察
  3. 观察单位形成表格

为了满足上述规则,我们肯定必须重塑我们的数据。 Pandas提供熔体功能,帮助我们以我们想要的方式重塑我们的数据。让我们来看看这个例子:

融化数据

熔化数据是将数据列转换为数据行的过程。融化数据熊猫提供功能熔体()。我们应该知道有两个熔体功能参数。这些都是:

  • ID_VARS - 它表示您不想融化或不想重塑的数据的列
  • value_vars - 它表示我们希望融入行的列。

让我们看看如何融化在行动中:

import pandas as pd

avocadoDataSet = pd.read_csv('avocado.csv')

avocadoDataSet_melt_4770 = pd.melt(avocadoDataSet, id_vars=['Date', 'AveragePrice', 
'Total Volume', '4046', '4225', 'Total Bags', 'Small Bags', 'Large Bags', 'XLarge Bags',
 'type', 'year', 'region'], var_name='avocados_variety', value_name='4770')

avocadoDataSet_melt_4225 = pd.melt(avocadoDataSet_melt_4770, id_vars=['Date', 
'AveragePrice', 'Total Volume', '4046', 'Total Bags', 'Small Bags', 'Large Bags', 
'XLarge Bags', 'type', 'year', 'region'], var_name='avocados_variety', value_name='4225')

avocadoDataSet_melt_4046 = pd.melt(avocadoDataSet_melt_4225, id_vars=['Date', 
'AveragePrice', 'Total Volume', 'Total Bags', 'Small Bags', 'Large Bags', 'XLarge Bags', 
'type', 'year', 'region'], var_name='avocados_variety', value_name='4046')

print(avocadoDataSet_melt_4046.head())


# Observations
# Melting of TMDB dataset is out of scope.
# We have taken new dataset from Kaggle
# Here in dataset we have three different variety of avocado: 4770, 4225 and 4046
# Its not the best way to melt multiple columns.
# To understand how melt works, the above example can be useful

这看起来很棒。但有时我们有一个数据集,我们需要将行变为当时该做什么的列?答案正在枢转数据集。

枢转数据

枢转数据与数据集的熔化相反。 Pandas提供pivot_table()方法来枢转数据集。我们应该知道有三个熔体函数参数。这些都是:

  1. 索引 - 它代表了我们不想枢转的列
  2. 列 - 它代表了我们想要枢转的列
  3. 值 - 它表示列枢转时要使用的值

让我们看看如何在行动中枢转:

# After melting the dataset, here we will see how pivoting works with dataset
# Pivoting of dataset
avocadoDataSet_melt_4046['4046'] = pd.to_numeric(avocadoDataSet_melt_4046['4046'], 
                                                           errors='coerce')

avocadoDataSet_pivot = avocadoDataSet_melt_4046.pivot_table(index=['Date'], 
columns='type', values='4046', aggfunc=np.mean)

print(avocadoDataSet_pivot.head())


#Observations
# We saw that type column has only two distinct values.
# So what if we want to see the mean of avocado variety by the type?
# We can do this by pivoting the dataSet as we did above.

笔记: 

  1. .pivot_table()使用的默认聚合函数是np.mean()。所以我们可以在sript上方ran,而无需将aggfunc参数指定为pivot_table()函数。
  2. 有时,您可以观察到数据集之后数据集的索引不正确。因此要更正它,您必须使用下面显示的命令重置索引:
tmdbDataSet_pivot = tmdbDataSet_pivot.reset_index()

我们也可以在不指定值属性的情况下枢转数据集。在这种情况下,数据集中的每个列都将由我们以Pivot方法指定的列参数拼接。

# Pivoting of dataset without specifying values
avocadoDataSet_pivot = avocadoDataSet_melt_4046.pivot_table(index=['Date'], 
columns='type')

print(avocadoDataSet_pivot.head())

# Observations
# Each and every column of data set will have two sub divided columns
# Two sub divided columns will be of type as we have specified in columns parameter

我们还可以将边缘属性指定为pivot_table函数,该函数也将显示每个单独列的总和。

# Pivoting of dataset with margin
avocadoDataSet_pivot_margin = avocadoDataSet_melt_4046.pivot_table(index=['Date'], 
columns='type', margins=True)

print(avocadoDataSet_pivot_margin.tail())

除了我们上面讨论的技术外,还有一些其他技术来清理我们的数据集。这些包括:

  1. 分裂列
  2. 级联数据或文件
  3. 合并数据
  4. 使用正则表达式和应用功能
  5. 替换重复/缺少数据

让我们详细讨论上述概念,并了解他们如何帮助清洁数据集。

堆叠和拆卸数据集

堆叠和unstacking是根据我们想要的方式重新排列数据的另一种方法。我们将在实例的帮助下更清楚地了解它。

堆叠数据集

堆叠DataFrame意味着将最内最内的列索引移动到最内部的行索引。考虑一个示例,如下所示:

# Stacking datasets
avocadoDataSet_stacked = avocadoDataSet_pivot.stack() 
# Or avocadoDataSet_pivot.stack(level=1)

display(avocadoDataSet_stacked.head())

以上描述了堆叠数据集的技术。在这里,我们考虑了我们从枢转数据集示例中生成的相同数据集。 

在我们的Avocadodataset_pivot数据集中,每个列和每列进一步分为传统和有机。

我们还可以通过称为“级别”的参数,该参数将决定要作为行索引移动的列索引。

unstaching dataSet.

虽然unsstach与堆叠数据集相反。 unstacke dataframe意味着将最内部的行索引移动到最内部列索引。考虑下面显示的示例:

# Unstacking the stacked datset
display(avocadoDataSet_stacked.unstack())

在上面显示的示例中,我们正在取消堆叠堆叠的数据集以返回原始枢转的数据集。

我们还可以通过称为“级别”的参数,该参数将决定我们想要移动为列索引的行索引。

笔记: 堆叠和unstacking的级别的默认值是最内最美的列或行级指数。

分裂列

有时可能发生在数据集中的单个列可能包含比预期更多的信息。例如,同一列中的名字和姓氏。让我们看看我们如何将信息从一个列拆分为两列:

import pandas as pd

avocadoDataSet = pd.read_csv('avocado.csv')


month = {1: 'JAN', 2: 'FEB', 3: 'MAR', 4: 'APR',5: 'MAY', 6: 'JUNE',
                7: 'JULY', 8: 'AUG', 9: 'SEP', 10: 'OCT', 11: 'NOV', 12: 'DEC' }

avocadoDataSet['Month'] = avocadoDataSet.Date.str.split('-').str.get(1)
avocadoDataSet['Month'] = pd.to_numeric(avocadoDataSet['Month'], errors='coerce')
avocadoDataSet['Month'] = avocadoDataSet['Month'].map(month)

print(avocadoDataSet.head())


# Observations
# We have fetched out month column from date using split fuction

上面的示例显示了从日期列中获取月份的方法。

级联数据或文件

我们可以从各种文件中获取我们的信息。可能发生这种情况可能是:

  1. 巨大的文件需要划分
  2. 我们的来源每天生成数据文件

PANDAS提供使用我们可以将多个数据集求出到单个数据集中的芯片功能。

import pandas as pd

row_concat = pd.concat([dataSet_1, dataSet_2, dataSet_3])

我们还可以为我们的数据集进行列明的连接。为此,我们也可以使用Concat函数,但具有额外的参数“轴”。

import pandas as pd

col_concat = pd.concat([dataSet_1, dataSet_2],axis=1)

笔记: 行明智连接的轴的默认居住是0。

当我们有限的数据集来拍摄时,上述技术非常有用。但是,如果我们有1000个数据集,我们需要拍照? 

要解决这个问题,我们有一个名为glob的包。 Glob Package具有名为Glob的函数,它将参数作为模式,并返回与该模式匹配的工作目录中的文件列表。让我们看看一个例子:

import glob
import pandas as pd

pattern = '*.csv'
csv_files = glob.glob(pattern)
dataset = pd.read_csv(csv_files[1])

合并数据

将两个数据集合并到一个类似于在关系数据库中加入两个表。我们可以基于表中的列加入数据集。 

o2o = pd.merge(left=site, right=visited, left_on='name', right_on='site')

使用正则表达式和应用功能

使用正则表达式,我们可以测试某些特定模式的数据。 Python提供了使用它可以执行相关的相关任务的正常表达式的“重新”软件包。让我们看看我们如何用一个例子的帮助点来做到这一点:

import re

prog = re.compile('\d{3}-\d{3}-\d{4}')
result = prog.match('123-456-7890')
print(bool(result))

result = prog.match('1123-456-7890')
print(bool(result))

“重新”软件包提供FindAll函数,我们可以使用它在字符串中找到所有匹配模式。

matches = re.findall('\d+', 'Out of 3 houses, 2 houses have 4 people statying.')
print(matches)

# Observation
# The above code will find out all the numbers in the string

我们学会了如何写作功能 Python用于数据科学 - 第2部分。在这里,我们将看到我们如何将函数应用于行列值。

def encode_avocado_type(value):
    if value == 'conventional':
        return 1
    elif value == 'organic':
        return 0

avocadoDataSet['type_coded'] = avocadoDataSet.type.apply(encode_avocado_type)

print(avocadoDataSet.head())

我们还阅读了关于Lambda功能的 Python用于数据科学 - 第2部分。在这里,我们将看到我们如何使用lambda函数(函数的缩写)来操纵数据集。

import pandas as pd

avocadoDataSet = pd.read_csv('avocado.csv')
del avocadoDataSet['Unnamed: 0'] # removing unwanted column from dataset

avocadoDataSet['Date_replace'] = avocadoDataSet['Date'].apply(lambda x: x.replace('-', '/'))

avocadoDataSet['Date_find'] = avocadoDataSet['Date'].apply(lambda x: re.findall('\d', x))

print(avocadoDataSet.head())

替换重复/缺少数据

如果我们在数据集中有重复或缺少值,则在数据分析结果期间肯定会导致问题。我们肯定的实时数据肯定有这个问题。重复数据也会消耗额外的空间和内存。因此,解决这个问题真的很重要。 

drop_duplicates函数用于删除数据集中的重复行。

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')
avocadoDataSet = pd.read_csv('avocado.csv')
del avocadoDataSet['Unnamed: 0'] # removing unwanted column from dataset

print(tmdbDataSet.info())
print(avocadoDataSet.info())

avocadoDataSet.drop_duplicates()
tmdbDataSet.drop_duplicates()

print(tmdbDataSet.info())
print(avocadoDataSet.info())

# Observations
# Since there are no duplicates rows in both of the datsets
# Therefore we can't see any chnage in rows returned

我们还可以从数据集中删除数据,其中我们缺少列的数据。为此,我们可以使用Dropna功能。考虑下面显示的示例:

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')

print(tmdbDataSet.shape)

# remove the row if any column have null value
print(tmdbDataSet.dropna(how='any').shape)

# remove the row if all column have null value
print(tmdbDataSet.dropna(how='all').shape)

# returns dataset where 19 columns have non N/A values
print(tmdbDataSet.dropna(thresh=19).info())

# drop rows where we have N/A value for a specific column
print(tmdbDataSet.dropna(subset=['runtime']).shape)

处理数据集中缺失的数据是一个重要问题。我们的分析应该首先检查我们有多少丢失的数据。根据我们的需求,有很多方法可以处理缺失的数据。

  1. 我们可以从数据集中删除行以获取缺失值。但我们需要小心,假设我们有100行数据,40行缺少数据。删除行是正确的选项?
  2. 我们可以在列中填充缺失的值,其中含义列值。
  3. 我们可以使用前向填充和后退填充策略

让我们来看看代码以填补缺失的值,含义。

runtime_mean = tmdbDataSet.runtime.mean()
tmdbDataSet['runtime'] = tmdbDataSet['runtime'].fillna(runtime_mean)

print(tmdbDataSet.info())

# Observations
# Filling values for two rows for which runtime value is null

前进填充和落后填充

我们已经看到了如何用列的平均值替换丢失的列值。现在,让我们看看如何使用前向填充和后退填充,以填补我们数据集中缺少的值。

import pandas as pd

tmdbDataSet = pd.read_csv('tmdb_5000_movies.csv')

# 前进填充和落后填充
tmdbDataSet['homepage_ffill'] = tmdbDataSet['homepage'].fillna(method='ffill')
tmdbDataSet['homepage_bfill'] = tmdbDataSet['homepage'].fillna(method='bfill')
print(tmdbDataSet[tmdbDataSet['homepage_ffill'].isnull()])

向前填充该行的特定列,其值为null的行将由该特定行顶部的行值填充。

虽然,使用向后填充该行的特定列,其值为null将由该特定行底部的行值填充。

请注意,选择要丢失的策略取决于您正在分析的数据集。没有100%正确或错误的策略。

清洁数据集是整个分析中最重要的过程之一,数据分析师在此阶段花费大部分时间。在此帖子中,我已经尝试涵盖正在遵循的每种可能的技术,以清除脏数据集。一旦我们完成了DataSet的清洁完成,下一步要查找要从数据集中求出的答案。

我们也创造了一个 jupyter笔记本 您可以在哪里练习和增强数据集,并根据您的目标进行清洁。希望你已经学会了这篇文章的新东西。继续支持和订阅最新更新。

    作者信息

    Tavish Aggarwal.

    网站: http://tavishaggarwal.com

    Tavish Aggarwal.是一个数据科学家 在一个海德拉巴工作,具有广泛的经验,在跨电子商务,财务,医疗保健等等不同领域解决现实世界的业务问题。 他对技术充满热情,喜欢在团队中工作。