Skip to content

一、清理数据注意事项

在评估之后,下一步是根据评估结果,对数据进行清洗。

(一)、清洗数据之前

在清洗数据之前,我们要先看看索引或列名是否有意义。

如果索引或列名都是乱七八糟的,应该对它们进行重命名,或重新排序,以便我们理解数据。

(二)、结构性问题

清洗数据,我们一般会先解决结构性问题,再处理内容性问题。

整洁数据,根据埃德加科德的第三范式,包括以下三个特点:

  1. 每列是一个变量
  2. 每行是一个观察值
  3. 每个单元格是一个值

任何不符合以上三个特点的数据都是乱数据。

1、每列是观察值,每行是变量

对行和列进行转置

2、每列包含多个变量

  • 对列进行拆分,把多的变量分到其它列去
  • 有的时候光拆分还不够,还要进行重塑,确保每列只包含一种变量

比如:许多列同时包含两个或多个变量的时候

3、每行包含多个观察值

  • 对行进行拆分,让每个观察值为独立的一行
  • 有的时候光拆分还不够,还要进行重塑,确保每列只包含一种观察值

比如:许多行同时包含两个或多个观察值的时候

很多时候,清理前的数据是宽数据,清理后的数据是长数据。

我们清理的目的,是为了后续能更高效地用程序处理数据,而不是更方便地让人类理解,所以清理前的宽数据更直观易懂也是正常的。

(三)、内容性问题

在确保结构不存在问题后,我们再去深入到内容,处理脏数据。

1、缺失数据

针对缺失数据,处理方式需要具体情况具体分析。

  • 如果恰好知道空缺值的实际值,可以更新表格数据,人工把那个值填进去。
  • 如果我们不知道空缺值的实际值,而缺失值并不影响此次分析,最直接的办法是不处理缺失值。

Pandas在计算的时候,会自动忽略缺失值,所以很多时候放着不管不会造成什么问题。

  • 如果是关键变量缺失,我们可以把变量为空缺的行删掉,只留下对分析结果有意义的数据。
  • 如果是关键变量缺失,我们也可以用填充值的方式去处理,比如说把平均数、中位数、众数等填充进去,来代替空缺值

2、重复数据

针对重复数据,我们的处理方式就很简单了。

找到后删除即可,不删除的话,重复数据可能影响分析结论

3、不一致数据

针对不一致数据,我们的目标是对它们进行统一。针对同一含义,只保留一种表达方式,把其余的都进行替换

4、无效/错误数据

针对无效/错误数据,也有不同的清洗途径。

比如删除/替换,否则留下无效/错误数据,也可能影响分析结论。比如说一个负数的身高记录值,可以严重拉低平均值的分析。

  1. 把那条记录值进行删除。因为Pandas会自动忽略空缺值,所以NaN值反而不影响平均值计算
  2. 替换成其他值。比如说平均数。

(四)、其他问题

除了数据本身的问题以外,我们清理数据时,有时候还要针对编程语言或库,做一些其他的处理,包括对数据类型进行转换。

比如:把手机号从数字类型转换成字符串类型;把'是'和'否'转换成布尔值True和False,能让我们之后针对这个变量的分析更加方便,包括能更简洁地进行逻辑判断

二、清理索引和列名

(一)、 重命名索引和列名(使用字典)

DataFrame的rename方法,rename方法会返回一个新的DataFrame

适用于列名或索引数量少的情况

python
import pandas as pd
df1 = pd.read_csv('example1.csv', index_col=0)
df1
客户_姓名客户 性别age邮箱
1李十58[email protected]
2_冯三27[email protected]
3吴十32[email protected]
4王十58[email protected]
_5钱十27[email protected]
6*赵八51[email protected]

1、重命名索引

放入可选参数index,并赋值为一个字典。

字典中,把需要修改的老的名字作为键,把对应的新的名字作为值。

python
df1 = df1.rename(index={'2_': '2', '_5': '5', '6*': '6'})
df1
客户_姓名客户 性别age邮箱
1李十58[email protected]
2冯三27[email protected]
3吴十32[email protected]
4王十58[email protected]
5钱十27[email protected]
6赵八51[email protected]

2、重命名列名

放入可选参数columns,并赋值为一个字典

字典中,把需要修改的老的名字作为键,把对应的新的名字作为值。

python
df1 = df1.rename(columns={'客户_姓名': '客户姓名', '客户 性别': '客户性别', 'age': '客户年龄', '邮箱': '客户邮箱'})
df1
客户姓名客户性别客户年龄客户邮箱
1李十58[email protected]
2冯三27[email protected]
3吴十32[email protected]
4王十58[email protected]
5钱十27[email protected]
6赵八51[email protected]

(二)、重命名索引和列名(函数/方法)

rename方法,除了传入字典,还可以传入一个针对Series的函数或方法,可以是Pandas库里面的,也可以是我们自行定义的

python
df2.rename(index=函数/方法)
df2.rename(columns=函数/方法)

这个函数/方法会把原本索引或列名作为参数,然后返回新的名字。

举个例子:

1、把所有列名变成大写

可以给columns这个可选参数,传入str.upper方法

str是Series类自带的一个属性,会返回一个包含了很多字符串相关操作方法的,StringMethods类的实例(返回实例才可以调用方法),对这个StringMethods实例调用upper方法,就会把Series里所有字符变成大写。

python
s1 = pd.Series(["hello", "this", "is", "Zheng"])
s1

0    hello
1     this
2       is
3    Zheng
dtype: object
python
s1.str
<pandas.core.strings.accessor.StringMethods at 0x1e6708d9710>
python
s1.str.upper()

0    HELLO
1     THIS
2       IS
3    ZHENG
dtype: object

作为columns参数的值,传给rename,执行后就会返回一个列名全变成了大写的DataFrame

python
df2 = pd.read_csv("example2.csv")
df2
DateAmountSalespersonLocation
02022-01-011000AliceNew York
12022-01-021500BobSan Francisco
22022-01-03800CharlieNew York
32022-01-041200DavidSan Francisco
python
df2.rename(columns=str.upper)
DATEAMOUNTSALESPERSONLOCATION
02022-01-011000AliceNew York
12022-01-021500BobSan Francisco
22022-01-03800CharlieNew York
32022-01-041200DavidSan Francisco

2、其他操作

  1. 如果想了解其它对字符串Series调用的方法,可以查看Pandas官方文档

像这些所有以pandas.Series.str开头的,都是可以用在Pandas Series上的字符串操作

所有Series的方法相关文档:

https://pandas.pydata.org/docs/reference/api/pandas.Series.html

  1. 所有DataFrame的方法相关文档:

https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html

  1. Pandas 官万文档: https://pandas.pydata.org/docs/reference

里面有所有 Pandas 库里面的类、类方法、类属性介绍等等。包括Series、DataFrame等

(三)、设置索引

1、把某列设为索引

set_index方法,可以直接把某列属性的值用来作为索引,里面直接传入列名,会返回一个新的DataFrame,其索引变成了那列的值

python
df3 = df2.set_index('Salesperson')
df3
DateAmountLocation
Salesperson
Alice2022-01-011000New York
Bob2022-01-021500San Francisco
Charlie2022-01-03800New York
David2022-01-041200San Francisco

2、重置索引

reset_index方法,相当于做的和set_index相反的事,即把索引重设为初始默认的位置索引,并且把原本作为index的值变成单独一列

python
df3.reset_index()
SalespersonDateAmountLocation
0Alice2022-01-011000New York
1Bob2022-01-021500San Francisco
2Charlie2022-01-03800New York
3David2022-01-041200San Francisco

(四)、对索引和列名重新排序

sort_index方法,适用于数据的索引或列名符合要求,但它的顺序是乱的情况

python
df4 = pd.read_csv('example3.csv', index_col=0)
df4
客户姓名客户性别客户年龄客户邮箱
a李十58[email protected]
c冯三27[email protected]
b吴十32[email protected]
e王十58[email protected]
d钱十27[email protected]
f赵八51[email protected]

1、对索引进行排序

默认axis=0,沿着索引纵向操作,对索引排序

python
df4 = df4.sort_index()
df4
客户姓名客户性别客户年龄客户邮箱
a李十58[email protected]
b吴十32[email protected]
c冯三27[email protected]
d钱十27[email protected]
e王十58[email protected]
f赵八51[email protected]

2、对列名进行排序

指定axis=1,沿着列名纵向操作,对列名排序

python
df4.sort_index(axis=1)
客户姓名客户年龄客户性别客户邮箱
a李十58[email protected]
b吴十32[email protected]
c冯三27[email protected]
d钱十27[email protected]
e王十58[email protected]
f赵八51[email protected]

(五)、可选参数inplace

适用于rename、set_index、reset_index、sort_index方法

传入'inplace=True',表示直接原地修改原始DataFrame,就不用进行赋值了;

并且此时方法不返回新的DataFrame,如果赋值给变量,则变量变为空值。

三、清理乱数据

整洁数据,根据埃德加科德的第三范式,包括以下三个特点:

  1. 每列是一个变量
  2. 每行是一个观察值
  3. 每个单元格是一个值

任何不符合以上三个特点的数据都是乱数据。

(一)、对数据进行转置

当数据的列和行是反的,也就是每列是观察值,每行是变量,需要对数据进行转置

DataFrame的T属性,能返回一个行和列调换后的DataFrame

python
import pandas as pd
df1 = pd.read_csv('example4.csv', index_col=0)
df1
012
姓名张三李四王五
年龄302528
地址北京上海广州
python
df1 = df1.T
df1
姓名年龄地址
0张三30北京
1李四25上海
2王五28广州

(二)、对列进行拆分

当一列有多个变量时,把一列拆分成多列

python
df2 = pd.read_csv("example5.csv")
df2
城市人口密度
0城市A28.53万人/0.87平方公里
1城市B37.83万人/2.19平方公里
2城市C15.3万人/1.57平方公里

1、拆分列

1)针对Python字符串

split方法,参数可以指定分隔符,就会得到拆分后字符串所组成的列表

python
"28.53万人/0.87平方公里".split("/")

['28.53万人', '0.87平方公里']

2)针对Series

str.split方法,参数可以指定分隔符,拆分字符串,调用后返回一个新的Series,每一个元素是一个列表。

但这没有达到拆分列的效果,因为Series只能表示DataFrame的一列,而我们希望拆分成多列。

python
df2['人口密度'].str.split('/')
python
0    [28.53万人, 0.87平方公里]
1    [37.83万人, 2.19平方公里]
2     [15.3万人, 1.57平方公里]
Name: 人口密度, dtype: object

3)拆分列(其实也是针对Series)

str.split方法,额外指定一个可选参数expand=True,表示把分隔后的结果分别用单独的Series表示,这样输出结果就会变成一个包含多列的DataFrame

python
df2['人口密度'].str.split('/', expand=True)
01
028.53万人0.87平方公里
137.83万人2.19平方公里
215.3万人1.57平方公里

2、把新生成的DataFrame添加进原先的DataFrame

其实就是添加多列

在DataFrame后面方括号里放入列表,列表里放入多个列名,赋值给要加入的新列所组成的DataFrame

python
df2[['人口', '面积']] = df2['人口密度'].str.split('/', expand=True)
df2
城市人口密度人口面积
0城市A28.53万人/0.87平方公里28.53万人0.87平方公里
1城市B37.83万人/2.19平方公里37.83万人2.19平方公里
2城市C15.3万人/1.57平方公里15.3万人1.57平方公里

3、删除拆分前的列

drop方法,指定axis=1

python
df2 = df2.drop('人口密度', axis=1)
df2
城市人口面积
0城市A28.53万人0.87平方公里
1城市B37.83万人2.19平方公里
2城市C15.3万人1.57平方公里

(三)、把不同列合并成一列

python
df3 = pd.DataFrame({'姓': ['张', '李', '王'], '名': ['三', '四', '五'], '年龄': [30, 25, 35]})
df3
年龄
030
125
235
  1. 拼接字符串

str.cat方法,参数传入拼接的Series,可以拼接2个Series。

可以传入可选参数sep,来指定拼接时的分隔符

  1. 添加列
  2. 删除拼接前的列

df3.姓.str.cat(df3.名)

python
0    张三
1    李四
2    王五
Name: 姓, dtype: object

df3['姓'].str.cat(df3['名'], sep='-')

python
0-
1-
2-
Name: 姓, dtype: object
python
df3['姓名'] = df3.姓.str.cat(df3.名)
df3 = df3.drop(['姓', '名'], axis=1)
df3
年龄姓名
030张三
125李四
235王五

(四)、把宽数据转换成长数据

python
df4 = pd.read_csv('example6.csv')
df4
国家代码年份男性年龄组(0-4岁)男性年龄组(5-14岁)男性年龄组(15-24岁)女性年龄组(0-4岁)女性年龄组(5-14岁)女性年龄组(15-24岁)
0CN201910020050080150400
1US20195015030040100200
2JP2019301202502080150
3IN20198018040060120300

即重塑列,具体来说是在把一部分列名的值,转换为变量的值

pd.melt方法,可以帮我们进行这方面的转换。

第一个参数传入要转换的DataFrame

可选参数id_vars传入一个列表,里面放入想保持原样的列,那么除了id_vars列表里面之外的列,都会被视为要进行转换的列

可选参数var_name,要被赋值为在转换后的DataFrame中,包含原本列名值的新列列名

可选参数value_name,要被赋值为在转换后的DataFrame中,包含原本变量值的新列列名

运行后,就会返回一个从原本宽数据转换成长数据的DataFrame

python
df4 = pd.melt(df4, 
              id_vars=['国家代码', '年份'], 
              var_name='年龄组', 
              value_name='肺结核病例数')
df4
国家代码年份年龄组肺结核病例数
0CN2019男性年龄组(0-4岁)100
1US2019男性年龄组(0-4岁)50
2JP2019男性年龄组(0-4岁)30
3IN2019男性年龄组(0-4岁)80
4CN2019男性年龄组(5-14岁)200
5US2019男性年龄组(5-14岁)150
6JP2019男性年龄组(5-14岁)120
7IN2019男性年龄组(5-14岁)180
8CN2019男性年龄组(15-24岁)500
9US2019男性年龄组(15-24岁)300
10JP2019男性年龄组(15-24岁)250
11IN2019男性年龄组(15-24岁)400
12CN2019女性年龄组(0-4岁)80
13US2019女性年龄组(0-4岁)40
14JP2019女性年龄组(0-4岁)20
15IN2019女性年龄组(0-4岁)60
16CN2019女性年龄组(5-14岁)150
17US2019女性年龄组(5-14岁)100
18JP2019女性年龄组(5-14岁)80
19IN2019女性年龄组(5-14岁)120
20CN2019女性年龄组(15-24岁)400
21US2019女性年龄组(15-24岁)200
22JP2019女性年龄组(15-24岁)150
23IN2019女性年龄组(15-24岁)300

(五)、对行进行拆分

python
df5 = pd.read_csv("example7.csv")
df5
学生姓名学号课程列表
0张三1['数学', '物理']
1李四2['英语', '化学', '历史']
2王五3['语文', '数学', '英语', '政治']
3赵六4['物理', '生物']

虽然上面的课程列表变量看起来像是列表,但实际上是字符串

比如第一行里的课程列表实际为字符串"['数学', '物理']",而不是列表['数学', '物理']

所以我们需要先将字符串形式的列表转换为实际的列表对象,这样explode才能对列表进行拆分

python
import json
df5['课程列表'] = df5['课程列表'].apply(lambda x: json.loads(x.replace("'", "\"")))
df5
学生姓名学号课程列表
0张三1[数学, 物理]
1李四2[英语, 化学, 历史]
2王五3[语文, 数学, 英语, 政治]
3赵六4[物理, 生物]

当某列的值都是列表,而不是一个个独立的值

df.explode方法,传入需要拆分的变量名,就会返回一个把该列列表中每一个元素,转换为单独一行的新DataFrame

这个方法很实用,当每个单元格是一个值而不是列表时,更好进行统计

python
df5 = df5.explode('课程列表')
df5
学生姓名学号课程列表
0张三1数学
0张三1物理
1李四2英语
1李四2化学
1李四2历史
2王五3语文
2王五3数学
2王五3英语
2王五3政治
3赵六4物理
3赵六4生物

(六)、对行或列进行删除

当我们想清理无效或无用的行或列

drop方法

基本上,对DataFrame的操作方法,都是默认不改变原始DataFrame的,而是返回一个新的DataFrame

要么就得进行重新赋值,要么指定可选参数inplace=True

四、清理脏数据

python
import pandas as pd
import numpy as np

(一)、处理缺失数据

1、对整列缺失值进行填充

python
# 创建示例 DataFrame
df1 = pd.DataFrame({
    '日期': ['2005-01-01', '2005-01-02', '2005-01-03', '2005-01-03'],
    '销售额': [1000, 1500, 800, 1200],
    '销售人员': ['李华', '王磊', '刘娜', '张洋'],
    '地址': ['苏州', '郑州', '南京', '西安']
})
df1 = df1.rename(index={
    0: '001',
    1: '002',
    2: '003',
    3: '004'
})
df1['国家'] = np.nan
df1
日期销售额销售人员地址国家
0012005-01-011000李华苏州NaN
0022005-01-021500王磊郑州NaN
0032005-01-03800刘娜南京NaN
0042005-01-031200张洋西安NaN
  1. 对全是缺失值的列填入统一值,可以通过针对列的赋值操作
  2. 对全是缺失值的列填入不同值

见更新DataFrame的一列值 2.15.一.1.

python
df1["国家"] = "中国"
df1
日期销售额销售人员地址国家
0012005-01-011000李华苏州中国
0022005-01-021500王磊郑州中国
0032005-01-03800刘娜南京中国
0042005-01-031200张洋西安中国

2、对整行缺失值进行填充

  1. 对全是缺失值的行填入统一值,可以通过针对行的赋值操作
  2. 对全是缺失值的行填入不同值,见更新DataFrame的一行值
python
df1.iloc[3] = np.nan
df1
日期销售额销售人员地址国家
0012005-01-011000.0李华苏州中国
0022005-01-021500.0王磊郑州中国
0032005-01-03800.0刘娜南京中国
004NaNNaNNaNNaNNaN
python
df1.iloc[3] = "test"
df1
日期销售额销售人员地址国家
0012005-01-011000.0李华苏州中国
0022005-01-021500.0王磊郑州中国
0032005-01-03800.0刘娜南京中国
004testtesttesttesttest

3、对某个缺失值进行填充

python
# 创建示例 DataFrame
df2 = pd.DataFrame({
    '日期': ['2005-01-01', '2005-01-02', '2005-01-03', '2005-01-03'],
    '销售额': [1000, 1500, np.nan, 1200],
    '销售人员': ['李华', '王磊', '刘娜', '张洋'],
    '地址': ['苏州', '郑州', '南京', '西安']
})
df2 = df2.rename(index={
    0: '001',
    1: '002',
    2: '003',
    3: '004'
})
df2
日期销售额销售人员地址
0012005-01-011000.0李华苏州
0022005-01-021500.0王磊郑州
0032005-01-03NaN刘娜南京
0042005-01-031200.0张洋西安

可以先用loc或iloc先去定位到那个值,然后重新赋值

用loc或iloc先去定位值,见Dataframe章节

python
df2.loc['003', '销售额'] = 800
df2
日期销售额销售人员地址
0012005-01-011000.0李华苏州
0022005-01-021500.0王磊郑州
0032005-01-03800.0刘娜南京
0042005-01-031200.0张洋西安

4、对部分缺失值进行填充

python
df3 = pd.DataFrame({
    '日期': ['2005-01-01', '2005-01-02', np.nan, np.nan],
    '销售额': [1000, 1500, 800, 1200],
    '销售人员': ['李华', '王磊', '刘娜', '张洋'],
    '地址': ['苏州', '郑州', '南京', '西安']
})
df3 = df3.rename(index={
    0: '001',
    1: '002',
    2: '003',
    3: '004'
})
df3
日期销售额销售人员地址
0012005-01-011000李华苏州
0022005-01-021500王磊郑州
003NaN800刘娜南京
004NaN1200张洋西安
1)填入统一值

如果要替换某一部分的值,也是一样的道理,能用loc或iloc提取出来的部分,都可以通过赋值来填充或替换值。

python
df3.loc['003': '004', '日期'] = '2005-01-03'
df3
日期销售额销售人员地址
0012005-01-011000李华苏州
0022005-01-021500王磊郑州
0032005-01-03800刘娜南京
0042005-01-031200张洋西安
2)分别填入值

如果要对部分缺失值,分别填入不同值,可以用元组或列表的形式来赋值

缺失值的个数和元组或列表里元素的个数,要一致

python
df3.loc['003': '004', '日期'] = ['2005-01-03', '2023-9-15']
df3
日期销售额销售人员地址
0012005-01-011000李华苏州
0022005-01-021500王磊郑州
0032005-01-03800刘娜南京
0042023-9-151200张洋西安

5、自动找到缺失值进行填充

以上方法都需要我们自行定位缺失值的位置,但在数据量很大,缺失值很多的情况下,更需要程序能自动找到所有为NaN的值,然后根据我们的指示进行填充

python
df4 = pd.DataFrame({'A': [1, 2, np.nan, 4],
                    'B': [5, np.nan, 7, np.nan],
                    'C': [8, 9, 10, 11]})
df4
ABC
01.05.08
12.0NaN9
2NaN7.010
34.0NaN11
1)Series的fillna方法

Series有个叫fillna的方法,调用时列里面所有NaN值都会被替换成传入的参数,就不需要一个个去定位缺失值的位置了

a、对缺失值填入确定的值

python
df4['B'].fillna(0)

0    5.0
1    0.0
2    7.0
3    0.0
Name: B, dtype: float64

b、对缺失值填入某个计算结果

fillna方法里,除了传入确定的参数,还可以替换成某个计算结果,如平均值

python
df4['B'].fillna(df4['B'].mean())

0    5.0
1    6.0
2    7.0
3    6.0
Name: B, dtype: float64
2)DataFrame的fillna方法

DataFrame也有fillna方法,所以除了能填充某列的缺失值,还能直接对整个DataFrame里的缺失值进行填充。

a、对缺失值填入统一值

传入某个值后,返回的新DataFrame里,所有缺失值都会变成那个值

python
df4.fillna(0)
ABC
01.05.08
12.00.09
20.07.010
34.00.011

b、对缺失值按列填入不同值

还可以传入一个字典,键为列名,值为替换值,能实现把不同列里的空缺值,替换成不同值的效果。这个相比Series的fillna方法逐列操作要高效得多

python
df4.fillna({'A': 0, 'B': 10, 'C': 20})
ABC
01.05.08
12.010.09
20.07.010
34.010.011

只返回替换好的新DataFrame

6、删除存在缺失值的行

如果丢失的是对分析目标有关键意义的数据,同时又没有合适的值进行填充,这时我们或许需要抛弃存在空缺值的观察值,调用dropna方法,被用于删除有缺失值的数据

python
df5 = pd.DataFrame({
    '姓名': ['John', 'Alice', 'Bob', 'Mary'],
    '年龄': [25, 30, np.nan, 40],
    '工资': [50000, np.nan, 70000, 60000],
    '性别': ['M', 'F', 'M', 'F']
})
df5
姓名年龄工资性别
0John25.050000.0M
1Alice30.0NaNF
2BobNaN70000.0M
3Mary40.060000.0F
1)删除所有有缺失值的行

DataFrame在dropna方法直接调用时,会返回没有任何缺失值的行,所组成的新DataFrame。也就是说,只要某行任何一个值是空缺的,调用dropna后就见不到它了。

python
df5.dropna()
姓名年龄工资性别
0John25.050000.0M
3Mary40.060000.0F
2)删除关键值缺失的行

但我们一般清理数据的时候,更关注的是某些有关键信息的列,不太关键的变量,即使缺失也问题不大

那我们调用dropna方法时,可以传入一个可选参数subset=['关键值缺失的列的列名1',...]。

python
df5.dropna(subset=['工资'])
姓名年龄工资性别
0John25.050000.0M
2BobNaN70000.0M
3Mary40.060000.0F
3)删除有缺失值的列

指定axis=1

python
df5.dropna(axis=1)
姓名性别
0JohnM
1AliceF
2BobM
3MaryF
python
df5.dropna(axis=1, subset=[0, 1])
姓名年龄性别
0John25.0M
1Alice30.0F
2BobNaNM
3Mary40.0F

(二)、删除重复数据

python
df6 = pd.DataFrame({
    '姓名': ['John', 'Alice', 'Bob', 'Alice', 'John'],
    '年龄': [25, 30, 35, 30, 40],
    '性别': ['M', 'F', 'M', 'F', 'M']
})
df6
姓名年龄性别
0John25M
1Alice30F
2Bob35M
3Alice30F
4John40M

drop_duplicates方法,可以用于删除Series里的重复值,或是DataFrame里的重复行

1、删除所有变量的值都重复的行

直接调用DataFrame的drop_duplicates时,只有当所有变量都一样的时候,才会被视为重复,也因此才会被删除掉。

python
df6['姓名'].drop_duplicates()

0     John
1    Alice
2      Bob
Name: 姓名, dtype: object
python
df6.drop_duplicates()
姓名年龄性别
0John25M
1Alice30F
2Bob35M
4John40M

2、删除特定变量的值重复的行

也可以用subset=['变量1', '变量2'...],只要这个列表里的变量同时重复,就会被删除

python
df6.drop_duplicates(subset=['姓名', '性别'])
姓名年龄性别
0John25M
1Alice30F
2Bob35M

3、可选参数keep

删除的时候,默认是删除第二次及之后出现的值。

但我们也可以把让可选参数keep='last',这样会保留最后一个出现的值,删除掉之前出现的重复值

python
df6.drop_duplicates(subset=['姓名', '性别'], keep='last')
姓名年龄性别
2Bob35M
3Alice30F
4John40M

(三)、处理不一致数据

不一致数据是指,存在不同的值实际含义相同,或指代的是同一目标

处理方法是,把数值都替换成统一的。

python
data = {'姓名': ['小明', '小红', '小张', '小李'],
        '家乡': ['北京', '上海', '广州', '深圳'],
        '学校': ['北京大学', '清华大学', '华南理工', '清华']}
df7 = pd.DataFrame(data)
df7
姓名家乡学校
0小明北京北京大学
1小红上海清华大学
2小张广州华南理工
3小李深圳清华

可以用Series或DataFrame的replace方法,在Series和DataFrame上用法差不多

1、replace方法参数是两个数字或字符串

表示想把前面值全部替换成后面值

python
df7['学校'].replace('清华', '清华大学')

0    北京大学
1    清华大学
2    华南理工
3    清华大学
Name: 学校, dtype: object
plain
df7.replace('清华', '清华大学')
姓名家乡学校
0小明北京北京大学
1小红上海清华大学
2小张广州华南理工
3小李深圳清华大学

2、replace方法第一个参数是一个列表

那么列表里面所有值都会被替换成后面那个,这样就可以一次性,对多个不同指代词进行统一

python
df7['学校'].replace(['清华', '五道口职业技术学院', 'Tsinghua University'],'清华大学')

0    北京大学
1    清华大学
2    华南理工
3    清华大学
Name: 学校, dtype: object
python
df7.replace(['清华', '五道口职业技术学院', 'Tsinghua University'],'清华大学')
姓名家乡学校
0小明北京北京大学
1小红上海清华大学
2小张广州华南理工
3小李深圳清华大学

3、replace方法参数是单个字典

去指定不同的值要被什么值替换

python
replace_dict = {'华南理工': '华南理工大学', 
                '清华': '清华大学', 
                '北大': '北京大学', 
                '中大': '中山大学'}
df7.replace(replace_dict)
姓名家乡学校
0小明北京北京大学
1小红上海清华大学
2小张广州华南理工大学
3小李深圳清华大学

(四)、进行数据类型转换

数据类型转换,在很多时候是有必要,因为某些方法只能用在特定类型的数据上。比如说:不能对字符串求平均值

1、Series的astype方法

参数为数据类型,比如int、float、str、bool等,调用后,返回的新Series里的数据就被转换成了那个类型

python
s1 = pd.Series([1, 2, 3])
s1.astype(float)
python
0    1.0
1    2.0
2    3.0
dtype: float64

2、type函数

在Python里面,如果你想知道数据类型,可以调用type函数

3、Pandas的数据类型category

数据可以被划分为两种类型,分类数据和数值数据。

分类数据,指的是包含有限数量的不同类别的数据,比如:出生时的性别,就两种,是有限的;奥运会的奖牌,金银铜,也是有限的

数值数据,指的是测量出的观测值,是某个具体的数值,种类不受限制。比如:0到1之间就有无限个数字,那对它进行求和或求平均值等数学运算也是有意义的

当分类数据种类有限时,Pandas会推荐把它们转换成category这个数据类型。

好处:节约内存空间,并且在后续分析或可视化的时候,也有利于让Pandas自动选用合适的统计方法或图标类型

category不是Python自带的类型名称,而是Pandas库里面的,所以我们在用astype进行转换的时候,要传入一个用引号包围的category,不然Python不认

python
s2 = pd.Series(["红色", "红色", "橙色", "蓝色"])
s2.astype('category')
python
0    红色
1    红色
2    橙色
3    蓝色
dtype: category
Categories (3, object): ['橙色', '红色', '蓝色']

4、转换成datetime日期时间类型

可以用Pandas的to_datetime方法,参数传入Series,可以返回转换成日期时间类型的Series

python
df3['日期'] = pd.to_datetime(df3['日期'])
df3.日期
python
001   2005-01-01
002   2005-01-02
003   2005-01-03
004   2023-09-15
Name: 日期, dtype: datetime64[ns]

Released under the MIT License.