本文概述
本教程将引导你完成一些基本的概念和数据准备步骤。掌握任何类型的数据集之后, 数据准备是第一步。这是将原始数据预处理为可以轻松, 准确地分析的形式的步骤。正确的数据准备可以进行有效的分析-可以消除在数据收集过程中可能发生的错误和不准确之处, 从而可以帮助消除因数据质量差而引起的一些偏见。因此, 分析师的很多时间都花在了这一至关重要的步骤上。
加载数据, 清理数据(删除不必要的数据或错误的数据), 转换数据格式和重新排列数据是数据准备步骤中涉及的各个步骤。在本教程中, 你将使用Python的Pandas库进行数据准备。
确保你了解Pandas DataFrame, Series等概念, 因为你将在本教程中大量阅读它。你可以在srcmini的Pandas教程中进一步了解Pandas。
在本教程中:
- 首先, 你将简要介绍Pandas-使用的库。
- 然后, 你将加载数据。
- 接下来, 你将看到丢失的数据是什么以及如何使用它们。你将看到如何处理丢失的数据以及填充丢失的数据的方法。
- 然后, 你将学习一些数据转换技巧:替换值, 连接Pandas系列, 使用地图函数向数据集中添加知识, 离散化连续数据, 最后涉及虚拟变量和一键编码。
顺便说一句, 这里有一些技巧, 窍门, 还可以参考其他更深入的材料, 以防你想深入探讨某个主题。
让我们从对Pandas的简短介绍开始…
Pandas
Pandas是为Python编写的软件库。它在数据科学界非常有名, 因为它提供了功能强大, 表现力强且灵活的数据结构, 使数据操作, 分析变得容易并且可以免费获得。此外, 如果你有特定的新用例, 甚至可以在Python邮件列表之一或pandas GitHub站点上共享它-实际上, 这是现实世界中驱动pandas的大多数功能的方式用例。
要获得有关Pandas的出色介绍, 请务必查看srcmini的Pandas基金会课程。它是非常互动的, 第一章是免费的!
要使用pandas库, 你需要先将其导入。只需在你的python控制台中输入以下内容即可:
import pandas as pd
加载数据中
数据准备的第一步是……好吧, 获取一些数据。如果你有.csv文件, 则可以使用pandas中的.read_csv()函数轻松地将其加载到系统中。然后可以输入:
数据= pd.read_csv(‘path_to_file.csv’)
但是, 对于本教程, 你将使用动态创建的一些较小的, 易于理解的DataFrame和Series。
缺失数据
处理丢失的数据
这是数据分析世界中普遍存在的问题。
由于多种原因, 数据集中可能会丢失数据:用户/数据收集应用程序未添加特定字段的数据, 手动传输时数据丢失, 编程错误等。有时, 弄清原因是必不可少的因为这会影响你处理此类数据的方式。但这将在本教程后面讨论。现在, 让我们集中讨论如果缺少数据该怎么办…
对于数字数据, Pandas使用浮点值NaN(非数字)表示丢失的数据。它是库Numpy下定义的唯一值, 因此我们也需要导入它。由于计算速度和便利性的原因, NaN是默认的缺失值标记。从某种意义上来说, 这是一个前哨值, 可以使用Pandas中的函数轻松检测和使用伪数据或标志值。
让我们玩一些数据…
import numpy as np
# Creating a pandas series
data = pd.Series([0, 1, 2, 3, 4, 5, np.nan, 6, 7, 8])
# To check if and what index in the dataset contains null value
data.isnull()
0 False
1 False
2 False
3 False
4 False
5 False
6 True
7 False
8 False
9 False
dtype: bool
上面, 我们使用了函数isull()返回布尔值true或false。是的, 当该特定索引处的数据实际上丢失或为NaN时。相反的是notnull()函数。
# To check where the dataset does not contain null value - opposite of isnull()
data.notnull()
0 True
1 True
2 True
3 True
4 True
5 True
6 False
7 True
8 True
9 True
dtype: bool
此外, 我们可以使用dropna()函数过滤掉丢失的数据并删除null(缺失)值, 并仅查看非null值。但是, NaN值并没有真正删除, 仍然可以在原始数据集中找到。
# Will not show the index 6 cause it contains null (NaN) value
data.dropna()
0 0.0
1 1.0
2 2.0
3 3.0
4 4.0
5 5.0
7 6.0
8 7.0
9 8.0
dtype: float64
data
0 0.0
1 1.0
2 2.0
3 3.0
4 4.0
5 5.0
6 NaN
7 6.0
8 7.0
9 8.0
dtype: float64
要真正”删除”或删除NaN值, 你可以执行的操作是存储新数据集(不使用NaN), 以使原始数据系列不被篡改或就地放置删除。 inplace参数的默认值为false。
not_null_data = data.dropna()
not_null_data
0 0.0
1 1.0
2 2.0
3 3.0
4 4.0
5 5.0
7 6.0
8 7.0
9 8.0
dtype: float64
# Drop the 6th index in the original 'data' since it has a NaN place
data.dropna(inplace = True)
data
0 0.0
1 1.0
2 2.0
3 3.0
4 4.0
5 5.0
7 6.0
8 7.0
9 8.0
dtype: float64
但是, 数据框可能更复杂并且为2维, 这意味着它们包含行和列。Pandas还有你覆盖…
# Creating a dataframe with 4 rows and 4 columns (4*4 matrix)
data_dim = pd.DataFrame([[1, 2, 3, np.nan], [4, 5, np.nan, np.nan], [7, np.nan, np.nan, np.nan], [np.nan, np.nan, np.nan, np.nan]])
data_dim
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 1.0 | 2.0 | 3.0 | NaN |
1 | 4.0 | 5.0 | NaN | NaN |
2 | 7.0 | NaN | NaN | NaN |
3 | NaN | NaN | NaN | NaN |
现在, 假设你只想删除全部为空的行或列, 或者仅删除包含一定数量的空值的行或列。检查各种情况, 请记住, 下降并不是就地发生的, 因此真实数据集不会被篡改。请注意传递给dropna()函数的参数, 以确定如何删除丢失的数据。
# Drop all rows and columns containing NaN value
data_dim.dropna()
0 | 1 | 2 | 3 |
---|
# Drop all rows and columns containing entirely of NaN value
data_dim.dropna(how = 'all')
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 1.0 | 2.0 | 3.0 | NaN |
1 | 4.0 | 5.0 | NaN | NaN |
2 | 7.0 | NaN | NaN | NaN |
# Drop only columns that contain entirely NaN value
# Default is 0 - which signifies rows
data_dim.dropna(axis = 1, how = 'all')
0 | 1 | 2 | |
---|---|---|---|
0 | 1.0 | 2.0 | 3.0 |
1 | 4.0 | 5.0 | NaN |
2 | 7.0 | NaN | NaN |
3 | NaN | NaN | NaN |
# Drop all columns that have more than 2 NaN values
data_dim.dropna(axis = 1, thresh = 2)
0 | 1 | |
---|---|---|
0 | 1.0 | 2.0 |
1 | 4.0 | 5.0 |
2 | 7.0 | NaN |
3 | NaN | NaN |
# Drop all rows that have more than 2 NaN values
data_dim.dropna(thresh = 2)
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 1.0 | 2.0 | 3.0 | NaN |
1 | 4.0 | 5.0 | NaN | NaN |
现在, 你知道了如何识别和删除缺失值-是仅查看结果数据集还是就地删除。在许多情况下, 简单地删除null值是不可行的选择, 并且你可能想用其他一些值填充丢失的数据。让我们看看如何做到这一点…
填写缺失数据
要替换或”填充”空数据, 可以使用fillna()函数。例如, 让我们尝试使用与上述相同的数据集, 并尝试用0填充NaN值。
# Check what the dataset looks like again
data_dim
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 1.0 | 2.0 | 3.0 | NaN |
1 | 4.0 | 5.0 | NaN | NaN |
2 | 7.0 | NaN | NaN | NaN |
3 | NaN | NaN | NaN | NaN |
# Fill the NaN values with 0
data_dim_fill = data_dim.fillna(0)
data_dim_fill
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 1.0 | 2.0 | 3.0 | 0.0 |
1 | 4.0 | 5.0 | 0.0 | 0.0 |
2 | 7.0 | 0.0 | 0.0 | 0.0 |
3 | 0.0 | 0.0 | 0.0 | 0.0 |
就像dropna()一样, 你还可以根据传递的参数类型做很多其他事情。还要提醒你, 传递inplace = True参数将更改原始数据集。
# Pass a dictionary to use differnt values for each column
data_dim_fill = data_dim.fillna({0: 0, 1: 8, 2: 9, 3: 10})
data_dim_fill
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 1.0 | 2.0 | 3.0 | 10.0 |
1 | 4.0 | 5.0 | 9.0 | 10.0 |
2 | 7.0 | 8.0 | 9.0 | 10.0 |
3 | 0.0 | 8.0 | 9.0 | 10.0 |
你可以将方法参数传递给fillna()函数, 该函数自动将非空值向前(填充或填充)或向后(填充或回填)传播。
# Pass method to determine how to fill-up the column - forward here
data_dim_fill = data_dim.fillna(method='ffill')
data_dim_fill
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 1.0 | 2.0 | 3.0 | NaN |
1 | 4.0 | 5.0 | 3.0 | NaN |
2 | 7.0 | 5.0 | 3.0 | NaN |
3 | 7.0 | 5.0 | 3.0 | NaN |
你也可以限制上述填充数量。例如, 仅填充列中的两个位置…。此外, 如果传递axis = 1, 则将相应地填充行值。
# Pass method to determine how to fill-up the column - forward here
data_dim_fill = data_dim.fillna(method='ffill', limit = 2)
data_dim_fill
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 1.0 | 2.0 | 3.0 | NaN |
1 | 4.0 | 5.0 | 3.0 | NaN |
2 | 7.0 | 5.0 | 3.0 | NaN |
3 | 7.0 | 5.0 | NaN | NaN |
# Pass method to determine how to fill-up the row - forward here
data_dim_fill = data_dim.fillna(axis = 1, method='ffill')
data_dim_fill
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 1.0 | 2.0 | 3.0 | 3.0 |
1 | 4.0 | 5.0 | 5.0 | 5.0 |
2 | 7.0 | 7.0 | 7.0 | 7.0 |
3 | NaN | NaN | NaN | NaN |
在对数据和用例有一定了解之后, 你可以通过许多其他方式使用fillna()函数, 而不是简单地用数字填充它。你也可以使用平均值(mean()或中位数中位数()来填充它…
# Check the data_dim dataset
data_dim
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 1.0 | 2.0 | 3.0 | NaN |
1 | 4.0 | 5.0 | NaN | NaN |
2 | 7.0 | NaN | NaN | NaN |
3 | NaN | NaN | NaN | NaN |
# Fill the NaN value with mean values in the corresponding column
data_dim_fill = data_dim.fillna(data_dim.mean())
data_dim_fill
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 1.0 | 2.0 | 3.0 | NaN |
1 | 4.0 | 5.0 | 3.0 | NaN |
2 | 7.0 | 3.5 | 3.0 | NaN |
3 | 4.0 | 3.5 | 3.0 | NaN |
数据转换
替换值
到目前为止, 你只处理了缺失数据(NaN), 但是在某些情况下, 你可能希望将非空值替换为其他值。或者, 可能将空值记录为随机数, 因此需要将其处理为NaN而不是数字。这是replace()函数派上用场的地方…
这次我们创建一个不同的数据集。
data = pd.Series([1, 2, -99, 4, 5, -99, 7, 8, -99])
data
0 1
1 2
2 -99
3 4
4 5
5 -99
6 7
7 8
8 -99
dtype: int64
# Replace the placeholder -99 as NaN
data.replace(-99, np.nan)
0 0.0
1 1.0
2 2.0
3 3.0
4 4.0
5 5.0
7 6.0
8 7.0
9 8.0
dtype: float64
你将不再看到-99, 因为它已被NaN取代, 因此未显示。同样, 你可以传递多个要替换的值。为此, 我们将创建另一个系列, 然后将原始数据系列与新系列连接起来, 然后应用多值替换功能。
串联Pandas系列
为此, 我们可以在pandas中使用concat()函数。要在应用串联后继续建立索引, 可以向其传递ignore_index = True参数。
# Create a new Series
new_data = pd.Series([-100, 11, 12, 13])
combined_series = pd.concat([data, new_data], ignore_index = True)
combined_series
0 1
1 2
2 -99
3 4
4 5
5 -99
6 7
7 8
8 -99
9 -100
10 11
11 12
12 13
dtype: int64
# Let's replace -99 and -100 as NaN in the new combined_series
data_replaced = combined_series.replace([-99, -100], np.nan)
data_replaced
0 1.0
1 2.0
2 NaN
3 4.0
4 5.0
5 NaN
6 7.0
7 8.0
8 NaN
9 NaN
10 11.0
11 12.0
12 13.0
dtype: float64
# Argument passed can also be a dictionary with separate values
data_replaced = combined_series.replace({-99: np.nan, -100: 0})
# Same as: new_data.replace([-99, -100], [np.nan, 0])
data_replaced
0 1.0
1 2.0
2 NaN
3 4.0
4 5.0
5 NaN
6 7.0
7 8.0
8 NaN
9 0.0
10 11.0
11 12.0
12 13.0
dtype: float64
增加知识-地图功能
在某些情况下, 你可能希望基于某种逻辑对已经拥有的内容进行更多的了解。这是你可以从地图和功能组合中寻求帮助的时候。逻辑可能会变得更加复杂, 但是请在此示例的帮助下尝试理解。
假设你有一个数字数据框, 该数据框映射到其对应的英语计数。
data_number = pd.DataFrame({'english': ['zero', 'one', 'two', 'three', 'four', 'five'], 'digits': [0, 1, 2, 3, 4, 5]})
data_number
英语 | 数字 | |
---|---|---|
0 | zero | 0 |
1 | one | 1 |
2 | two | 2 |
3 | three | 3 |
4 | four | 4 |
5 | five | 5 |
假设你现在要添加另一列, 将两列的倍数表示为”是”, 其余列表示为”否”。你可以写下每个不同的英语呼叫对应的”是”或”否”的映射。
english_to_multiple = {
'two': 'yes', 'four': 'yes'
}
然后, 当英语列是2的倍数时, 可以调用map函数添加该列。其他非整数列将填充什么?让我们找出…
data_number['multiple'] = data_number['english'].map(english_to_multiple)
data_number
英语 | 数字 | 多 | |
---|---|---|---|
0 | zero | 0 | NaN |
1 | one | 1 | NaN |
2 | two | 2 | yes |
3 | three | 3 | NaN |
4 | four | 4 | yes |
5 | five | 5 | NaN |
其他列填充有NaN值, 并且你已经知道如何进一步使用缺失的值。这是一个简单的例子。但是希望你能从这里启发灵感, 使用想法来使用map函数来做更多的事情, 并在你的特定用例中加以利用。
离散化-剪切功能
有时, 你可能希望基于某种逻辑进行分类, 然后将所有数据放入离散的存储桶或存储箱中以进行分析。你可以为此使用cut()函数。例如, 让我们首先创建一个数据集, 其中包含30个1至100之间的随机数。
import random
data = random.sample(range(1, 101), 30)
# data
[45, 39, 25, 83, 27, 6, 73, 43, 36, 93, 97, 17, 15, 99, 37, 5, 31, 22, 65, 30, 3, 26, 91, 12, 52, 76, 63, 84, 59, 53]
假设我们要按照我们定义自己的存储桶进行分类:数字1-25, 然后25-35, 40-60, 然后60-80, 然后是其余部分。所以我们定义一个桶…
然后, 我们将使用cut函数。
# Defining the starting value for each bucket
bucket = [1, 25, 35, 60, 80, 100]
cut_data = pd.cut(data, bucket)
cut_data
[(35, 60], (35, 60], (1, 25], (80, 100], (25, 35], ..., (60, 80], (60, 80], (80, 100], (35, 60], (35, 60]]
Length: 30
Categories (5, interval[int64]): [(1, 25] < (25, 35] < (35, 60] < (60, 80] < (80, 100]]
cut()是一个非常有用的函数, 你可以使用它做更多的事情。强烈建议你查看Pandas文档以了解更多信息。
虚拟变量和一键编码
当你希望能够将一些分类数据转换为数值以便可以在数据分析模型中使用时, 本主题特别有用。这特别方便, 特别是在进行机器学习建模时(其中一键编码的概念非常著名)。使用更专业的词:”一键编码”是将分类值转换为一维数字矢量的过程。
使用pandas的一种方法是使用get_dummies()函数。如果数据框中的一列具有” n”个不同的值, 则该函数将派生一个矩阵, 其中” n”个列包含全1和0。让我们看一个例子, 以更好地理解这个概念。
# Creating a DataFrame consiting individual characters in the list
data = pd.Series(list('abcdababcdabcd'))
data
0 a
1 b
2 c
3 d
4 a
5 b
6 a
7 b
8 c
9 d
10 a
11 b
12 c
13 d
dtype: object
假设现在你要有单独的向量来指示每个字符的外观, 以将其提供给函数。
像这样:对于’a’= [1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0]其中1处于存在’a’的位置, 并且0表示不存在。使用get_dummies()函数将使任务更加容易。
pd.get_dummies(data)
一种 | b | C | d | |
---|---|---|---|---|
0 | 1 | 0 | 0 | 0 |
1 | 0 | 1 | 0 | 0 |
2 | 0 | 0 | 1 | 0 |
3 | 0 | 0 | 0 | 1 |
4 | 1 | 0 | 0 | 0 |
5 | 0 | 1 | 0 | 0 |
6 | 1 | 0 | 0 | 0 |
7 | 0 | 1 | 0 | 0 |
8 | 0 | 0 | 1 | 0 |
9 | 0 | 0 | 0 | 1 |
10 | 1 | 0 | 0 | 0 |
11 | 0 | 1 | 0 | 0 |
12 | 0 | 0 | 1 | 0 |
13 | 0 | 0 | 0 | 1 |
但是, 这是一个简单的示例, 可帮助你入门。在现实世界的应用程序中, 角色的成员资格可以同时属于各种类别, 因此你将必须学习更复杂的方法。同样对于更大的数据, 此功能在速度方面可能不是很有效。 srcmini的Python处理分类数据讨论了这种情况, 并且对该主题进行了更深入的讨论。
现在怎么办?
好了, 你到了本教程的结尾, 并且你已经学习了一些基本工具来开始数据分析路径中的第一步。学习数据准备步骤的其他技能还包括学习如何检测和过滤数据集中的异常值, 以及数据集是否庞大-也许从随机抽样开始。但是这些本身又是广泛的话题, 很难一概而论。
现实中的用例通常可能更复杂, 并且可能需要其自己独特的解决方案, 但其想法是从小处着手并在此过程中进行学习, 并探索更多并用不同的数据集弄脏你的手!确保检查出srcmini的Python清洗数据课程, 以了解更多工具和技巧, 最后, 你将开始研究从Gapminder Foundation获得的真实, 混乱的数据集。开始吧!
评论前必须登录!
注册