以泰坦尼克号数据集为例,探讨数据清洗及修复的流程手段
发布于 作者:苏南大叔 来源:程序如此灵动~话题回到泰坦尼克数据集,本文以该数据集为例,探讨对数据进行清洗处理的几种方式。对于数据清洗这件事情来说,本文的内容并不是很完整,但是具有代表性。同时,需要注意的是:泰坦尼克数据集也是有很多个版本的,缺失值的情况并不完全一致。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码经验文章。测试环境:python@3.12.3
,pandas@2.2.2
,numpy@1.26.4
,xlrd@2.0.1
,openpyxl@3.1.2
。
加载数据集
数据集不同版本的选择,和后面的代码的编写是很紧密相关的。下面的链接可以对泰坦尼克数据集做较详细的描述。
- https://newsn.net/say/titanic.html
- https://newsn.net/say/sklearn-fetch_openml.html
- https://newsn.net/say/pandas-excel.html
对于na
空值,实际上是本文讨论的重点内容。什么样的数据可以被认为是na
,pandas
是有着自己的标准的。但是,这个标准可以被自定义。比如一些不合理的数据,也可以在读取excel
文件的时候,通过定义na_values
参数,就被自动转化为NA
值。
import pandas as pd
file = "http://hbiostat.org/data/repo/titanic3.xls"
df = pd.read_excel(file, "titanic3", index_col=None, na_values=['NA'])
去掉重复值
是否需要去掉重复值,这个就不一定了,看数据集的具体情况而定。对于本文的泰坦尼克数据集来说,这个操作就是不必要的。不过执行一下,也无伤大雅。
df = df.drop_duplicates()
dataframe
去重的问题,可以参考文章:
- https://newsn.net/say/dataframe-column-duplicates.html
- https://newsn.net/say/dataframe-drop-duplicates.html
删除不合理值
假如,存在着一些明显不合理的数据,也是可以直接删除的。使用dataframe
的条件筛选功能,就可以找到这些数据。
df = df.drop(df[df['age'] <= 5].index)
# print(df)
# print(df.count())
条件筛选的方式写法很多,更多的dataframe
的条件筛选问题,待后续文章讨论。
还可以选择删除掉有缺陷的数据,比如某条数据存在着空值,那么这条数据就可以视为有缺陷的数据。当然,缺陷数据可以弥补修复,也可以被删除掉。
df = df.dropna()
更多参数,可以参考文章:
观察数据集
观察的数据目标,主要包括:一共有多少列数据,各个字段中每个字段都有多少NA
值。这些NA
值就是本文要重点处理的字段。
值得注意的是:read_excel()
的时候,是可以通过定义na_values
谁是NA
,来刻意改变空值的范围的。
print(df.count())
输出:
pclass 1309
survived 1309
name 1309
sex 1309
age 1046
sibsp 1309
parch 1309
ticket 1309
fare 1308
cabin 295
embarked 1307
boat 486
body 121
home.dest 745
dtype: int64
根据输出,可以得出数据。少于计数值1309
的字段,都是存在缺失值的。
参考文章:
筛选目标字段
比如name
字段,对于泰坦尼克数据集的生存率计算来说,并不重要。就可以对它进行删除。参考文章:
df = df.drop("name", axis=1)
df = df.drop(["cabin", "body"], axis=1)
如果想明确的保留哪些字段的时候,也可以这么操作:
selected_cols = ["survived", "pclass", "sex", "age"]
df = df[selected_cols]
填充空值na
对于存在空值的字段,首先要对其进行统计,获得平均值或者中位数值。平均值mean
,填充中位数Median
,或者某个经验值。
这里对年龄字段填充中位数值。参考代码:
# print(df.count())
df['age'] = df['age'].fillna(df['age'].median())
# print(df.count())
可以通过代码df.count()
,观察age
字段的非空值的变化。非空值从1046
变成了1309
。
文字变数字
操作的主要例子就是sex
性别字段,male
变1
,female
变0
。
df['sex2']= df['sex'].map({'female':0, 'male': 1}).astype(int)
# print(df)
输出:
survived pclass sex age sex2
0 1 1 female 29.0000 0
1 1 1 male 0.9167 1
2 0 1 female 2.0000 0
3 0 1 male 30.0000 1
4 0 1 female 25.0000 0
... ... ... ... ... ...
1304 0 3 female 14.5000 0
1305 0 3 female 28.0000 0
1306 0 3 male 26.5000 1
1307 0 3 male 27.0000 1
1308 0 3 male 29.0000 1
数字范围变文字
这个操作的主要例子是age
字段,不同的age
有着不同的年龄段范围,并且这个范围又是可定义的。参考文章:
df["age2"] = pd.cut(df.age, [0, 12, 18, 30, 60, 80], labels=['baby', 'juvenile', 'youth', 'midage', 'oldman'])
# print(df)
通过打印df
,可以看到age
和age2
之间存在着一一对应的关系。
survived pclass sex age age2
0 1 1 female 29.0000 youth
1 1 1 male 0.9167 baby
2 0 1 female 2.0000 baby
3 0 1 male 30.0000 youth
4 0 1 female 25.0000 youth
... ... ... ... ... ...
1304 0 3 female 14.5000 juvenile
1305 0 3 female 28.0000 youth
1306 0 3 male 26.5000 youth
1307 0 3 male 27.0000 youth
1308 0 3 male 29.0000 youth
数字范围变成文字后,通常又接连着groupby
分组操作。不过,这就属于数据分析的范畴了,而不是数据清洗修复。留作后续文章讨论。参考文章:
查看dataframe
所有数据的方式,可以参考:
小数点问题
这里的age
字段有个小数点的问题,可以使用round()
方法解决。比如:
df['age'] = df['age'].fillna(df['age'].median()).round(1)
# print(df)
输出:
survived pclass sex age
0 1 1 female 29.0
1 1 1 male 0.9
2 0 1 female 2.0
3 0 1 male 30.0
4 0 1 female 25.0
... ... ... ... ...
1304 0 3 female 14.5
1305 0 3 female 28.0
1306 0 3 male 26.5
1307 0 3 male 27.0
1308 0 3 male 29.0
枚举变布尔/哑变量/独热码
经过这么多次的文章总结,大家应该也意识到了:单纯的文字是无法完成机器学习的重任的。必须变成数字或者布尔类型,才能参与后续的机器学习计算。所以,对于一些(伪)枚举类型的字段,也可以变成布尔型。使用的方法就是变成“哑变量”。
df = pd.get_dummies(df, columns=['pclass', 'sex'], drop_first=True)
输出:
survived age pclass_2 pclass_3 sex_male
0 1 29.0000 False False False
1 1 0.9167 False False True
2 0 2.0000 False False False
3 0 30.0000 False False True
4 0 25.0000 False False False
... ... ... ... ... ...
1304 0 14.5000 False True False
1305 0 NaN False True False
1306 0 26.5000 False True True
1307 0 27.0000 False True True
1308 0 29.0000 False True True
[1309 rows x 5 columns]
在pd.get_dummies()
中,
columns
指的就是要转变的字段。drop_first
指的是:被转变完的字段要删除掉第一个。(其实就是减少数据的冗余性)
更多内容,请参考文章:
总结
更多苏南大叔使用python
进行数据清洗的内容,请参考:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。