重新索引以与另一个对象对齐
你可能希望取一个对象并重新索引其轴,使其标签与另一个对象相同。虽然这个操作的语法虽然冗长但简单,但它是一个常见的操作,因此reindex_like()
方法可用于简化此操作:
In [213]: df2 = df.reindex(["a", "b", "c"], columns=["one", "two"]) In [214]: df3 = df2 - df2.mean() In [215]: df2 Out[215]: one two a 1.394981 1.772517 b 0.343054 1.912123 c 0.695246 1.478369 In [216]: df3 Out[216]: one two a 0.583888 0.051514 b -0.468040 0.191120 c -0.115848 -0.242634 In [217]: df.reindex_like(df2) Out[217]: one two a 1.394981 1.772517 b 0.343054 1.912123 c 0.695246 1.478369 ```### 使用`align`将对象与其他对象对齐 `align()` 方法是同时对齐两个对象的最快方法。它支持一个`join`参数(与连接和合并相关): > + `join='outer'`:取索引的并集(默认) > + > + `join='left'`:使用调用对象的索引 > + > + `join='right'`:使用传入对象的索引 > + > + `join='inner'`:交集索引 返回一个包含重新索引的两个 Series 的元组: ```py In [218]: s = pd.Series(np.random.randn(5), index=["a", "b", "c", "d", "e"]) In [219]: s1 = s[:4] In [220]: s2 = s[1:] In [221]: s1.align(s2) Out[221]: (a -0.186646 b -1.692424 c -0.303893 d -1.425662 e NaN dtype: float64, a NaN b -1.692424 c -0.303893 d -1.425662 e 1.114285 dtype: float64) In [222]: s1.align(s2, join="inner") Out[222]: (b -1.692424 c -0.303893 d -1.425662 dtype: float64, b -1.692424 c -0.303893 d -1.425662 dtype: float64) In [223]: s1.align(s2, join="left") Out[223]: (a -0.186646 b -1.692424 c -0.303893 d -1.425662 dtype: float64, a NaN b -1.692424 c -0.303893 d -1.425662 dtype: float64)
对于 DataFrames,默认情况下,连接方法将应用于索引和列:
In [224]: df.align(df2, join="inner") Out[224]: ( one two a 1.394981 1.772517 b 0.343054 1.912123 c 0.695246 1.478369, one two a 1.394981 1.772517 b 0.343054 1.912123 c 0.695246 1.478369)
你还可以传递一个axis
选项,只在指定的轴上对齐:
In [225]: df.align(df2, join="inner", axis=0) Out[225]: ( one two three a 1.394981 1.772517 NaN b 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435, one two a 1.394981 1.772517 b 0.343054 1.912123 c 0.695246 1.478369)
如果你将一个 Series 传递给DataFrame.align()
,你可以选择使用axis
参数在 DataFrame 的索引或列上同时对齐两个对象:
In [226]: df.align(df2.iloc[0], axis=1) Out[226]: ( one three two a 1.394981 NaN 1.772517 b 0.343054 -0.050390 1.912123 c 0.695246 1.227435 1.478369 d NaN -0.613172 0.279344, one 1.394981 three NaN two 1.772517 Name: a, dtype: float64) ```### 重新索引时填充 `reindex()` 接受一个可选参数`method`,该参数是从以下表中选择的填充方法: | 方法 | 动作 | | --- | --- | | pad / ffill | 向前填充值 | | bfill / backfill | 向后填充值 | | nearest | 从最近的索引值填充 | 我们在一个简单的 Series 上演示这些填充方法: ```py In [227]: rng = pd.date_range("1/3/2000", periods=8) In [228]: ts = pd.Series(np.random.randn(8), index=rng) In [229]: ts2 = ts.iloc[[0, 3, 6]] In [230]: ts Out[230]: 2000-01-03 0.183051 2000-01-04 0.400528 2000-01-05 -0.015083 2000-01-06 2.395489 2000-01-07 1.414806 2000-01-08 0.118428 2000-01-09 0.733639 2000-01-10 -0.936077 Freq: D, dtype: float64 In [231]: ts2 Out[231]: 2000-01-03 0.183051 2000-01-06 2.395489 2000-01-09 0.733639 Freq: 3D, dtype: float64 In [232]: ts2.reindex(ts.index) Out[232]: 2000-01-03 0.183051 2000-01-04 NaN 2000-01-05 NaN 2000-01-06 2.395489 2000-01-07 NaN 2000-01-08 NaN 2000-01-09 0.733639 2000-01-10 NaN Freq: D, dtype: float64 In [233]: ts2.reindex(ts.index, method="ffill") Out[233]: 2000-01-03 0.183051 2000-01-04 0.183051 2000-01-05 0.183051 2000-01-06 2.395489 2000-01-07 2.395489 2000-01-08 2.395489 2000-01-09 0.733639 2000-01-10 0.733639 Freq: D, dtype: float64 In [234]: ts2.reindex(ts.index, method="bfill") Out[234]: 2000-01-03 0.183051 2000-01-04 2.395489 2000-01-05 2.395489 2000-01-06 2.395489 2000-01-07 0.733639 2000-01-08 0.733639 2000-01-09 0.733639 2000-01-10 NaN Freq: D, dtype: float64 In [235]: ts2.reindex(ts.index, method="nearest") Out[235]: 2000-01-03 0.183051 2000-01-04 0.183051 2000-01-05 2.395489 2000-01-06 2.395489 2000-01-07 2.395489 2000-01-08 0.733639 2000-01-09 0.733639 2000-01-10 0.733639 Freq: D, dtype: float64
这些方法要求索引是有序递增或递减的。
请注意,使用 ffill(除了method='nearest'
)或 interpolate 也可以达到相同的结果:
In [236]: ts2.reindex(ts.index).ffill() Out[236]: 2000-01-03 0.183051 2000-01-04 0.183051 2000-01-05 0.183051 2000-01-06 2.395489 2000-01-07 2.395489 2000-01-08 2.395489 2000-01-09 0.733639 2000-01-10 0.733639 Freq: D, dtype: float64
当索引不是单调递增或递减时,reindex()
会引发 ValueError。fillna()
和 interpolate()
不会对索引的顺序执行任何检查。### 重新索引时的填充限制
limit
和 tolerance
参数提供了在重新索引时填充的额外控制。Limit 指定连续匹配的最大计数:
In [237]: ts2.reindex(ts.index, method="ffill", limit=1) Out[237]: 2000-01-03 0.183051 2000-01-04 0.183051 2000-01-05 NaN 2000-01-06 2.395489 2000-01-07 2.395489 2000-01-08 NaN 2000-01-09 0.733639 2000-01-10 0.733639 Freq: D, dtype: float64
相反,容差指定索引和索引器值之间的最大距离:
In [238]: ts2.reindex(ts.index, method="ffill", tolerance="1 day") Out[238]: 2000-01-03 0.183051 2000-01-04 0.183051 2000-01-05 NaN 2000-01-06 2.395489 2000-01-07 2.395489 2000-01-08 NaN 2000-01-09 0.733639 2000-01-10 0.733639 Freq: D, dtype: float64
请注意,当在 DatetimeIndex
、TimedeltaIndex
或 PeriodIndex
上使用时,如果可能,tolerance
将被强制转换为 Timedelta
。这允许您使用适当的字符串指定容差。### 从轴中删除标签
与 reindex
密切相关的方法是 drop()
函数。它从轴中删除一组标签:
In [239]: df Out[239]: one two three a 1.394981 1.772517 NaN b 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435 d NaN 0.279344 -0.613172 In [240]: df.drop(["a", "d"], axis=0) Out[240]: one two three b 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435 In [241]: df.drop(["one"], axis=1) Out[241]: two three a 1.772517 NaN b 1.912123 -0.050390 c 1.478369 1.227435 d 0.279344 -0.613172
请注意,以下方法也有效,但不够明显/干净:
In [242]: df.reindex(df.index.difference(["a", "d"])) Out[242]: one two three b 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435 ```### 重命名 / 映射标签 `rename()` 方法允许您根据某些映射(字典或 Series)或任意函数重新标记轴。 ```py In [243]: s Out[243]: a -0.186646 b -1.692424 c -0.303893 d -1.425662 e 1.114285 dtype: float64 In [244]: s.rename(str.upper) Out[244]: A -0.186646 B -1.692424 C -0.303893 D -1.425662 E 1.114285 dtype: float64
如果传递一个函数,当使用任何标签调用时,它必须返回一个值(并且必须生成一组唯一值)。也可以使用字典或 Series:
In [245]: df.rename( .....: columns={"one": "foo", "two": "bar"}, .....: index={"a": "apple", "b": "banana", "d": "durian"}, .....: ) .....: Out[245]: foo bar three apple 1.394981 1.772517 NaN banana 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435 durian NaN 0.279344 -0.613172
如果映射不包括列/索引标签,则不会重命名。请注意,映射中的额外标签不会引发错误。
DataFrame.rename()
还支持“轴样式”调用约定,您可以指定单个 mapper
和要应用该映射的 axis
。
In [246]: df.rename({"one": "foo", "two": "bar"}, axis="columns") Out[246]: foo bar three a 1.394981 1.772517 NaN b 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435 d NaN 0.279344 -0.613172 In [247]: df.rename({"a": "apple", "b": "banana", "d": "durian"}, axis="index") Out[247]: one two three apple 1.394981 1.772517 NaN banana 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435 durian NaN 0.279344 -0.613172
最后,rename()
还接受标量或类似列表以修改 Series.name
属性。
In [248]: s.rename("scalar-name") Out[248]: a -0.186646 b -1.692424 c -0.303893 d -1.425662 e 1.114285 Name: scalar-name, dtype: float64
DataFrame.rename_axis()
和 Series.rename_axis()
方法允许更改 MultiIndex
的特定名称(而不是标签)。
In [249]: df = pd.DataFrame( .....: {"x": [1, 2, 3, 4, 5, 6], "y": [10, 20, 30, 40, 50, 60]}, .....: index=pd.MultiIndex.from_product( .....: [["a", "b", "c"], [1, 2]], names=["let", "num"] .....: ), .....: ) .....: In [250]: df Out[250]: x y let num a 1 1 10 2 2 20 b 1 3 30 2 4 40 c 1 5 50 2 6 60 In [251]: df.rename_axis(index={"let": "abc"}) Out[251]: x y abc num a 1 1 10 2 2 20 b 1 3 30 2 4 40 c 1 5 50 2 6 60 In [252]: df.rename_axis(index=str.upper) Out[252]: x y LET NUM a 1 1 10 2 2 20 b 1 3 30 2 4 40 c 1 5 50 2 6 60 ```### 重新索引以与另一个对象对齐 你可能希望取一个对象,并将其轴重新索引为与另一个对象相同的标签。虽然这个语法是简单明了的,但它是一个常见的操作,`reindex_like()` 方法可用于简化这个操作: ```py In [213]: df2 = df.reindex(["a", "b", "c"], columns=["one", "two"]) In [214]: df3 = df2 - df2.mean() In [215]: df2 Out[215]: one two a 1.394981 1.772517 b 0.343054 1.912123 c 0.695246 1.478369 In [216]: df3 Out[216]: one two a 0.583888 0.051514 b -0.468040 0.191120 c -0.115848 -0.242634 In [217]: df.reindex_like(df2) Out[217]: one two a 1.394981 1.772517 b 0.343054 1.912123 c 0.695246 1.478369
使用 align
将对象与其他对象对齐
align()
方法是同时对齐两个对象的最快方法。它支持一个 join
参数(与 joining and merging 相关):
join='outer'
:取索引的并集(默认)join='left'
:使用调用对象的索引join='right'
:使用传递对象的索引join='inner'
:交集索引
它返回一个包含重新索引的两个 Series 的元组:
In [218]: s = pd.Series(np.random.randn(5), index=["a", "b", "c", "d", "e"]) In [219]: s1 = s[:4] In [220]: s2 = s[1:] In [221]: s1.align(s2) Out[221]: (a -0.186646 b -1.692424 c -0.303893 d -1.425662 e NaN dtype: float64, a NaN b -1.692424 c -0.303893 d -1.425662 e 1.114285 dtype: float64) In [222]: s1.align(s2, join="inner") Out[222]: (b -1.692424 c -0.303893 d -1.425662 dtype: float64, b -1.692424 c -0.303893 d -1.425662 dtype: float64) In [223]: s1.align(s2, join="left") Out[223]: (a -0.186646 b -1.692424 c -0.303893 d -1.425662 dtype: float64, a NaN b -1.692424 c -0.303893 d -1.425662 dtype: float64)
对于 DataFrame,默认情况下 join 方法将应用于索引和列:
In [224]: df.align(df2, join="inner") Out[224]: ( one two a 1.394981 1.772517 b 0.343054 1.912123 c 0.695246 1.478369, one two a 1.394981 1.772517 b 0.343054 1.912123 c 0.695246 1.478369)
你也可以传递一个 axis
选项,只在指定的轴上对齐:
In [225]: df.align(df2, join="inner", axis=0) Out[225]: ( one two three a 1.394981 1.772517 NaN b 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435, one two a 1.394981 1.772517 b 0.343054 1.912123 c 0.695246 1.478369)
如果你将一个 Series 传递给DataFrame.align()
,你可以选择使用 axis
参数来对齐 DataFrame 的索引或列:
In [226]: df.align(df2.iloc[0], axis=1) Out[226]: ( one three two a 1.394981 NaN 1.772517 b 0.343054 -0.050390 1.912123 c 0.695246 1.227435 1.478369 d NaN -0.613172 0.279344, one 1.394981 three NaN two 1.772517 Name: a, dtype: float64)
重新索引时进行填充
reindex()
接受一个可选参数 method
,这是从以下表中选择的填充方法:
方法 | 动作 |
pad / ffill | 向前填充值 |
bfill / backfill | 向后填充值 |
nearest | 从最近的索引值填充 |
我们在一个简单的 Series 上说明这些填充方法:
In [227]: rng = pd.date_range("1/3/2000", periods=8) In [228]: ts = pd.Series(np.random.randn(8), index=rng) In [229]: ts2 = ts.iloc[[0, 3, 6]] In [230]: ts Out[230]: 2000-01-03 0.183051 2000-01-04 0.400528 2000-01-05 -0.015083 2000-01-06 2.395489 2000-01-07 1.414806 2000-01-08 0.118428 2000-01-09 0.733639 2000-01-10 -0.936077 Freq: D, dtype: float64 In [231]: ts2 Out[231]: 2000-01-03 0.183051 2000-01-06 2.395489 2000-01-09 0.733639 Freq: 3D, dtype: float64 In [232]: ts2.reindex(ts.index) Out[232]: 2000-01-03 0.183051 2000-01-04 NaN 2000-01-05 NaN 2000-01-06 2.395489 2000-01-07 NaN 2000-01-08 NaN 2000-01-09 0.733639 2000-01-10 NaN Freq: D, dtype: float64 In [233]: ts2.reindex(ts.index, method="ffill") Out[233]: 2000-01-03 0.183051 2000-01-04 0.183051 2000-01-05 0.183051 2000-01-06 2.395489 2000-01-07 2.395489 2000-01-08 2.395489 2000-01-09 0.733639 2000-01-10 0.733639 Freq: D, dtype: float64 In [234]: ts2.reindex(ts.index, method="bfill") Out[234]: 2000-01-03 0.183051 2000-01-04 2.395489 2000-01-05 2.395489 2000-01-06 2.395489 2000-01-07 0.733639 2000-01-08 0.733639 2000-01-09 0.733639 2000-01-10 NaN Freq: D, dtype: float64 In [235]: ts2.reindex(ts.index, method="nearest") Out[235]: 2000-01-03 0.183051 2000-01-04 0.183051 2000-01-05 2.395489 2000-01-06 2.395489 2000-01-07 2.395489 2000-01-08 0.733639 2000-01-09 0.733639 2000-01-10 0.733639 Freq: D, dtype: float64
这些方法要求索引是有序的,递增或递减的。
注意,可以使用 ffill(除了 method='nearest'
)或 interpolate 来实现相同的结果:
In [236]: ts2.reindex(ts.index).ffill() Out[236]: 2000-01-03 0.183051 2000-01-04 0.183051 2000-01-05 0.183051 2000-01-06 2.395489 2000-01-07 2.395489 2000-01-08 2.395489 2000-01-09 0.733639 2000-01-10 0.733639 Freq: D, dtype: float64
当索引不是单调递增或递减时,reindex()
会引发 ValueError。fillna()
和 interpolate()
不会对索引的顺序进行任何检查。
重新索引时填充的限制
limit
和 tolerance
参数提供了在重新索引时填充的额外控制。Limit 指定连续匹配的最大计数:
In [237]: ts2.reindex(ts.index, method="ffill", limit=1) Out[237]: 2000-01-03 0.183051 2000-01-04 0.183051 2000-01-05 NaN 2000-01-06 2.395489 2000-01-07 2.395489 2000-01-08 NaN 2000-01-09 0.733639 2000-01-10 0.733639 Freq: D, dtype: float64
相反,容差指定索引和索引器值之间的最大距离:
In [238]: ts2.reindex(ts.index, method="ffill", tolerance="1 day") Out[238]: 2000-01-03 0.183051 2000-01-04 0.183051 2000-01-05 NaN 2000-01-06 2.395489 2000-01-07 2.395489 2000-01-08 NaN 2000-01-09 0.733639 2000-01-10 0.733639 Freq: D, dtype: float64
请注意,当用于 DatetimeIndex
、TimedeltaIndex
或 PeriodIndex
时,如果可能的话,tolerance
会被转换为 Timedelta
。这允许您使用适当的字符串指定容差。
从轴中删除标签
与 reindex
密切相关的方法是 drop()
函数。它从轴中删除一组标签:
In [239]: df Out[239]: one two three a 1.394981 1.772517 NaN b 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435 d NaN 0.279344 -0.613172 In [240]: df.drop(["a", "d"], axis=0) Out[240]: one two three b 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435 In [241]: df.drop(["one"], axis=1) Out[241]: two three a 1.772517 NaN b 1.912123 -0.050390 c 1.478369 1.227435 d 0.279344 -0.613172
注意,以下方法也有效,但不够明显/清晰:
In [242]: df.reindex(df.index.difference(["a", "d"])) Out[242]: one two three b 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435
重命名/映射标签
rename()
方法允许您基于一些映射(dict 或 Series)或任意函数重新标记轴。
In [243]: s Out[243]: a -0.186646 b -1.692424 c -0.303893 d -1.425662 e 1.114285 dtype: float64 In [244]: s.rename(str.upper) Out[244]: A -0.186646 B -1.692424 C -0.303893 D -1.425662 E 1.114285 dtype: float64
如果传递一个函数,调用任何标签时必须返回一个值(并且必须产生一组唯一值)。也可以使用 dict 或 Series:
In [245]: df.rename( .....: columns={"one": "foo", "two": "bar"}, .....: index={"a": "apple", "b": "banana", "d": "durian"}, .....: ) .....: Out[245]: foo bar three apple 1.394981 1.772517 NaN banana 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435 durian NaN 0.279344 -0.613172
如果映射不包括列/索引标签,则不会重命名。请注意,映射中的额外标签不会引发错误。
DataFrame.rename()
还支持“轴样式”调用约定,您可以指定单个 mapper
和要应用该映射的 axis
。
In [246]: df.rename({"one": "foo", "two": "bar"}, axis="columns") Out[246]: foo bar three a 1.394981 1.772517 NaN b 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435 d NaN 0.279344 -0.613172 In [247]: df.rename({"a": "apple", "b": "banana", "d": "durian"}, axis="index") Out[247]: one two three apple 1.394981 1.772517 NaN banana 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435 durian NaN 0.279344 -0.613172
最后,rename()
也接受标量或类似列表以更改 Series.name
属性。
In [248]: s.rename("scalar-name") Out[248]: a -0.186646 b -1.692424 c -0.303893 d -1.425662 e 1.114285 Name: scalar-name, dtype: float64
方法 DataFrame.rename_axis()
和 Series.rename_axis()
允许更改 MultiIndex
的特定名称(而不是标签)。
In [249]: df = pd.DataFrame( .....: {"x": [1, 2, 3, 4, 5, 6], "y": [10, 20, 30, 40, 50, 60]}, .....: index=pd.MultiIndex.from_product( .....: [["a", "b", "c"], [1, 2]], names=["let", "num"] .....: ), .....: ) .....: In [250]: df Out[250]: x y let num a 1 1 10 2 2 20 b 1 3 30 2 4 40 c 1 5 50 2 6 60 In [251]: df.rename_axis(index={"let": "abc"}) Out[251]: x y abc num a 1 1 10 2 2 20 b 1 3 30 2 4 40 c 1 5 50 2 6 60 In [252]: df.rename_axis(index=str.upper) Out[252]: x y LET NUM a 1 1 10 2 2 20 b 1 3 30 2 4 40 c 1 5 50 2 6 60
迭代
对于 pandas 对象的基本迭代行为取决于类型。当迭代 Series 时,它被视为类似数组,基本迭代会产生数值。DataFrame 遵循字典的惯例,迭代对象的“键”。
简而言之,基本迭代(for i in object
)会产生:
- Series:数值
- DataFrame:列标签
因此,例如,迭代 DataFrame 将为您提供列名:
In [253]: df = pd.DataFrame( .....: {"col1": np.random.randn(3), "col2": np.random.randn(3)}, index=["a", "b", "c"] .....: ) .....: In [254]: for col in df: .....: print(col) .....: col1 col2
pandas 对象还具有类似字典的 items()
方法,用于迭代(键,值)对。
要迭代 DataFrame 的行,可以使用以下方法:
iterrows()
:将 DataFrame 的行作为(索引,Series)对进行迭代。这会将行转换为 Series 对象,这可能会改变 dtypes 并具有一些性能影响。itertuples()
:将 DataFrame 的行作为命名元组的值进行迭代。这比iterrows()
快得多,并且在大多数情况下,最好使用它来迭代 DataFrame 的值。
警告
通过 pandas 对象进行迭代通常较慢。在许多情况下,不需要手动遍历行,并且可以通过以下方法之一避免:
- 寻找矢量化解决方案:许多操作可以使用内置方法或 NumPy 函数(布尔)索引等来执行,…
- 当您有一个无法一次处理完整 DataFrame/Series 的函数时,最好使用
apply()
而不是迭代值。请参阅函数应用部分的文档。 - 如果需要对值进行迭代操作但性能很重要,请考虑使用 cython 或 numba 编写内部循环。请参阅提高性能部分,了解一些此方法的示例。
警告
您永远不应该修改您正在迭代的内容。这并不保证在所有情况下都有效。根据数据类型,迭代器返回一个副本而不是视图,对其进行写入将不会产生任何效果!
例如,在以下情况中设置值没有效果:
In [255]: df = pd.DataFrame({"a": [1, 2, 3], "b": ["a", "b", "c"]}) In [256]: for index, row in df.iterrows(): .....: row["a"] = 10 .....: In [257]: df Out[257]: a b 0 1 a 1 2 b 2 3 c
Pandas 2.2 中文官方教程和指南(九·三)(2)https://developer.aliyun.com/article/1509733