关于Pandas版本: 本文基于 pandas2.2.0 编写。
关于本文内容更新: 随着pandas的stable版本更迭,本文持续更新,不断完善补充。
本节目录
- Pandas.DataFrame.reindex_like()
- 语法:
- 返回值:
- 参数说明:
- other 指定另一个 DataFrame 对象(仿制索引的目标)
- method 缺失值的填充方法
- copy 是否创建原始数据副本
- limit 最大连续填充次数
- tolerance 最大容差距离
- 相关方法:
- 示例:
Pandas.DataFrame.reindex_like()
用另一个 DataFrame
的索引(index)、列名,替换当前DataFrame
的索引和列名。
- 默认状态下
copy=True
,这意味着将创建新的DataFrame
对象,无论新索引、列名和原始数据的索引、列名是否相同。 - 索引仿制后,如果新索引、新列名,对于原始
DataFrame
产生异同,对应位置的数据将会被填充为缺失值(Nan)。 - 新索引、新列名的数据类型,必须和原始索引、原始列名的数据类型相同。否则数据将全是NaN。例如数字1 和字符串
1
并不相同。 例
这个方法的目的是将一个 DataFrame
对象的索引调整为另一个 DataFrame
对象的索引,以便它们具有相同的索引结构。
语法:
DataFrame.reindex_like(other, method=None, copy=None, limit=None, tolerance=None)
返回值:
- Series or DataFrame
与调用者相同类型的对象,但在每个轴上具有更改的索引。
参数说明:
other 指定另一个 DataFrame 对象(仿制索引的目标)
- other : Object of the same data type
指定另一个具有相同数据类型(索引、列名)的DataFrame
对象。
method 缺失值的填充方法
- method:{None, ‘backfill’/’bfill’, ‘pad’/’ffill’, ‘nearest’}
如果仿制索引后,DataFrame
产生了缺失值,可以根据需要使用method
参数进行填充: 例
- ‘pad’ 或 ’ffill’ : 使用缺失值 前一个有效值 填充缺失值;
- ‘backfill’ 或 ’bfill’ : 使用缺失值 后一个有效值 填充缺失值;
- ‘nearest’ : 使用缺失值 最近的 填充缺失值;
⚠️ 注意 :
method
参数仅适用于单调递增/递减 的 新索引/列名
copy 是否创建原始数据副本
- copy:bool, default True
默认情况下,copy=True
这意味着仿制索引后的DataFrame
是一个全新的对象,对其进行的数据修改,不会作用于原始数据。例
若指定copy=False
将根据新索引和原始索引是否相同,产生如下结果:
- 新索引和原始索引相同:视图模式,新
DataFrame
对象的数据修改,会作用于原始DataFrame
。例 - 新索引和原始索引不同:拷贝模式,自动创建一个全新的对象,新
DataFrame
对象的数据修改,不会作用于原始DataFrame
。例
⚠️ 注意 :
copy
参数将改变pandas 3.0
中的行为。默认情况下会启用Copy-on-Write
,这意味着所有带有copy
参数的方法都将使用惰性复制机制来推迟复制并忽略copy
参数。copy
参数将在pandas
的未来版本中删除。您已经可以通过启用写入时复制pd.options.mode.copy_on_write = True
来获得未来的行为和改进。
limit 最大连续填充次数
- limit : int, default None
当需要填充缺失值,limit
参数控制最大连续填充次数。默认为不限制,可以用整数指定最大次数。例
⚠️ 注意 :
limit
需要和method
参数配合使用。
tolerance 最大容差距离
- tolerance:optional
最大容差距离:例当新索引和原始索引不一致,会产生缺失值。如果希望通过method
参数进行插值,会进行【最近有效值】的判定。默认状况下,这个距离是不受限制的。
如果,你希望【最近有效值】有距离限制,可以使用tolerance
参数指定一个最大容差距离。最大容差距离有以下注意事项:
- 【最近有效值】 应符合公式
abs(index[indexer] - target) <= tolerance
简单理解为:缺失值对应的新索引的索引值 减 最近目标值对应的新索引的索引值 小于等于 最大容差距离 即可判定为这个值是有效值 - 最大容差距离是一个标量值,它对所有值应用相同的tolerance;
- 也可以是
list-like
的值,它对每个元素应用可变的tolerance。 - 并且必须与索引相同大小,其 dtype 必须与索引的类型完全匹配。
⚠️ 注意 :
tolerance
参数 只能和method
参数 同时使用。否则会引发ValueError
示例:
测试文件下载:
本文所涉及的测试文件,如有需要,可在文章顶部的绑定资源处下载。
若发现文件无法下载,应该是资源包有内容更新,正在审核,请稍后再试。或站内私信作者索要。
示例:新索引和原始索引的数据类型必须相同,会产生数据全是缺失值(NaN)的问题
import pandas as pd
# df1
index1 = [1, 2, 3]
data1 = {111:['a1', 'a2', 'a3'], 222:['b1', 'b2', 'b3']}
df1 = pd.DataFrame(data=data1, index=index1)
# df2
index2 = ['1', '2', '3']
data2 = {'111':['a1', 'a2', 'a3'], '222':['b1', 'b2', 'b3']}
df2 = pd.DataFrame(data=data2, index=index2)
# df3 = 仿制索引后的df1
df3 = df1.reindex_like(df2)
# 观察原始数据
print(f"以下为运行结果:\n{'*' * 50}\n原始数据:\n{df1}\n原始数据索引和列名的数据类型:\n{df1.axes}\n\n用来提取索引和列名的df2:\n{df2}\ndf2索引和列名的数据类型:\n{df2.axes}\n\n原始数据仿制索引后的df3:\n{df3}\n原始数据仿制索引后的索引、列名数据类型:\n{df3.axes}\n{'*' * 50}")
以下为运行结果:
**************************************************
原始数据:
111 222
1 a1 b1
2 a2 b2
3 a3 b3
原始数据索引和列名的数据类型:
[Index([1, 2, 3], dtype='int64'), Index([111, 222], dtype='int64')]
用来提取索引和列名的df2:
111 222
1 a1 b1
2 a2 b2
3 a3 b3
df2索引和列名的数据类型:
[Index(['1', '2', '3'], dtype='object'), Index(['111', '222'], dtype='object')]
原始数据仿制索引后的df3:
111 222
1 NaN NaN
2 NaN NaN
3 NaN NaN
原始数据仿制索引后的索引、列名数据类型:
[Index(['1', '2', '3'], dtype='object'), Index(['111', '222'], dtype='object')]
**************************************************
由上结果可见,由于数据类型的不同,即使新索引、新列名的值和原始索引、原始列名的值 看起来一样,但实际上并不相同。所有数据都被填充为缺失值(NaN)
示例:填充缺失值,仅使用 ffill
演示,其他的填充方法请自行测试
import pandas as pd
# df1
index1 = [1, 2, 3]
data1 = {111:['a1', 'a2', 'a3'], 222:['b1', 'b2', 'b3']}
df1 = pd.DataFrame(data=data1, index=index1)
# df2
index2 = [1, 4, 5]
data2 = {111:['a1', 'a2', 'a3'], 222:['b1', 'b2', 'b3']}
df2 = pd.DataFrame(data=data2, index=index2)
# df3 = 仿制索引后的df1
df3 = df1.reindex_like(df2, method='ffill')
df3
111 | 222 | |
1 | a1 | b1 |
4 | a3 | b3 |
5 | a3 | b3 |
由上面结果可以发现,索引 4 因为无法在原始数据中找到有效数据,使用 method=‘ffill’ 从原始数据中的 第3 行取数据进行了填充。
示例:默认状态下 copy=True
,仿制索引后的新对象的数据修改,不会作用于原始数据
import pandas as pd
# df1
index1 = [1, 2, 3]
data1 = {111:['a1', 'a2', 'a3'], 222:['b1', 'b2', 'b3']}
df1 = pd.DataFrame(data=data1, index=index1)
# df2
index2 = [1, 4, 5]
data2 = {111:['a1', 'a2', 'a3'], 222:['b1', 'b2', 'b3']}
df2 = pd.DataFrame(data=data2, index=index2)
# df3 = 仿制索引后的df1
df3 = df1.reindex_like(df2)
# 修改df3的数据
df3.iloc[0,0] = 8888
# 观察原始数据
df1
111 | 222 | |
1 | a1 | b1 |
2 | a2 | b2 |
3 | a3 | b3 |
示例:若指定 copy=False
,新索引、列名和原始索引、列名 相同,则使用视图模式,重置索引后的DataFrame的 数据修改会作用于原始数据
import pandas as pd
# df1
index1 = [1, 2, 3]
data1 = {111:['a1', 'a2', 'a3'], 222:['b1', 'b2', 'b3']}
df1 = pd.DataFrame(data=data1, index=index1)
# df2
index2 = [1, 2, 3]
data2 = {111:['a1', 'a2', 'a3'], 222:['b1', 'b2', 'b3']}
df2 = pd.DataFrame(data=data2, index=index2)
# df3 = 仿制索引后的df1
df3 = df1.reindex_like(df2, copy=False)
# 修改df3的数据
df3.iloc[0,0] = 8888
# 观察原始数据
df1
111 | 222 | |
1 | 8888 | b1 |
2 | a2 | b2 |
3 | a3 | b3 |
示例:若指定 copy=False
,新索引、列名和原始索引、列名 不同,则使用拷贝模式,重置索引后的DataFrame的 数据修改不会作用于原始数据
import pandas as pd
# df1
index1 = [1, 2, 3]
data1 = {111:['a1', 'a2', 'a3'], 222:['b1', 'b2', 'b3']}
df1 = pd.DataFrame(data=data1, index=index1)
# df2
index2 = [1, 4, 6]
data2 = {111:['a1', 'a2', 'a3'], 222:['b1', 'b2', 'b3']}
df2 = pd.DataFrame(data=data2, index=index2)
# df3 = 仿制索引后的df1
df3 = df1.reindex_like(df2, copy=False)
# 修改df3的数据
df3.iloc[0,0] = 8888
# 观察原始数据
df1
111 | 222 | |
1 | a1 | b1 |
2 | a2 | b2 |
3 | a3 | b3 |
示例:控制缺失值填充的最大连续填充数
import pandas as pd
# df1
index1 = [1, 2, 3]
data1 = {111:['a1', 'a2', 'a3'], 222:['b1', 'b2', 'b3']}
df1 = pd.DataFrame(data=data1, index=index1)
# df2
index2 = [1, 4, 6]
data2 = {111:['a1', 'a2', 'a3'], 222:['b1', 'b2', 'b3']}
df2 = pd.DataFrame(data=data2, index=index2)
# df3 = 仿制索引后的df1
df3 = df1.reindex_like(df2, method='ffill', limit=1)
df3
111 | 222 | |
1 | a1 | b1 |
4 | a3 | b3 |
6 | NaN | NaN |
由上面结果可以发现,当最大连续填充数 limit=1
只在新索引的 4 的位置填充了,后面的一个虽然紧挨着上面的行,但是并没有被填充。
示例:当新索引和原始索引无法完全匹配,可以使用 tolerance
参数控制容差
- 1、默认状态下,新索引和原始索引如果无法完全匹配,会产生缺失值,在使用
method
插值时,是不会关注新老索引距离问题的。
# df1
index1 = [1, 2, 3]
data1 = {111:['a1', 'a2', 'a3'], 222:['b1', 'b2', 'b3']}
df1 = pd.DataFrame(data=data1, index=index1)
# df2
index2 = [6, 7, 8]
data2 = {111:['a1', 'a2', 'a3'], 222:['b1', 'b2', 'b3']}
df2 = pd.DataFrame(data=data2, index=index2)
# df3 = 仿制索引后的df1
df3 = df1.reindex_like(df2, method='ffill')
df3
111 | 222 | |
6 | a3 | b3 |
7 | a3 | b3 |
8 | a3 | b3 |
- 2、如果,使用
tolerance
限制容差距离,只有当 <=4 ,才会被视为最近有效数值。插值方可生效。
# df1
index1 = [1, 2, 3]
data1 = {111:['a1', 'a2', 'a3'], 222:['b1', 'b2', 'b3']}
df1 = pd.DataFrame(data=data1, index=index1)
# df2
index2 = [6, 7, 8]
data2 = {111:['a1', 'a2', 'a3'], 222:['b1', 'b2', 'b3']}
df2 = pd.DataFrame(data=data2, index=index2)
# df3 = 仿制索引后的df1
df3 = df1.reindex_like(df2, method='ffill', tolerance=4)
df3
111 | 222 | |
6 | a3 | b3 |
7 | a3 | b3 |
8 | NaN | NaN |
由上述结果可见,因为 8-3 >4 所以新索引8的位置,并没有被填充。
8-3 >4:
8是新索引缺失值对应的索引值
3是老索引中最近的有效值