数据清洗
数据清洗是一项复杂且繁琐的工作,同时也是数据分析过程中最为重要的环节,它主要通过一些处理方法将脏数据清洗干净,是数据具有完整性、唯一性、权威性、合法性、一致性等特点,提高数据的质量。
缺失值的检测
为了检测数据中是否包含缺失值,Pandas 中提供了里昂个函数,分别是 isnull() 和 notnull(),他们接收一个 Series 类或 DataFrame 类对象,返回一个跟元对象形状相同的新对象,新对象中的数据都是表示检测结果的布尔值。
df = pd.DataFrame({'Num1':[1 ,2 ,None ,4],
'Num2':[5 ,6 ,7 ,8],
'Num3':[9 ,10 ,11 ,12],
'Num4':[13 ,14 ,np.nan ,np.nan]})
df.isnull()
# 结果:
# Num1 Num2 Num3 Num4
# 0 False False False False
# 1 False False False False
# 2 True False False True
# 3 False False False True
df = pd.DataFrame({'Num1':[1 ,2 ,None ,4],
'Num2':[5 ,6 ,7 ,8],
'Num3':[9 ,10 ,11 ,12],
'Num4':[13 ,14 ,np.nan ,np.nan]})
df.notnull()
# 结果:
# Num1 Num2 Num3 Num4
# 0 True True True True
# 1 True True True True
# 2 False True True False
# 3 True True True False
如果想要获取缺失值的数量和占比情况,那么可以自定义一个函数。
def missing_values_table(df):
misNum = df.isnull().sum()
misPercent = misNum / len(df) * 100
obj = pd.DataFrame({'数量':misNum,'占比':misPercent})
return obj.sort_values('数量',ascending = False)
missing_values_table(df)
# 结果:
# 数量 占比
# Num4 2 50.0
# Num1 1 25.0
# Num2 0 0.0
# Num3 0 0.0
缺失值的处理
缺失值会影响数据的完整性和准确性,使得分析结果产生偏差或无法得到可靠的结论。
- 删除缺失值:
dropna(axis = 0 ,how = 'any' ,thresh = None , subset = None ,inplace = False)- 部分参数的解释:
- axis:用于确定删除行或列,取值可以是 0 或 index、1 或 columns。
- 0 或 index:表示删除包含缺失值的行(默认值)
- 1 或 columns:表示删除包含缺失值的列
- how:表示删除缺失值的方式,该参数支持 any 和 how 两种取值
- any:表示有 NaN 时便删除整行或整列(默认值)
- all:表示只有所有值为 NaN 值时才删除整行或整列
- thresh:表示保留至少有 N 个非 NaN 值的行或列。如果 N 的值为 2,当删除缺失值时只要一行或一列数据中有两个或两个以上非 NaN 值,就会保留该列。
- axis:用于确定删除行或列,取值可以是 0 或 index、1 或 columns。
- 部分参数的解释:
df = pd.DataFrame({'Num1':[1 ,2 ,None ,4],
'Num2':[5 ,6 ,7 ,8],
'Num3':[9 ,10 ,11 ,12],
'Num4':[13 ,14 ,np.nan ,np.nan]})
# 结果:
# Num1 Num2 Num3 Num4
# 0 1.0 5 9 13.0
# 1 2.0 6 10 14.0
# 2 NaN 7 11 NaN
# 3 4.0 8 12 NaN
# 删除包含缺失值的行
df.dropna()
# 结果:
# Num1 Num2 Num3 Num4
# 0 1.0 5 9 13.0
# 1 2.0 6 10 14.0
# 删除包含缺失值的行,并指定非缺失值的数量
df.dropna(thresh = 3)
# 结果:
# Num1 Num2 Num3 Num4
# 0 1.0 5 9 13.0
# 1 2.0 6 10 14.0
# 3 4.0 8 12 NaN
- 填充缺失值:
fillna(value = None ,method = None ,axis = None ,inplace = False ,limit = None ,downcast = None)- 部分参数的解释:
- value:用于填充的值,可以是标量、字典、Series 或 DataFrame 类的对象。
- method:表示填充方式(默认值为 None),该参数还支持 pad、ffill、backfill 和 bfill 值
- pad 或 ffill 表示向前填充,即用缺失值前面的有效值填充
- backfill 或 bfill 表示后向填充,即用缺失值后面的有效值填充
- limit:可以连续填充的最大数量
- 部分参数的解释:
# 使用常量值进行填充
df.fillna(value= 3)
# 结果:
# Num1 Num2 Num3 Num4
# 0 1.0 5 9 13.0
# 1 2.0 6 10 14.0
# 2 3.0 7 11 3.0
# 3 4.0 8 12 3.0
使用平均值进行填充:
# 使用常量值进行填充
df.fillna(value = {'Num1':round(df['Num1'].mean(),1),'Num4':round(df['Num4'].mean() ,1)})
# 结果:
# Num1 Num2 Num3 Num4
# 0 1.0 5 9 13.0
# 1 2.0 6 10 14.0
# 2 2.3 7 11 13.5
# 3 4.0 8 12 13.5
df.fillna(method = 'ffill')
# 结果:
# Num1 Num2 Num3 Num4
# 0 1.0 5 9 13.0
# 1 2.0 6 10 14.0
# 2 2.0 7 11 14.0
# 3 4.0 8 12 14.0
df.fillna(method = 'bfill')
# 结果:
# Num1 Num2 Num3 Num4
# 0 1.0 5 9 13.0
# 1 2.0 6 10 14.0
# 2 4.0 7 11 NaN
# 3 4.0 8 12 NaN
重复值的检测
重复值是指数据集中某个或某些记录是完全相同的,产生的原因主要有机械故障或人工重复录入。Pandas 中提供了一个检测重复值的方法 duplicated() ,该方法默认情况下会对所有数据进行检测,检测的标准为:
duplicated(subset = None , keep = 'first')- 参数含义:
- subset:用于指定检测重复值的列索引或列索引序列(默认检测所有列)
- keep:用于确定标记哪一行是重复值。
- first(默认值):表示保留第一次出现重复值的行,其余出现重复值的行会被标记
- last:表示保留最后一次出现重复值的行,其余出现重复值的行会被标记
- False:表示标记所有出现重复值的行
- 注意:该方法检测完成后会返回一个新的 Series 对象。
- 参数含义:
df = pd.DataFrame({'name':['张三','李四','王五','赵六','赵六','小明'],
'age':[24,23,29,22,22,27],
'height':[162,168,163,175,175,180]})
df.dupulicated()
# 结果:
# 0 False
# 1 False
# 2 False
# 3 False
# 4 True
# 5 False
重复值的处理
在数据分析中,重复值会影响分析结果的准确性,一般情况下需要进行删除,这样可以保证数据中保留唯一的数据记录。Pandas 中提供了删除重复值的方法 drop_duplicates() 方法。
drop_duplicated(subset = None ,keep = 'first' ,inplace = False ,ignore_index = False)- 参数解释:
- inplace:接收一个布尔值类型的值,表示是否替换原来的数据(默认为 False)
- ignore_index:表示是否重新分配索引(默认值为 False)
- subset:用于指定检测重复值的列索引或列索引序列(默认检测所有列)
- keep:用于确定标记
- first(默认值):表示保留第一次出现重复值的行,其余出现重复值的行会被标记
- last:表示保留最后一次出现重复值的行,其余出现重复值的行会被标记
- False:表示标记所有出现重复值的行
- 参数解释:
df = pd.DataFrame({'name':['张三','李四','王五','赵六','赵六','小明'],
'age':[24,23,29,22,22,27],
'height':[162,168,163,175,175,180]})
df.drop_duplicates()
# 结果:
# name age height
# 0 张三 24 162
# 1 李四 23 168
# 2 王五 29 163
# 3 赵六 22 175
# 5 小明 27 180
异常值的检测
异常值是指数据集中的个别值明显偏离其他所属数据的其余值,这些数值是不合理的或错误的。如果想要确认一组数据中是否有异常值,常见的检测方法有 3σ 原则和箱型图,其中 3σ 原则只适用于符合或近似正态分布的数据集,而箱型图没有什么原则的要求。
- 3σ 原则:又称拉伊达原则,它是指先假设一组检测数据只含有随机误差,对这组数据进行计算处理得到标准偏差,按一定概率确定一个区间。
- 如果超出
(这个区间,则为异常值平均值 - 3 * 标准差,平均值 + 3 * 标准差) - 代码:
- 如果超出
def three_sigma(ser):
# 计算平均值
avg = ser.mean()
# 计算标准差
std = ser.std()
rule = avg + 3 * std > ser | avg - 3 * std < ser
index = np.arange(ser.shape[0])[rule]
return ser.iloc[index]
index = np.arange(ser.shape[0])[rule]
# 可替换为:
index = ser[rule].index
- 箱型图:一种用于显示数据分散情况的统计图,它通过 5 个数据节点描述按照从大到小的顺序排列的一组数据。Pandas 中提供了一个
boxplot()方法,该方法会根据一组数据绘制箱型图,便于用户从箱型图中查看数据中是否有异常值。- 代码:
df = pd.DataFrame({'A':[1,2,3,4,5,6,50,3,3,4,5,3,2,4,5,23,2,5,3],
'B':[2,3,8,5,6,7,8,9,0,3,4,5,6,7,2,4,5,6,4]})
df.boxplot()
运行结果:
![图片[1]-[学习笔记 Day07]数据分析与应用:数据预处理-资源刺客](https://images.kodo.cdn.itdka.cn/wp-contents/uploads/2026/04/20260413124635683-image.png)
如果想进一步获得异常值的位置,可自定义一个函数,在该函数中根据箱型图识别异常值的规则进行判断,即如果一组数据中的值超出 (Q3 + 1.5 * IQR , Q1 - 1.5 * IQR) 这个区间就为异常值。
def boxCheck(ser):
newSer = ser.sort_values()
# 计算下四分位数
q1 = newSer.quantitle(0.25)
# 计算上四分位数
q3 = newSer.quantitle(0.75)
iqr = round(q3 - q1 ,1)
rule = q1 - 1.5 * iqr > ser | q3 + 1.5 * iqr < ser
index = ser.iloc[rule].index
return ser.iloc[index]
Series 对象.quantitle(位数值),用于求上四分位数(0.25)和下四分位数(0.75)
异常值的处理
如果检测出来时异常值,通常情况下会使用指定的值或根据一些算法计算的值替换异常值。在 Pandas 中提供了用于替换值的方法 replace() ,该方法不仅可以对单个值进行替换,还可以对多个值进行批量替换。
replace(to_replace = None ,value = NoDefault.no_default ,inplace = False ,limit = None ,regex = False ,method = NoDefault.no_default)- to_replace:表示被替换的值
- value:表示替换后的值
- inplace:表示是否返回新的对象(True:直接修改原始对象,反之)
- method:表示替换的方式(默认值为 NoDefault.no_default)
- NoDefault.no_default:表示替换过程中没有提供替换方式
- pad 和 ffill:表示向前填充
- bfill:表示向后填充
df = pd.DataFrame({'A':[1,2,3,4,5,6,50,3,3,4,5,3,2,4,5,23,2,5,3],
'B':[2,3,8,5,6,7,8,9,0,3,4,5,6,7,2,4,5,6,4]})
# 执行替换操作并将结果放到原始对象中
df['A'] = df['A'].replace(to_replace=5,value=111)
# 结果:
# A B
# 0 1 2
# 1 2 3
# 2 3 8
# 3 4 5
# 4 111 6
# 5 6 7
# 6 50 8
# 7 3 9
# 8 3 0
# 9 4 3
# 10 111 4
# 11 3 5
# 12 2 6
# 13 4 7
# 14 111 2
# 15 23 4
# 16 2 5
# 17 111 6
# 18 3 4
替换多列同行的多个值:
df.replace(to_replace=[5,6],value=[22,33])
# 结果:
# A B
# 0 1 2
# 1 2 3
# 2 3 8
# 3 4 22
# 4 22 33
# 5 33 7
# 6 50 8
# 7 3 9
# 8 3 0
# 9 4 3
# 10 22 4
# 11 3 22
# 12 2 33
# 13 4 7
# 14 22 2
# 15 23 4
# 16 2 22
# 17 22 33
# 18 3 4
转换数据类型
在清洗数据时,可能会遇到更改数据类型的情况,为例解决该问题,Pandas 中提供了用于转换数据类型的 astype() 方法和 to_numeric() 函数。
astype(dtype ,copy = True ,errors = 'raise' ,**kwargs)- dtype:表示数据的类型
- copy:是否返回新的对象(默认为 True)
- errors:异常采取的处理方式
- raise:表示允许引发异常(默认值)
- ignore:表示抑制异常
df = pd.DataFrame({'A':['1','1.2','4.2'],'B':['-9','70','88'],'C':['x','5.0','0']})
df.dtypes
# 结果:
# A object
# B object
# C object
# dtype: object
df['B'].astype(dtype='int')
# 结果:
# 0 -9
# 1 70
# 2 88
# Name: B, dtype: int64
to_numeric(arg ,errors = 'raise' ,downcast = None)- arg:表示要转换的数据,可以是列表、一维数组、Series 等
- errors:表示异常采取的处理方式
- ignore:表示无效解析时会忽略异常
- raise:表示无效解析时会引发异常(默认值)
- coerce:表示无效解析时会将数值设置为 NaN
- downcast:用于指定最终要转换的类型,该参数的取值可以是 interger、signed、unsigned、float、None
ser = pd.Series(['1.5','2.2','3.8'])
# 将 object 类型转换为 float 类型
pd.to_numeric(ser)
# 结果:
# 0 1.5
# 1 2.2
# 2 3.8
# dtype: float64
如果目标对象中包含某个字符串并进行转换时会报错,这时候就需要给 to_numeric() 函数中的 errors 参数传入 ignore 值。
ser = pd.Series(['1.5','2.2','problem'])
# 将 object 类型转换为 float 类型
pd.to_numeric(ser ,errors = 'ignore')
# 结果:
# 0 1.5
# 1 2.2
# 2 problem
# dtype: float64
数据合并
在进行数据分析前,数据往往来源于不同的地方,有的来自文件,有的来自数据库,这些数据被读取之后需要进行合并,方便用户统一进行相关的操作。Pandas 中提供了几种数据合并的方式,分别是
堆叠合并
堆叠合并指的是沿着某个轴的方向将两个及两个以上的对象按照一定的逻辑关系进行合并。
concat(objs ,axis = 0 ,join = 'outer' ,ignore_index = False ,keys = None ,levels = None ,names = None ,verify_integrity = False ,sort = False ,copy = True)- objs:表示要合并的多个对象(包含 Series 或 DataFrame 对象的序列或字典)
- axis:表示堆叠的方向(取值可以是 0(默认值,表纵向) 或 index 和 1(表横向) 或 columns)
- join:表连接方式
- inner:内连接,即取所有对象共有的行索引或列索引(交集部分),没有数据的位置填充为 NaN
- outer:外连接(默认),即取所有对象全部的行索引或列索引(并集部分),没有数据的位置填充为 NaN
- ignore_index:是否忽略索引(默认为 False)
- True:会清除现有索引并重置索引
- 外连接:保证两表数据不会丢失
- 内连接:两表数据可能会丢失
df1 = pd.DataFrame({'A':['A0','A1','A2'],'B':['B0','B1','B2'],'C':['C0','C1','C2']})
df2 = pd.DataFrame({'C':['C0','C1','C2'],'D':['D0','D1','D2']})
pd.concat([df1,df2],join='outer',axis=1)
# 结果:
# A B C C D
# 0 A0 B0 C0 C0 D0
# 1 A1 B1 C1 C1 D1
# 2 A2 B2 C2 C2 D2
df1 = pd.DataFrame({'A':['A0','A1','A2'],'B':['B0','B1','B2'],'C':['C0','C1','C2']})
df2 = pd.DataFrame({'C':['C0','C1','C2'],'D':['D0','D1','D2']})
pd.concat([df1,df2],join='inner',axis=1)
# 结果:
# A B C C D
# 0 A0 B0 C0 C0 D0
# 1 A1 B1 C1 C1 D1
# 2 A2 B2 C2 C2 D2
df1 = pd.DataFrame({'A':['A0','A1','A2'],'B':['B0','B1','B2'],'C':['C0','C1','C2']})
df2 = pd.DataFrame({'C':['C0','C1','C2'],'D':['D0','D1','D2']})
pd.concat([df1,df2],join='outer',axis=0)
# 结果:
# A B C D
# 0 A0 B0 C0 NaN
# 1 A1 B1 C1 NaN
# 2 A2 B2 C2 NaN
# 0 NaN NaN C0 D0
# 1 NaN NaN C1 D1
# 2 NaN NaN C2 D2
df1 = pd.DataFrame({'A':['A0','A1','A2'],'B':['B0','B1','B2'],'C':['C0','C1','C2']})
df2 = pd.DataFrame({'C':['C0','C1','C2'],'D':['D0','D1','D2']})
pd.concat([df1,df2],join='inner',axis=0)
# 结果:
# C
# 0 C0
# 1 C1
# 2 C2
# 0 C0
# 1 C1
# 2 C2
主键合并
主键合并类似于关系型数据库的主键查询操作,它指的是根据一个或多个键将两个对象进行合并,大多数情况下会将这两个对象中共有的列作为合并的键。
merge(left ,right ,how = 'inner' ,on = None ,left_on = None ,right_on = None .left_index = False ,right_index = False ,sort = False ,suffixes = ('_x' ,'_y') ,copy = True ,indicator = False ,validate = None)- left:参与合并的 DateFrame 类的对象
- right:参与合并的 DatFrame / Series 对象(Series 对象必须有名称)
- how:合并的方式
- inner:交集合并,类似于数据库的内连接操作(默认值)
- outer:并集合并,类似于数据库的全外连接操作
- left:基于 left 的主键合并
- right:基于 right 的主键合并
- cross:基于 left 与 right 的笛卡尔积合并
- on:合并的键,可以是列索引或包含列索引的列表(列索引必须存在于两表中)
- suffixes:表示重名的列添加的后缀(默认值:(‘_x’ ,’_y’))
- left_index:是否使用 left 的索引进行合并(默认值为 False)
- right_index:是否使用 right 的索引进行合并(默认值为 False)
df1 = pd.DataFrame({'key':['K0','K2','K3'],'A':['A0','A1','A2'],'B':['B0','B1','B2'],'C':['C0','C1','C2']})
df2 = pd.DataFrame({'key':['K0','K1','K2'],'C':['C0','C1','C2'],'D':['D0','D1','D2']})
pd.merge(df1,df2,on='key')
# 结果:
# key A B C_x C_y D
# 0 K0 A0 B0 C0 C0 D0
# 1 K2 A1 B1 C1 C2 D2
df1 = pd.DataFrame({'key':['K0','K2','K3'],'A':['A0','A1','A2'],'B':['B0','B1','B2'],'C':['C0','C1','C2']})
df2 = pd.DataFrame({'key':['K0','K1','K2'],'C':['C0','C1','C2'],'D':['D0','D1','D2']})
pd.merge(df1,df2,on=['key','C'])
# 结果:
# key A B C D
# 0 K0 A0 B0 C0 D0
df1 = pd.DataFrame({'key':['K0','K1','K2'],'A':['A0','A1','A2'],'B':['B0','B1','B2'],'C':['C0','C1','C2']})
df2 = pd.DataFrame({'key':['K0','K1','K2','K3','K4'],'C':['C0','C1','C2','C3','C4'],'D':['D0','D1','D2','D3','D4']})
pd.merge(df1,df2,on='key',how='outer')
# 结果:
# key A B C_x C_y D
# 0 K0 A0 B0 C0 C0 D0
# 1 K1 A1 B1 C1 C1 D1
# 2 K2 A2 B2 C2 C2 D2
# 3 K3 NaN NaN NaN C3 D3
# 4 K4 NaN NaN NaN C4 D4
df1 = pd.DataFrame({'key':['K0','K1','K2'],'A':['A0','A1','A2'],'B':['B0','B1','B2'],'C':['C0','C1','C2']})
df2 = pd.DataFrame({'key':['K0','K1','K2','K3','K4'],'C':['C0','C1','C2','C3','C4'],'D':['D0','D1','D2','D3','D4']})
pd.merge(df1,df2,on='key',how='left')
# 结果:
# key A B C_x C_y D
# 0 K0 A0 B0 C0 C0 D0
# 1 K1 A1 B1 C1 C1 D1
# 2 K2 A2 B2 C2 C2 D2
df1 = pd.DataFrame({'key':['K0','K1','K2'],'A':['A0','A1','A2'],'B':['B0','B1','B2'],'C':['C0','C1','C2']})
df2 = pd.DataFrame({'key':['K0','K1','K2','K3','K4'],'C':['C0','C1','C2','C3','C4'],'D':['D0','D1','D2','D3','D4']})
pd.merge(df1,df2,on='key',how='left')
# 结果:
# key A B C_x C_y D
# 0 K0 A0 B0 C0 C0 D0
# 1 K1 A1 B1 C1 C1 D1
# 2 K2 A2 B2 C2 C2 D2
# 3 K3 NaN NaN NaN C3 D3
# 4 K4 NaN NaN NaN C4 D4
df1 = pd.DataFrame({'key':['K0','K1','K2'],'A':['A0','A1','A2'],'B':['B0','B1','B2'],'C':['C0','C1','C2']})
df2 = pd.DataFrame({'key':['K0','K1','K2','K3','K4'],'C':['C0','C1','C2','C3','C4'],'D':['D0','D1','D2','D3','D4']},index=['a','b','c','d','e'])
pd.merge(df1,df2,how='outer',left_index=True,right_index=True)
# 结果:
# key_x A B C_x key_y C_y D
# 0 K0 A0 B0 C0 NaN NaN NaN
# 1 K1 A1 B1 C1 NaN NaN NaN
# 2 K2 A2 B2 C2 NaN NaN NaN
# a NaN NaN NaN NaN K0 C0 D0
# b NaN NaN NaN NaN K1 C1 D1
# c NaN NaN NaN NaN K2 C2 D2
# d NaN NaN NaN NaN K3 C3 D3
# e NaN NaN NaN NaN K4 C4 D4
根据索引合并
根据索引合并指的是根据行索引或列索引将多个对象合并成一个对象。Pandas 的 DateFrame 类中提供了一个用于根据索引合并多个对象的 join() 方法,该方法通常会根据列索引来合并多个对象,
join(other ,on = None ,how = 'left' ,lsuffix = '' ,rsuffix = '' ,sort = False)- other:表示要合并的对象,包含 DataFrame、Series (Series 类的对象必须有名称(作为合并后的列名))类对象或者包含DataFrame 类对象的列表
- on:表示合并的列索引
- how:表示合并的方式
- inner:交集合并,类似于数据库的内连接操作
- outer:并集合并,类似于数据库的全外连接操作
- left:使用左连接的方式合并多个对象,即以 join() 方法的对象为基准,保留该对象的全部数据,若其他对象有与该对象重叠的索引,就保留其他对象中这些重叠索引对应的数据,否则就舍弃数据(默认值)
- right:基于 right 的主键合并
- lsuffix:表示左侧对象有重名的列时,给该列的名称添加的后缀名
- rsuffix:表示右侧对象有重名的列时,给该列的名称添加的后缀名
df1 = pd.DataFrame({'key':['K0','K1','K2'],'A':['A0','A1','A2'],'B':['B0','B1','B2'],'C':['C0','C1','C2']})
df2 = pd.DataFrame({'E':['K0','K1','K2','K3','K4'],'F':['C0','C1','C2','C3','C4'],'D':['D0','D1','D2','D3','D4']},index=['a','b','c','d','e'])
df1.join(df2)
# 结果:
# key A B C E F D
# 0 K0 A0 B0 C0 NaN NaN NaN
# 1 K1 A1 B1 C1 NaN NaN NaN
# 2 K2 A2 B2 C2 NaN NaN NaN
df1 = pd.DataFrame({'key':['K0','K1','K2'],'A':['A0','A1','A2'],'B':['B0','B1','B2'],'C':['C0','C1','C2']})
df2 = pd.DataFrame({'E':['K0','K1','K2','K3','K4'],'F':['C0','C1','C2','C3','C4'],'D':['D0','D1','D2','D3','D4']},index=['a','b','c','d','e'])
df1.join(df2 ,how='right')
# 结果:
# key A B C E F D
# a NaN NaN NaN NaN K0 C0 D0
# b NaN NaN NaN NaN K1 C1 D1
# c NaN NaN NaN NaN K2 C2 D2
# d NaN NaN NaN NaN K3 C3 D3
# e NaN NaN NaN NaN K4 C4 D4
df1 = pd.DataFrame({'key':['K0','K1','K2'],'A':['A0','A1','A2'],'B':['B0','B1','B2'],'C':['C0','C1','C2']})
df2 = pd.DataFrame({'E':['K0','K1','K2','K3','K4'],'F':['C0','C1','C2','C3','C4'],'D':['D0','D1','D2','D3','D4']},index=['a','b','c','d','e'])
df1.join(df2 ,how='right')
# 结果:
# key A B C E F D
# 0 K0 A0 B0 C0 NaN NaN NaN
# 1 K1 A1 B1 C1 NaN NaN NaN
# 2 K2 A2 B2 C2 NaN NaN NaN
# a NaN NaN NaN NaN K0 C0 D0
# b NaN NaN NaN NaN K1 C1 D1
# c NaN NaN NaN NaN K2 C2 D2
# d NaN NaN NaN NaN K3 C3 D3
# e NaN NaN NaN NaN K4 C4 D4
合并重叠数据
在处理数据时,如果一个 DataFrame 类的对象有缺失的数据,而这些缺失的数据我们希望可以使用其他的 DataFrame 类对象的数据进行填充,这些可以通过 combine_first() 方法实现这个效果。
combine_first(other)- other:该参数表示用于填充缺失值的 DataFrame 类的对象
df1 = pd.DataFrame({'A':['A0','A1','A2'],'B':['B0',np.nan,'B2'],'C':['C0','C1','C2']})
df2 = pd.DataFrame({'A':['K0','K1','K2'],'B':['C0','C1','C2']})
df1.combine_first(df2)
# 结果:
# A B C
# 0 A0 B0 C0
# 1 A1 C1 C1
# 2 A2 B2 C2
数据重塑
重塑分层索引
Pandas 中实现重塑分层索引功能有 stack() 方法和 unstack() 方法,其中 stack() 方法用于将数据的列索引旋转为行索引,unstack() 相反。
stack(level = -1 ,dropna = True)- level:表示操作内层索引,若设为 0 ,表示操作外层索引
- dropna:表示是否将旋转后产生的缺失值删除
- True:表示自动过滤缺失值
- False:相反
df1 = pd.DataFrame({'A':['A0','A1','A2'],'B':['B0',np.nan,'B2'],'C':['C0','C1','C2']})
# 结果:
A B C
0 A0 B0 C0
1 A1 NaN C1
2 A2 B2 C2
df1.stack()
# 结果:
# 0 A A0
# B B0
# C C0
# 1 A A1
# C C1
# 2 A A2
# B B2
# C C2
# dtype: object
unstack(level = -1 ,fill_value = None)- level:表示操作内层索引,若设为 0 ,表示操作外层索引
- fill_value:用于指定在产生缺失值时要替换的值
df1 = pd.DataFrame({'A':['A0','A1','A2'],'B':['B0',np.nan,'B2'],'C':['C0','C1','C2']})
# 结果:
A B C
0 A0 B0 C0
1 A1 NaN C1
2 A2 B2 C2
df1.unstack()
# 结果:
# A 0 A0
# 1 A1
# 2 A2
# B 0 B0
# 1 NaN
# 2 B2
# C 0 C0
# 1 C1
# 2 C2
# dtype: object
轴向旋转
Pandas 中提供了 pivot() 方法实现了轴向旋转的功能,它会根据给定的行索引或列索引重新组织一个 DataFrame 类的对象。
pivot(index = None ,columns = None ,values = None)- index:用于创建新对象的行索引。如果未设置,则使用原对象的行索引
- columns:用于创建新对象的列索引。如果未设置,则使用原对象的列索引
- values:用于填充新对象中的值
df = pd.DataFrame({'商品名称':['A1','A2','A3','A1','A2','A3'],
'出售日期':['2023年5月25日','2023年5月25日','2023年5月25日','2023年6月18日','2023年6月18日','2023年6月18日'],
'价格':[999,1399,888,777,666,555]})
df.pivot(index='出售日期',columns='商品名称',values='价格')
# 结果:
# 商品名称 A1 A2 A3
# 出售日期
# 2023年5月25日 999 1399 888
# 2023年6月18日 777 666 555
数据转换
面元划分
面元划分是指连续数据被离散化处理,按一定的映射关系划分为相应的面元,这里的面元可以理解为区间。Pandas 中使用 cut() 函数能够实现面元划分操作,其函数会采用等宽法对连续型数据进行离散化处理。
cut(x ,bins ,right = True ,labels = None ,retbins = False ,precision = 3 ,include_lowest = False ,duplicaates = 'raise' ,ordered = True)- x:表示面元划分的连续数据,取值可以是一维数组或 Series 类对象
- bins:表示划分面元的依据
- 若为 int 类型的值,则代表面元的数目
- 若为 list、tuple、array 类型的值,则代表划分区间(每两个值的间隔为一个区间)
- right:表示右端点是否为闭区间(默认为 True)
- labels:表示划分的个区间的标签
- retbins:表示是否返回每个区间的边缘值(默认为 False)
- precision:用于确定每隔区间边缘值的精度(默认为 3)
- include_lowest:表示是否包含区间的左端点(默认为 False)
ser = pd.Series([19,27,38,44,57,62,50,35,31,44,85,93,72,44,53,23,52,65,73])
bins = [0,50,100]
pd.cut(ser,bins)
# 结果:
# 0 (0, 50]
# 1 (0, 50]
# 2 (0, 50]
# 3 (0, 50]
# 4 (50, 100]
# 5 (50, 100]
# 6 (0, 50]
# 7 (0, 50]
# 8 (0, 50]
# 9 (0, 50]
# 10 (50, 100]
# 11 (50, 100]
# 12 (50, 100]
# 13 (0, 50]
# 14 (50, 100]
# 15 (0, 50]
# 16 (50, 100]
# 17 (50, 100]
# 18 (50, 100]
# dtype: category
# Categories (2, interval[int64, right]): [(0, 50] < (50, 100]]
等宽法:每一段一样长
等频法:每一段个数相同
哑变量处理
在数据分析中,一些算法模型要求输入以数值类型表示的特征,但是代表特征的数据不一定都是数值类型的,其中一部分是类别型的。哑变量又称虚拟变量、名义变量等,他是人为虚设的变量,用来反映某个变量的不同类别,
Pandas 中使用 get_dummies() 函数对类别数据进行哑变量的处理,在处理后返回一个哑变量矩阵。
get_dummies(data ,prefix = None ,prefix_sep = '_' ,dummy_na = False ,columns = None ,sparse = False ,drop_first = False ,dtype = None)- data:表示要处理的类别数据,可以是数组、DataFrame 或 Series 类的对象
- prefix:表示列索引的前缀(默认为 None)
- prefix_sep:用于附加前缀作为分隔符使用(默认 _)
- dummy_na:表示是否为 NaN 值添加一列(默认为 False)
- columns:表示 DataFrame 要编码的列名(默认为 None)
- sparse:表示虚拟列是否是稀疏的(默认为 False)
- drop_list:是否通过从 k 个分类级别中删除第一个级来获得 k – 1 个分类级别(默认为 False)
df = pd.DataFrame({'职业':['工人','学生','司机','教师','导游']})
# 哑变量处理
pd.get_dummies(df,prefix=['col_'])
# 结果:
# col__司机 col__学生 col__导游 col__工人 col__教师
# 0 False False False True False
# 1 False True False False False
# 2 True False False False False
# 3 False False False False True
# 4 False False True False False
![[学习笔记 Day07]数据分析与应用:数据预处理-资源刺客](http://images.kodo.cdn.itdka.cn/wp-content/uploads/2025/09/20250923154612655.png)

![[学习笔记 Day01]C++基础:简单的程序设计,始于梦想的开始!-资源刺客](http://images.kodo.cdn.itdka.cn/wp-content/uploads/2025/09/20250922171813209.webp)
![[学习笔记 Day08]数据分析与应用:数据聚合与分组运算-资源刺客](https://images.kodo.cdn.itdka.cn/wp-content/uploads/2025/09/20250923154612655.png)
![[学习笔记 Day02]Vue基础:前端造梦,继续干!-资源刺客](http://images.kodo.cdn.itdka.cn/wp-content/uploads/2025/09/20250919193418264.jpeg)

![[学习笔记 Day03]Redis 基础:Redis 设计的优化建议与最佳实践-资源刺客](https://images.kodo.cdn.itdka.cn/wp-contents/uploads/2026/05/20260521215425110-科技感ENVI安装教程封面-8.png)
![[学习笔记 Day02]Redis + OpenResty + Lua 实现多级缓存-资源刺客](https://images.kodo.cdn.itdka.cn/wp-contents/uploads/2026/05/20260521202850344-科技感ENVI安装教程封面-7.png)
![[学习笔记 Day 01] Redis 基础:从入门到缓存、主从、分片集群的深入-资源刺客](https://images.kodo.cdn.itdka.cn/wp-contents/uploads/2026/05/20260520211903179-科技感ENVI安装教程封面-6.png)
![[Windows + Redis]Windows 部署安装 Redis 软件附注册 Windows 服务!-资源刺客](https://images.kodo.cdn.itdka.cn/wp-contents/uploads/2026/05/20260518221407144-科技感ENVI安装教程封面-5.png)
![[.NET Core + AOP + Attribute]实现横切面对象方法的额外操作,简化开发,提高效率!-资源刺客](https://images.kodo.cdn.itdka.cn/wp-contents/uploads/2026/05/20260510223906175-科技感ENVI安装教程封面-3.png)

![[自动化 + 手残党专属]宝塔安装AllinSSL证书管理教程-资源刺客](http://images.kodo.cdn.itdka.cn/wp-content/uploads/2025/11/20251112122722716.png)




暂无评论内容