Pandas 2.2 中文官方教程和指南(九·三)

这篇具有很好参考价值的文章主要介绍了Pandas 2.2 中文官方教程和指南(九·三)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

重新索引以与另一个对象对齐

你可能希望取一个对象并重新索引其轴,使其标签与另一个对象相同。虽然这个操作的语法虽然冗长但简单,但它是一个常见的操作,因此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() 不会对索引的顺序执行任何检查。### 重新索引时的填充限制

limittolerance 参数提供了在重新索引时填充的额外控制。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 

请注意,当在 DatetimeIndexTimedeltaIndexPeriodIndex 上使用时,如果可能,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() 不会对索引的顺序进行任何检查。

重新索引时填充的限制

limittolerance 参数提供了在重新索引时填充的额外控制。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 

请注意,当用于 DatetimeIndexTimedeltaIndexPeriodIndex 时,如果可能的话,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 

items

与类似字典的接口一致,items()遍历键值对:

  • Series:(索引,标量值)对

  • DataFrame:(列,Series)对

例如:

In [258]: for label, ser in df.items():
 .....:    print(label)
 .....:    print(ser)
 .....: 
a
0    1
1    2
2    3
Name: a, dtype: int64
b
0    a
1    b
2    c
Name: b, dtype: object 

iterrows

iterrows()允许您将 DataFrame 的行作为 Series 对象进行迭代。它返回一个迭代器,产生每个索引值以及包含每行数据的 Series:

In [259]: for row_index, row in df.iterrows():
 .....:    print(row_index, row, sep="\n")
 .....: 
0
a    1
b    a
Name: 0, dtype: object
1
a    2
b    b
Name: 1, dtype: object
2
a    3
b    c
Name: 2, dtype: object 

注意

因为iterrows()为每行返回一个 Series,它不会在行之间保留数据类型(数据类型在 DataFrame 的列之间保留)。例如,

In [260]: df_orig = pd.DataFrame([[1, 1.5]], columns=["int", "float"])

In [261]: df_orig.dtypes
Out[261]: 
int        int64
float    float64
dtype: object

In [262]: row = next(df_orig.iterrows())[1]

In [263]: row
Out[263]: 
int      1.0
float    1.5
Name: 0, dtype: float64 

row中的所有值,作为一个 Series 返回,现在都被转换为浮点数,包括列x中的原始整数值:

In [264]: row["int"].dtype
Out[264]: dtype('float64')

In [265]: df_orig["int"].dtype
Out[265]: dtype('int64') 

为了在迭代行时保留数据类型,最好使用itertuples(),它返回值的命名元组,通常比iterrows()快得多。

例如,转置 DataFrame 的一种构造方法是:

In [266]: df2 = pd.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})

In [267]: print(df2)
 x  y
0  1  4
1  2  5
2  3  6

In [268]: print(df2.T)
 0  1  2
x  1  2  3
y  4  5  6

In [269]: df2_t = pd.DataFrame({idx: values for idx, values in df2.iterrows()})

In [270]: print(df2_t)
 0  1  2
x  1  2  3
y  4  5  6 

itertuples

itertuples() 方法将返回一个迭代器,为 DataFrame 中的每一行生成一个命名元组。元组的第一个元素将是行的相应索引值,而其余值是行值。

例如:

In [271]: for row in df.itertuples():
 .....:    print(row)
 .....: 
Pandas(Index=0, a=1, b='a')
Pandas(Index=1, a=2, b='b')
Pandas(Index=2, a=3, b='c') 

此方法不会将行转换为 Series 对象;它仅返回命名元组中的值。因此,itertuples() 保留值的数据类型,并且通常比iterrows() 快得多。

注意

如果列名是无效的 Python 标识符、重复的或以下划线开头,则列名将重命名为位置名称。如果列数较多(>255),则返回常规元组。

项目

与类似字典的接口一致,items() 迭代遍历键值对:

  • Series:(索引,标量值) 对

  • DataFrame:(列,Series) 对

例如:

In [258]: for label, ser in df.items():
 .....:    print(label)
 .....:    print(ser)
 .....: 
a
0    1
1    2
2    3
Name: a, dtype: int64
b
0    a
1    b
2    c
Name: b, dtype: object 

遍历行

iterrows() 允许您遍历 DataFrame 的行作为 Series 对象。它返回一个迭代器,每个索引值以及包含每行数据的 Series:

In [259]: for row_index, row in df.iterrows():
 .....:    print(row_index, row, sep="\n")
 .....: 
0
a    1
b    a
Name: 0, dtype: object
1
a    2
b    b
Name: 1, dtype: object
2
a    3
b    c
Name: 2, dtype: object 

注意

因为iterrows() 为每行返回一个 Series,它不会在行之间保留 dtype(对于 DataFrame,dtype 在列之间保留)。例如,

In [260]: df_orig = pd.DataFrame([[1, 1.5]], columns=["int", "float"])

In [261]: df_orig.dtypes
Out[261]: 
int        int64
float    float64
dtype: object

In [262]: row = next(df_orig.iterrows())[1]

In [263]: row
Out[263]: 
int      1.0
float    1.5
Name: 0, dtype: float64 

返回为 Series 的row中的所有值现在都被转换为浮点数,包括列x中的原始整数值:

In [264]: row["int"].dtype
Out[264]: dtype('float64')

In [265]: df_orig["int"].dtype
Out[265]: dtype('int64') 

在遍历行时保留 dtypes,最好使用itertuples(),它返回值的命名元组,通常比iterrows()快得多。

例如,转置 DataFrame 的一种构造方法是:

In [266]: df2 = pd.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})

In [267]: print(df2)
 x  y
0  1  4
1  2  5
2  3  6

In [268]: print(df2.T)
 0  1  2
x  1  2  3
y  4  5  6

In [269]: df2_t = pd.DataFrame({idx: values for idx, values in df2.iterrows()})

In [270]: print(df2_t)
 0  1  2
x  1  2  3
y  4  5  6 

itertuples

itertuples() 方法将返回一个迭代器,为 DataFrame 中的每一行生成一个命名元组。元组的第一个元素将是行的相应索引值,而其余值是行值。

例如:

In [271]: for row in df.itertuples():
 .....:    print(row)
 .....: 
Pandas(Index=0, a=1, b='a')
Pandas(Index=1, a=2, b='b')
Pandas(Index=2, a=3, b='c') 

此方法不会将行转换为 Series 对象;它只是返回命名元组内的值。因此,itertuples() 保留了值的数据类型,并且通常比 iterrows() 更快。

注意

如果列名无效的 Python 标识符、重复或以下划线开头,则列名将重命名为位置名称。当列数较多(>255)时,将返回常规元组。

.dt 访问器

如果 Series 是日期时间/周期类别的 Series,则 Series 具有一种访问器,以简洁地返回 Series的日期时间类属性。这将返回一个 Series,其索引类似于现有的 Series

# datetime
In [272]: s = pd.Series(pd.date_range("20130101 09:10:12", periods=4))

In [273]: s
Out[273]: 
0   2013-01-01 09:10:12
1   2013-01-02 09:10:12
2   2013-01-03 09:10:12
3   2013-01-04 09:10:12
dtype: datetime64[ns]

In [274]: s.dt.hour
Out[274]: 
0    9
1    9
2    9
3    9
dtype: int32

In [275]: s.dt.second
Out[275]: 
0    12
1    12
2    12
3    12
dtype: int32

In [276]: s.dt.day
Out[276]: 
0    1
1    2
2    3
3    4
dtype: int32 

这使得可以像这样进行美观的表达:

In [277]: s[s.dt.day == 2]
Out[277]: 
1   2013-01-02 09:10:12
dtype: datetime64[ns] 

您可以轻松地生成带时区的转换:

In [278]: stz = s.dt.tz_localize("US/Eastern")

In [279]: stz
Out[279]: 
0   2013-01-01 09:10:12-05:00
1   2013-01-02 09:10:12-05:00
2   2013-01-03 09:10:12-05:00
3   2013-01-04 09:10:12-05:00
dtype: datetime64[ns, US/Eastern]

In [280]: stz.dt.tz
Out[280]: <DstTzInfo 'US/Eastern' LMT-1 day, 19:04:00 STD> 

您还可以链接这些类型的操作:

In [281]: s.dt.tz_localize("UTC").dt.tz_convert("US/Eastern")
Out[281]: 
0   2013-01-01 04:10:12-05:00
1   2013-01-02 04:10:12-05:00
2   2013-01-03 04:10:12-05:00
3   2013-01-04 04:10:12-05:00
dtype: datetime64[ns, US/Eastern] 

您还可以使用 Series.dt.strftime() 将日期时间值格式化为字符串,其支持与标准 strftime() 相同的格式。

# DatetimeIndex
In [282]: s = pd.Series(pd.date_range("20130101", periods=4))

In [283]: s
Out[283]: 
0   2013-01-01
1   2013-01-02
2   2013-01-03
3   2013-01-04
dtype: datetime64[ns]

In [284]: s.dt.strftime("%Y/%m/%d")
Out[284]: 
0    2013/01/01
1    2013/01/02
2    2013/01/03
3    2013/01/04
dtype: object 
# PeriodIndex
In [285]: s = pd.Series(pd.period_range("20130101", periods=4))

In [286]: s
Out[286]: 
0    2013-01-01
1    2013-01-02
2    2013-01-03
3    2013-01-04
dtype: period[D]

In [287]: s.dt.strftime("%Y/%m/%d")
Out[287]: 
0    2013/01/01
1    2013/01/02
2    2013/01/03
3    2013/01/04
dtype: object 

.dt 访问器适用于周期和时间增量数据类型。

# period
In [288]: s = pd.Series(pd.period_range("20130101", periods=4, freq="D"))

In [289]: s
Out[289]: 
0    2013-01-01
1    2013-01-02
2    2013-01-03
3    2013-01-04
dtype: period[D]

In [290]: s.dt.year
Out[290]: 
0    2013
1    2013
2    2013
3    2013
dtype: int64

In [291]: s.dt.day
Out[291]: 
0    1
1    2
2    3
3    4
dtype: int64 
# timedelta
In [292]: s = pd.Series(pd.timedelta_range("1 day 00:00:05", periods=4, freq="s"))

In [293]: s
Out[293]: 
0   1 days 00:00:05
1   1 days 00:00:06
2   1 days 00:00:07
3   1 days 00:00:08
dtype: timedelta64[ns]

In [294]: s.dt.days
Out[294]: 
0    1
1    1
2    1
3    1
dtype: int64

In [295]: s.dt.seconds
Out[295]: 
0    5
1    6
2    7
3    8
dtype: int32

In [296]: s.dt.components
Out[296]: 
 days  hours  minutes  seconds  milliseconds  microseconds  nanoseconds
0     1      0        0        5             0             0            0
1     1      0        0        6             0             0            0
2     1      0        0        7             0             0            0
3     1      0        0        8             0             0            0 

注意

如果您使用非日期时间类似值访问 Series.dt,将引发 TypeError

向量化字符串方法

Series 配备了一组字符串处理方法,使得操作数组的每个元素变得容易。最重要的是,这些方法会自动排除丢失/NA 值。通过 Seriesstr 属性访问这些方法,通常名称与等效的(标量)内置字符串方法匹配。例如:

In [297]: s = pd.Series(
 .....:    ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
 .....: )
 .....: 

In [298]: s.str.lower()
Out[298]: 
0       a
1       b
2       c
3    aaba
4    baca
5    <NA>
6    caba
7     dog
8     cat
dtype: string 

还提供了强大的模式匹配方法,但请注意,模式匹配通常默认使用正则表达式(有些情况下总是使用)。

注意

在 pandas 1.0 之前,字符串方法仅适用于 object -dtype Series。pandas 1.0 添加了 StringDtype,专门用于字符串。有关更多信息,请参阅文本数据类型。

请参阅向量化字符串方法以获取完整的描述。

排序

pandas 支持三种排序方式:按索引标签排序、按列值排序以及按两者组合排序。

按索引

Series.sort_index()DataFrame.sort_index() 方法用于按索引级别对 pandas 对象进行排序。

In [299]: df = pd.DataFrame(
 .....:    {
 .....:        "one": pd.Series(np.random.randn(3), index=["a", "b", "c"]),
 .....:        "two": pd.Series(np.random.randn(4), index=["a", "b", "c", "d"]),
 .....:        "three": pd.Series(np.random.randn(3), index=["b", "c", "d"]),
 .....:    }
 .....: )
 .....: 

In [300]: unsorted_df = df.reindex(
 .....:    index=["a", "d", "c", "b"], columns=["three", "two", "one"]
 .....: )
 .....: 

In [301]: unsorted_df
Out[301]: 
 three       two       one
a       NaN -1.152244  0.562973
d -0.252916 -0.109597       NaN
c  1.273388 -0.167123  0.640382
b -0.098217  0.009797 -1.299504

# DataFrame
In [302]: unsorted_df.sort_index()
Out[302]: 
 three       two       one
a       NaN -1.152244  0.562973
b -0.098217  0.009797 -1.299504
c  1.273388 -0.167123  0.640382
d -0.252916 -0.109597       NaN

In [303]: unsorted_df.sort_index(ascending=False)
Out[303]: 
 three       two       one
d -0.252916 -0.109597       NaN
c  1.273388 -0.167123  0.640382
b -0.098217  0.009797 -1.299504
a       NaN -1.152244  0.562973

In [304]: unsorted_df.sort_index(axis=1)
Out[304]: 
 one     three       two
a  0.562973       NaN -1.152244
d       NaN -0.252916 -0.109597
c  0.640382  1.273388 -0.167123
b -1.299504 -0.098217  0.009797

# Series
In [305]: unsorted_df["three"].sort_index()
Out[305]: 
a         NaN
b   -0.098217
c    1.273388
d   -0.252916
Name: three, dtype: float64 

按索引排序还支持一个 key 参数,该参数接受一个可调用函数,应用于正在排序的索引。对于 MultiIndex 对象,key 会按级别应用到由 level 指定的级别。

In [306]: s1 = pd.DataFrame({"a": ["B", "a", "C"], "b": [1, 2, 3], "c": [2, 3, 4]}).set_index(
 .....:    list("ab")
 .....: )
 .....: 

In [307]: s1
Out[307]: 
 c
a b 
B 1  2
a 2  3
C 3  4 
In [308]: s1.sort_index(level="a")
Out[308]: 
 c
a b 
B 1  2
C 3  4
a 2  3

In [309]: s1.sort_index(level="a", key=lambda idx: idx.str.lower())
Out[309]: 
 c
a b 
a 2  3
B 1  2
C 3  4 

有关按值排序的关键信息,请参见 value sorting。 ### 按值排序

Series.sort_values() 方法用于按其值对 Series 进行排序。DataFrame.sort_values() 方法用于按其列或行值对 DataFrame 进行排序。可选的 by 参数可用于指定一个或多个列以确定排序顺序。

In [310]: df1 = pd.DataFrame(
 .....:    {"one": [2, 1, 1, 1], "two": [1, 3, 2, 4], "three": [5, 4, 3, 2]}
 .....: )
 .....: 

In [311]: df1.sort_values(by="two")
Out[311]: 
 one  two  three
0    2    1      5
2    1    2      3
1    1    3      4
3    1    4      2 

by 参数可以接受列名的列表,例如:

In [312]: df1[["one", "two", "three"]].sort_values(by=["one", "two"])
Out[312]: 
 one  two  three
2    1    2      3
1    1    3      4
3    1    4      2
0    2    1      5 

这些方法通过 na_position 参数对 NA 值进行特殊处理:

In [313]: s[2] = np.nan

In [314]: s.sort_values()
Out[314]: 
0       A
3    Aaba
1       B
4    Baca
6    CABA
8     cat
7     dog
2    <NA>
5    <NA>
dtype: string

In [315]: s.sort_values(na_position="first")
Out[315]: 
2    <NA>
5    <NA>
0       A
3    Aaba
1       B
4    Baca
6    CABA
8     cat
7     dog
dtype: string 

排序还支持一个 key 参数,该参数接受一个可调用函数,应用于正在排序的值。

In [316]: s1 = pd.Series(["B", "a", "C"]) 
In [317]: s1.sort_values()
Out[317]: 
0    B
2    C
1    a
dtype: object

In [318]: s1.sort_values(key=lambda x: x.str.lower())
Out[318]: 
1    a
0    B
2    C
dtype: object 

key 将获得值的 Series 并应返回具有相同形状的转换值的 Series 或数组。对于 DataFrame 对象,key 会按列应用,因此 key 仍应期望一个 Series 并返回一个 Series,例如

In [319]: df = pd.DataFrame({"a": ["B", "a", "C"], "b": [1, 2, 3]}) 
In [320]: df.sort_values(by="a")
Out[320]: 
 a  b
0  B  1
2  C  3
1  a  2

In [321]: df.sort_values(by="a", key=lambda col: col.str.lower())
Out[321]: 
 a  b
1  a  2
0  B  1
2  C  3 

每列的名称或类型可用于对不同列应用不同函数。 ### 按索引和值排序

作为 by 参数传递给 DataFrame.sort_values() 的字符串可以指代列或索引级别名称。

# Build MultiIndex
In [322]: idx = pd.MultiIndex.from_tuples(
 .....:    [("a", 1), ("a", 2), ("a", 2), ("b", 2), ("b", 1), ("b", 1)]
 .....: )
 .....: 

In [323]: idx.names = ["first", "second"]

# Build DataFrame
In [324]: df_multi = pd.DataFrame({"A": np.arange(6, 0, -1)}, index=idx)

In [325]: df_multi
Out[325]: 
 A
first second 
a     1       6
 2       5
 2       4
b     2       3
 1       2
 1       1 

按‘second’(索引)和‘A’(列)排序

In [326]: df_multi.sort_values(by=["second", "A"])
Out[326]: 
 A
first second 
b     1       1
 1       2
a     1       6
b     2       3
a     2       4
 2       5 

注意

如果一个字符串既匹配列名又匹配索引级别名称,则会发出警告并且列优先。这将导致在将来版本中出现歧义错误。 ### searchsorted

Series 有 searchsorted() 方法,其工作方式类似于 numpy.ndarray.searchsorted()

In [327]: ser = pd.Series([1, 2, 3])

In [328]: ser.searchsorted([0, 3])
Out[328]: array([0, 2])

In [329]: ser.searchsorted([0, 4])
Out[329]: array([0, 3])

In [330]: ser.searchsorted([1, 3], side="right")
Out[330]: array([1, 3])

In [331]: ser.searchsorted([1, 3], side="left")
Out[331]: array([0, 2])

In [332]: ser = pd.Series([3, 1, 2])

In [333]: ser.searchsorted([0, 3], sorter=np.argsort(ser))
Out[333]: array([0, 2]) 
```### 最小/最大值

`Series` 有 `nsmallest()` 和 `nlargest()` 方法,返回最小或最大的 \(n\) 值。对于大型 `Series`,这比对整个 Series 进行排序并在结果上调用 `head(n)` 要快得多。

```py
In [334]: s = pd.Series(np.random.permutation(10))

In [335]: s
Out[335]: 
0    2
1    0
2    3
3    7
4    1
5    5
6    9
7    6
8    8
9    4
dtype: int64

In [336]: s.sort_values()
Out[336]: 
1    0
4    1
0    2
2    3
9    4
5    5
7    6
3    7
8    8
6    9
dtype: int64

In [337]: s.nsmallest(3)
Out[337]: 
1    0
4    1
0    2
dtype: int64

In [338]: s.nlargest(3)
Out[338]: 
6    9
8    8
3    7
dtype: int64 

DataFrame 也有 nlargestnsmallest 方法。

In [339]: df = pd.DataFrame(
 .....:    {
 .....:        "a": [-2, -1, 1, 10, 8, 11, -1],
 .....:        "b": list("abdceff"),
 .....:        "c": [1.0, 2.0, 4.0, 3.2, np.nan, 3.0, 4.0],
 .....:    }
 .....: )
 .....: 

In [340]: df.nlargest(3, "a")
Out[340]: 
 a  b    c
5  11  f  3.0
3  10  c  3.2
4   8  e  NaN

In [341]: df.nlargest(5, ["a", "c"])
Out[341]: 
 a  b    c
5  11  f  3.0
3  10  c  3.2
4   8  e  NaN
2   1  d  4.0
6  -1  f  4.0

In [342]: df.nsmallest(3, "a")
Out[342]: 
 a  b    c
0 -2  a  1.0
1 -1  b  2.0
6 -1  f  4.0

In [343]: df.nsmallest(5, ["a", "c"])
Out[343]: 
 a  b    c
0 -2  a  1.0
1 -1  b  2.0
6 -1  f  4.0
2  1  d  4.0
4  8  e  NaN 
```### 按 MultiIndex 列排序

当列是 MultiIndex 时,必须明确指定排序,并完全指定所有级别到 `by`。

```py
In [344]: df1.columns = pd.MultiIndex.from_tuples(
 .....:    [("a", "one"), ("a", "two"), ("b", "three")]
 .....: )
 .....: 

In [345]: df1.sort_values(by=("a", "two"))
Out[345]: 
 a         b
 one two three
0   2   1     5
2   1   2     3
1   1   3     4
3   1   4     2 
```### 按索引

`Series.sort_index()` 和 `DataFrame.sort_index()` 方法用于按其索引级别对 pandas 对象进行排序。

```py
In [299]: df = pd.DataFrame(
 .....:    {
 .....:        "one": pd.Series(np.random.randn(3), index=["a", "b", "c"]),
 .....:        "two": pd.Series(np.random.randn(4), index=["a", "b", "c", "d"]),
 .....:        "three": pd.Series(np.random.randn(3), index=["b", "c", "d"]),
 .....:    }
 .....: )
 .....: 

In [300]: unsorted_df = df.reindex(
 .....:    index=["a", "d", "c", "b"], columns=["three", "two", "one"]
 .....: )
 .....: 

In [301]: unsorted_df
Out[301]: 
 three       two       one
a       NaN -1.152244  0.562973
d -0.252916 -0.109597       NaN
c  1.273388 -0.167123  0.640382
b -0.098217  0.009797 -1.299504

# DataFrame
In [302]: unsorted_df.sort_index()
Out[302]: 
 three       two       one
a       NaN -1.152244  0.562973
b -0.098217  0.009797 -1.299504
c  1.273388 -0.167123  0.640382
d -0.252916 -0.109597       NaN

In [303]: unsorted_df.sort_index(ascending=False)
Out[303]: 
 three       two       one
d -0.252916 -0.109597       NaN
c  1.273388 -0.167123  0.640382
b -0.098217  0.009797 -1.299504
a       NaN -1.152244  0.562973

In [304]: unsorted_df.sort_index(axis=1)
Out[304]: 
 one     three       two
a  0.562973       NaN -1.152244
d       NaN -0.252916 -0.109597
c  0.640382  1.273388 -0.167123
b -1.299504 -0.098217  0.009797

# Series
In [305]: unsorted_df["three"].sort_index()
Out[305]: 
a         NaN
b   -0.098217
c    1.273388
d   -0.252916
Name: three, dtype: float64 

按索引排序还支持一个 key 参数,该参数接受一个可调用函数,应用于要排序的索引。对于 MultiIndex 对象,key 会按指定的 level 对每个级别应用。

In [306]: s1 = pd.DataFrame({"a": ["B", "a", "C"], "b": [1, 2, 3], "c": [2, 3, 4]}).set_index(
 .....:    list("ab")
 .....: )
 .....: 

In [307]: s1
Out[307]: 
 c
a b 
B 1  2
a 2  3
C 3  4 
In [308]: s1.sort_index(level="a")
Out[308]: 
 c
a b 
B 1  2
C 3  4
a 2  3

In [309]: s1.sort_index(level="a", key=lambda idx: idx.str.lower())
Out[309]: 
 c
a b 
a 2  3
B 1  2
C 3  4 

有关按值排序的键排序信息,请参阅 值排序。

按数值排序

使用 Series.sort_values() 方法可以按其数值对 Series 进行排序。使用 DataFrame.sort_values() 方法可以按其列或行数值对 DataFrame 进行排序。可选的 by 参数用于指定一个或多个列以确定排序顺序。

In [310]: df1 = pd.DataFrame(
 .....:    {"one": [2, 1, 1, 1], "two": [1, 3, 2, 4], "three": [5, 4, 3, 2]}
 .....: )
 .....: 

In [311]: df1.sort_values(by="two")
Out[311]: 
 one  two  three
0    2    1      5
2    1    2      3
1    1    3      4
3    1    4      2 

by 参数可以接受列名的列表,例如:

In [312]: df1[["one", "two", "three"]].sort_values(by=["one", "two"])
Out[312]: 
 one  two  three
2    1    2      3
1    1    3      4
3    1    4      2
0    2    1      5 

这些方法对 NA 值有特殊处理,通过 na_position 参数:

In [313]: s[2] = np.nan

In [314]: s.sort_values()
Out[314]: 
0       A
3    Aaba
1       B
4    Baca
6    CABA
8     cat
7     dog
2    <NA>
5    <NA>
dtype: string

In [315]: s.sort_values(na_position="first")
Out[315]: 
2    <NA>
5    <NA>
0       A
3    Aaba
1       B
4    Baca
6    CABA
8     cat
7     dog
dtype: string 

排序还支持一个 key 参数,该参数接受一个可调用函数,应用于要排序的值。

In [316]: s1 = pd.Series(["B", "a", "C"]) 
In [317]: s1.sort_values()
Out[317]: 
0    B
2    C
1    a
dtype: object

In [318]: s1.sort_values(key=lambda x: x.str.lower())
Out[318]: 
1    a
0    B
2    C
dtype: object 

key 将给出 Series 的值,并应返回一个形状相同的 Series 或数组,带有转换后的值。对于 DataFrame 对象,key 会按列应用,因此 key 仍应期望一个 Series,并返回一个 Series,例如:

In [319]: df = pd.DataFrame({"a": ["B", "a", "C"], "b": [1, 2, 3]}) 
In [320]: df.sort_values(by="a")
Out[320]: 
 a  b
0  B  1
2  C  3
1  a  2

In [321]: df.sort_values(by="a", key=lambda col: col.str.lower())
Out[321]: 
 a  b
1  a  2
0  B  1
2  C  3 

每列的名称或类型可用于对不同列应用不同的函数。

通过索引和数值

作为 DataFrame.sort_values()by 参数传递的字符串可以是列名,也可以是索引级别名称。

# Build MultiIndex
In [322]: idx = pd.MultiIndex.from_tuples(
 .....:    [("a", 1), ("a", 2), ("a", 2), ("b", 2), ("b", 1), ("b", 1)]
 .....: )
 .....: 

In [323]: idx.names = ["first", "second"]

# Build DataFrame
In [324]: df_multi = pd.DataFrame({"A": np.arange(6, 0, -1)}, index=idx)

In [325]: df_multi
Out[325]: 
 A
first second 
a     1       6
 2       5
 2       4
b     2       3
 1       2
 1       1 

按‘second’(索引)和‘A’(列)排序

In [326]: df_multi.sort_values(by=["second", "A"])
Out[326]: 
 A
first second 
b     1       1
 1       2
a     1       6
b     2       3
a     2       4
 2       5 

注意

如果一个字符串既匹配列名又匹配索引级别名称,那么会发出警告,并且列优先。这将导致将来版本中的歧义错误。

searchsorted

Series 有 searchsorted() 方法,工作方式类似于 numpy.ndarray.searchsorted()

In [327]: ser = pd.Series([1, 2, 3])

In [328]: ser.searchsorted([0, 3])
Out[328]: array([0, 2])

In [329]: ser.searchsorted([0, 4])
Out[329]: array([0, 3])

In [330]: ser.searchsorted([1, 3], side="right")
Out[330]: array([1, 3])

In [331]: ser.searchsorted([1, 3], side="left")
Out[331]: array([0, 2])

In [332]: ser = pd.Series([3, 1, 2])

In [333]: ser.searchsorted([0, 3], sorter=np.argsort(ser))
Out[333]: array([0, 2]) 

最小值 / 最大值

Series具有nsmallest()nlargest()方法,返回最小或最大的(n)个值。对于大型Series,这比对整个 Series 进行排序并在结果上调用head(n)要快得多。

In [334]: s = pd.Series(np.random.permutation(10))

In [335]: s
Out[335]: 
0    2
1    0
2    3
3    7
4    1
5    5
6    9
7    6
8    8
9    4
dtype: int64

In [336]: s.sort_values()
Out[336]: 
1    0
4    1
0    2
2    3
9    4
5    5
7    6
3    7
8    8
6    9
dtype: int64

In [337]: s.nsmallest(3)
Out[337]: 
1    0
4    1
0    2
dtype: int64

In [338]: s.nlargest(3)
Out[338]: 
6    9
8    8
3    7
dtype: int64 

DataFrame也有nlargestnsmallest方法。

In [339]: df = pd.DataFrame(
 .....:    {
 .....:        "a": [-2, -1, 1, 10, 8, 11, -1],
 .....:        "b": list("abdceff"),
 .....:        "c": [1.0, 2.0, 4.0, 3.2, np.nan, 3.0, 4.0],
 .....:    }
 .....: )
 .....: 

In [340]: df.nlargest(3, "a")
Out[340]: 
 a  b    c
5  11  f  3.0
3  10  c  3.2
4   8  e  NaN

In [341]: df.nlargest(5, ["a", "c"])
Out[341]: 
 a  b    c
5  11  f  3.0
3  10  c  3.2
4   8  e  NaN
2   1  d  4.0
6  -1  f  4.0

In [342]: df.nsmallest(3, "a")
Out[342]: 
 a  b    c
0 -2  a  1.0
1 -1  b  2.0
6 -1  f  4.0

In [343]: df.nsmallest(5, ["a", "c"])
Out[343]: 
 a  b    c
0 -2  a  1.0
1 -1  b  2.0
6 -1  f  4.0
2  1  d  4.0
4  8  e  NaN 

按多级索引列排序

当列是多级索引时,必须明确排序,并完全指定所有级别到by

In [344]: df1.columns = pd.MultiIndex.from_tuples(
 .....:    [("a", "one"), ("a", "two"), ("b", "three")]
 .....: )
 .....: 

In [345]: df1.sort_values(by=("a", "two"))
Out[345]: 
 a         b
 one two three
0   2   1     5
2   1   2     3
1   1   3     4
3   1   4     2 

复制

pandas 对象上的copy()方法会复制基础数据(尽管不会复制轴索引,因为它们是不可变的),并返回一个新对象。请注意很少需要复制对象。例如,只有少数几种方法可以原地修改 DataFrame:

  • 插入、删除或修改列。

  • 分配给indexcolumns属性。

  • 对于同质数据,可以通过values属性或高级索引直接修改值。

明确一点,没有任何 pandas 方法会具有修改数据的副作用;几乎每个方法都会返回一个新对象,保持原始对象不变。如果数据被修改,那是因为你明确这样做了。

数据类型

在大多数情况下,pandas 使用 NumPy 数组和数据类型来处理 Series 或 DataFrame 的单个列。NumPy 支持floatintbooltimedelta64[ns]datetime64[ns](请注意,NumPy 不支持时区感知的日期时间)。

pandas 和第三方库扩展了 NumPy 的类型系统的几个地方。本节描述了 pandas 在内部所做的扩展。请参阅扩展类型了解如何编写自己的扩展以与 pandas 一起使用。请参阅生态系统页面查看已实现扩展的第三方库列表。

以下表列出了所有 pandas 扩展类型。对于需要dtype参数的方法,可以按照指示指定字符串。有关每种类型的更多信息,请参阅相应的文档部分。

数据类型 数据类型 标量 数组 字符串别名
时区感知日期时间 DatetimeTZDtype Timestamp arrays.DatetimeArray 'datetime64[ns, <tz>]'
类别 CategoricalDtype (none) Categorical 'category'
期间(时间跨度) PeriodDtype Period arrays.PeriodArray 'Period[<freq>]' 'period[<freq>]',
稀疏 SparseDtype (none) arrays.SparseArray 'Sparse', 'Sparse[int]', 'Sparse[float]'
间隔 IntervalDtype Interval arrays.IntervalArray 'interval', 'Interval', 'Interval[<numpy_dtype>]', 'Interval[datetime64[ns, <tz>]]', 'Interval[timedelta64[<freq>]]'
可空整数 Int64Dtype, … (none) arrays.IntegerArray 'Int8', 'Int16', 'Int32', 'Int64', 'UInt8', 'UInt16', 'UInt32', 'UInt64'
可空浮点数 Float64Dtype, … (none) arrays.FloatingArray 'Float32', 'Float64'
字符串 StringDtype str arrays.StringArray 'string'
布尔(带 NA) BooleanDtype bool arrays.BooleanArray 'boolean'

pandas 有两种存储字符串的方式。

  1. object数据类型,可以保存任何 Python 对象,包括字符串。

  2. StringDtype,专门用于字符串。

通常,我们建议使用StringDtype。更多信息请参阅文本数据类型。

最后,可以使用object数据类型存储任意对象,但应尽可能避免(出于性能和与其他库和方法的互操作性考虑。请参阅对象转换)。

一个方便的dtypes属性用于 DataFrame 返回一个 Series,其中包含每列的数据类型。

In [346]: dft = pd.DataFrame(
 .....:    {
 .....:        "A": np.random.rand(3),
 .....:        "B": 1,
 .....:        "C": "foo",
 .....:        "D": pd.Timestamp("20010102"),
 .....:        "E": pd.Series([1.0] * 3).astype("float32"),
 .....:        "F": False,
 .....:        "G": pd.Series([1] * 3, dtype="int8"),
 .....:    }
 .....: )
 .....: 

In [347]: dft
Out[347]: 
 A  B    C          D    E      F  G
0  0.035962  1  foo 2001-01-02  1.0  False  1
1  0.701379  1  foo 2001-01-02  1.0  False  1
2  0.281885  1  foo 2001-01-02  1.0  False  1

In [348]: dft.dtypes
Out[348]: 
A          float64
B            int64
C           object
D    datetime64[s]
E          float32
F             bool
G             int8
dtype: object 

Series对象上,使用dtype属性。

In [349]: dft["A"].dtype
Out[349]: dtype('float64') 

如果 pandas 对象包含具有多种数据类型在单个列中的数据,则将选择列的数据类型以容纳所有数据类型(object是最通用的)。

# these ints are coerced to floats
In [350]: pd.Series([1, 2, 3, 4, 5, 6.0])
Out[350]: 
0    1.0
1    2.0
2    3.0
3    4.0
4    5.0
5    6.0
dtype: float64

# string data forces an ``object`` dtype
In [351]: pd.Series([1, 2, 3, 6.0, "foo"])
Out[351]: 
0      1
1      2
2      3
3    6.0
4    foo
dtype: object 

可以通过调用DataFrame.dtypes.value_counts()来查找DataFrame中每种类型的列数。

In [352]: dft.dtypes.value_counts()
Out[352]: 
float64          1
int64            1
object           1
datetime64[s]    1
float32          1
bool             1
int8             1
Name: count, dtype: int64 

数值数据类型将传播并可以共存于数据框中。如果传递了数据类型(可以直接通过dtype关键字、传递的ndarray或传递的Series),那么它将在数据框操作中保留。此外,不同的数值数据类型不会被合并。以下示例将让你有所了解。

In [353]: df1 = pd.DataFrame(np.random.randn(8, 1), columns=["A"], dtype="float32")

In [354]: df1
Out[354]: 
 A
0  0.224364
1  1.890546
2  0.182879
3  0.787847
4 -0.188449
5  0.667715
6 -0.011736
7 -0.399073

In [355]: df1.dtypes
Out[355]: 
A    float32
dtype: object

In [356]: df2 = pd.DataFrame(
 .....:    {
 .....:        "A": pd.Series(np.random.randn(8), dtype="float16"),
 .....:        "B": pd.Series(np.random.randn(8)),
 .....:        "C": pd.Series(np.random.randint(0, 255, size=8), dtype="uint8"),  # [0,255] (range of uint8)
 .....:    }
 .....: )
 .....: 

In [357]: df2
Out[357]: 
 A         B    C
0  0.823242  0.256090   26
1  1.607422  1.426469   86
2 -0.333740 -0.416203   46
3 -0.063477  1.139976  212
4 -1.014648 -1.193477   26
5  0.678711  0.096706    7
6 -0.040863 -1.956850  184
7 -0.357422 -0.714337  206

In [358]: df2.dtypes
Out[358]: 
A    float16
B    float64
C      uint8
dtype: object 

默认值

默认情况下,整数类型为int64,浮点类型为float64不受平台(32 位或 64 位)的影响。以下都将导致int64数据类型。

In [359]: pd.DataFrame([1, 2], columns=["a"]).dtypes
Out[359]: 
a    int64
dtype: object

In [360]: pd.DataFrame({"a": [1, 2]}).dtypes
Out[360]: 
a    int64
dtype: object

In [361]: pd.DataFrame({"a": 1}, index=list(range(2))).dtypes
Out[361]: 
a    int64
dtype: object 

请注意,当创建数组时,Numpy 将选择依赖于平台的类型。以下将在 32 位平台上导致int32

In [362]: frame = pd.DataFrame(np.array([1, 2])) 

向上转换

当与其他类型组合时,类型可能会向上转换,这意味着它们从当前类型(例如intfloat)提升。

In [363]: df3 = df1.reindex_like(df2).fillna(value=0.0) + df2

In [364]: df3
Out[364]: 
 A         B      C
0  1.047606  0.256090   26.0
1  3.497968  1.426469   86.0
2 -0.150862 -0.416203   46.0
3  0.724370  1.139976  212.0
4 -1.203098 -1.193477   26.0
5  1.346426  0.096706    7.0
6 -0.052599 -1.956850  184.0
7 -0.756495 -0.714337  206.0

In [365]: df3.dtypes
Out[365]: 
A    float32
B    float64
C    float64
dtype: object 

DataFrame.to_numpy()将返回较低的公共分母,意味着可以容纳结果同质化的 NumPy 数组中的所有类型的数据类型。这可能会导致一些向上转换

In [366]: df3.to_numpy().dtype
Out[366]: dtype('float64') 

astype

您可以使用astype()方法显式地将 dtype 从一种转换为另一种。即使 dtype 未更改,它们默认也会返回一个副本(传递copy=False以更改此行为)。此外,如果 astype 操作无效,它们将引发异常。

向上转型始终遵循NumPy规则。如果操作涉及两种不同的 dtype,则将使用更通用的 dtype 作为操作的结果。

In [367]: df3
Out[367]: 
 A         B      C
0  1.047606  0.256090   26.0
1  3.497968  1.426469   86.0
2 -0.150862 -0.416203   46.0
3  0.724370  1.139976  212.0
4 -1.203098 -1.193477   26.0
5  1.346426  0.096706    7.0
6 -0.052599 -1.956850  184.0
7 -0.756495 -0.714337  206.0

In [368]: df3.dtypes
Out[368]: 
A    float32
B    float64
C    float64
dtype: object

# conversion of dtypes
In [369]: df3.astype("float32").dtypes
Out[369]: 
A    float32
B    float32
C    float32
dtype: object 

使用astype()将一部分列转换为指定类型。

In [370]: dft = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]})

In [371]: dft[["a", "b"]] = dft[["a", "b"]].astype(np.uint8)

In [372]: dft
Out[372]: 
 a  b  c
0  1  4  7
1  2  5  8
2  3  6  9

In [373]: dft.dtypes
Out[373]: 
a    uint8
b    uint8
c    int64
dtype: object 

通过将字典传递给astype(),将某些列转换为特定的 dtype。

In [374]: dft1 = pd.DataFrame({"a": [1, 0, 1], "b": [4, 5, 6], "c": [7, 8, 9]})

In [375]: dft1 = dft1.astype({"a": np.bool_, "c": np.float64})

In [376]: dft1
Out[376]: 
 a  b    c
0   True  4  7.0
1  False  5  8.0
2   True  6  9.0

In [377]: dft1.dtypes
Out[377]: 
a       bool
b      int64
c    float64
dtype: object 

注意

当尝试使用astype()loc()将一部分列转换为指定类型时,会发生向上转型。

loc()尝试适应我们分配给当前 dtype 的内容,而[]将覆盖它们,从右侧获取 dtype。因此,以下代码片段会产生意外结果。

In [378]: dft = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]})

In [379]: dft.loc[:, ["a", "b"]].astype(np.uint8).dtypes
Out[379]: 
a    uint8
b    uint8
dtype: object

In [380]: dft.loc[:, ["a", "b"]] = dft.loc[:, ["a", "b"]].astype(np.uint8)

In [381]: dft.dtypes
Out[381]: 
a    int64
b    int64
c    int64
dtype: object 

对象转换

pandas 提供各种函数,尝试强制将类型从object dtype 转换为其他类型。在数据已经是正确类型但存储在object数组中的情况下,可以使用DataFrame.infer_objects()Series.infer_objects()方法进行软转换为正确类型。

In [382]: import datetime

In [383]: df = pd.DataFrame(
 .....:    [
 .....:        [1, 2],
 .....:        ["a", "b"],
 .....:        [datetime.datetime(2016, 3, 2), datetime.datetime(2016, 3, 2)],
 .....:    ]
 .....: )
 .....: 

In [384]: df = df.T

In [385]: df
Out[385]: 
 0  1                    2
0  1  a  2016-03-02 00:00:00
1  2  b  2016-03-02 00:00:00

In [386]: df.dtypes
Out[386]: 
0    object
1    object
2    object
dtype: object 

由于数据被转置,原始推断将所有列存储为对象,infer_objects将进行更正。

In [387]: df.infer_objects().dtypes
Out[387]: 
0             int64
1            object
2    datetime64[ns]
dtype: object 

下列函数可用于一维对象数组或标量,执行将对象硬转换为指定类型:

  • to_numeric()(转换为数值 dtype)

    In [388]: m = ["1.1", 2, 3]
    
    In [389]: pd.to_numeric(m)
    Out[389]: array([1.1, 2\. , 3\. ]) 
    
  • to_datetime()(转换为日期时间对象)

    In [390]: import datetime
    
    In [391]: m = ["2016-07-09", datetime.datetime(2016, 3, 2)]
    
    In [392]: pd.to_datetime(m)
    Out[392]: DatetimeIndex(['2016-07-09', '2016-03-02'], dtype='datetime64[ns]', freq=None) 
    
  • to_timedelta()(转换为时间增量对象)

    In [393]: m = ["5us", pd.Timedelta("1day")]
    
    In [394]: pd.to_timedelta(m)
    Out[394]: TimedeltaIndex(['0 days 00:00:00.000005', '1 days 00:00:00'], dtype='timedelta64[ns]', freq=None) 
    

要强制转换,我们可以传入一个errors参数,该参数指定 pandas 如何处理无法转换为所需数据类型或对象的元素。默认情况下,errors='raise',意味着在转换过程中遇到的任何错误都将被引发。但是,如果errors='coerce',这些错误将被忽略,pandas 将把有问题的元素转换为pd.NaT(对于日期时间和时间增量)或np.nan(对于数值)。如果您正在读取大部分为所需数据类型(例如数值、日期时间)的数据,但偶尔混有不符合规范的元素,您希望将其表示为缺失值,则这可能很有用:

In [395]: import datetime

In [396]: m = ["apple", datetime.datetime(2016, 3, 2)]

In [397]: pd.to_datetime(m, errors="coerce")
Out[397]: DatetimeIndex(['NaT', '2016-03-02'], dtype='datetime64[ns]', freq=None)

In [398]: m = ["apple", 2, 3]

In [399]: pd.to_numeric(m, errors="coerce")
Out[399]: array([nan,  2.,  3.])

In [400]: m = ["apple", pd.Timedelta("1day")]

In [401]: pd.to_timedelta(m, errors="coerce")
Out[401]: TimedeltaIndex([NaT, '1 days'], dtype='timedelta64[ns]', freq=None) 

除了对象转换,to_numeric()还提供另一个参数downcast,该参数可以将新(或已有)数值数据向下转换为较小的数据类型,从而节省内存:

In [402]: m = ["1", 2, 3]

In [403]: pd.to_numeric(m, downcast="integer")  # smallest signed int dtype
Out[403]: array([1, 2, 3], dtype=int8)

In [404]: pd.to_numeric(m, downcast="signed")  # same as 'integer'
Out[404]: array([1, 2, 3], dtype=int8)

In [405]: pd.to_numeric(m, downcast="unsigned")  # smallest unsigned int dtype
Out[405]: array([1, 2, 3], dtype=uint8)

In [406]: pd.to_numeric(m, downcast="float")  # smallest float dtype
Out[406]: array([1., 2., 3.], dtype=float32) 

由于这些方法仅适用于一维数组、列表或标量;它们不能直接用于多维对象,如 DataFrames。但是,通过apply(),我们可以高效地对每列“应用”函数:

In [407]: import datetime

In [408]: df = pd.DataFrame([["2016-07-09", datetime.datetime(2016, 3, 2)]] * 2, dtype="O")

In [409]: df
Out[409]: 
 0                    1
0  2016-07-09  2016-03-02 00:00:00
1  2016-07-09  2016-03-02 00:00:00

In [410]: df.apply(pd.to_datetime)
Out[410]: 
 0          1
0 2016-07-09 2016-03-02
1 2016-07-09 2016-03-02

In [411]: df = pd.DataFrame([["1.1", 2, 3]] * 2, dtype="O")

In [412]: df
Out[412]: 
 0  1  2
0  1.1  2  3
1  1.1  2  3

In [413]: df.apply(pd.to_numeric)
Out[413]: 
 0  1  2
0  1.1  2  3
1  1.1  2  3

In [414]: df = pd.DataFrame([["5us", pd.Timedelta("1day")]] * 2, dtype="O")

In [415]: df
Out[415]: 
 0                1
0  5us  1 days 00:00:00
1  5us  1 days 00:00:00

In [416]: df.apply(pd.to_timedelta)
Out[416]: 
 0      1
0 0 days 00:00:00.000005 1 days
1 0 days 00:00:00.000005 1 days 

注意事项

整数类型数据执行选择操作可能会轻松将数据向上转型为浮点数。在不引入nans的情况下,输入数据的数据类型将被保留。另请参阅对整数 NA 的支持。

In [417]: dfi = df3.astype("int32")

In [418]: dfi["E"] = 1

In [419]: dfi
Out[419]: 
 A  B    C  E
0  1  0   26  1
1  3  1   86  1
2  0  0   46  1
3  0  1  212  1
4 -1 -1   26  1
5  1  0    7  1
6  0 -1  184  1
7  0  0  206  1

In [420]: dfi.dtypes
Out[420]: 
A    int32
B    int32
C    int32
E    int64
dtype: object

In [421]: casted = dfi[dfi > 0]

In [422]: casted
Out[422]: 
 A    B    C  E
0  1.0  NaN   26  1
1  3.0  1.0   86  1
2  NaN  NaN   46  1
3  NaN  1.0  212  1
4  NaN  NaN   26  1
5  1.0  NaN    7  1
6  NaN  NaN  184  1
7  NaN  NaN  206  1

In [423]: casted.dtypes
Out[423]: 
A    float64
B    float64
C      int32
E      int64
dtype: object 

浮点数数据类型不会改变。

In [424]: dfa = df3.copy()

In [425]: dfa["A"] = dfa["A"].astype("float32")

In [426]: dfa.dtypes
Out[426]: 
A    float32
B    float64
C    float64
dtype: object

In [427]: casted = dfa[df2 > 0]

In [428]: casted
Out[428]: 
 A         B      C
0  1.047606  0.256090   26.0
1  3.497968  1.426469   86.0
2       NaN       NaN   46.0
3       NaN  1.139976  212.0
4       NaN       NaN   26.0
5  1.346426  0.096706    7.0
6       NaN       NaN  184.0
7       NaN       NaN  206.0

In [429]: casted.dtypes
Out[429]: 
A    float32
B    float64
C    float64
dtype: object 

默认值

默认情况下,整数类型为int64,浮点数类型为float64不受平台(32 位或 64 位)影响。以下操作将全部导致int64数据类型。

In [359]: pd.DataFrame([1, 2], columns=["a"]).dtypes
Out[359]: 
a    int64
dtype: object

In [360]: pd.DataFrame({"a": [1, 2]}).dtypes
Out[360]: 
a    int64
dtype: object

In [361]: pd.DataFrame({"a": 1}, index=list(range(2))).dtypes
Out[361]: 
a    int64
dtype: object 

请注意,当创建数组时,Numpy 将选择平台相关类型。以下操作在 32 位平台上将导致int32

In [362]: frame = pd.DataFrame(np.array([1, 2])) 

向上转型

当与其他类型组合时,类型可能会向上转型,这意味着它们从当前类型(例如int)提升为float

In [363]: df3 = df1.reindex_like(df2).fillna(value=0.0) + df2

In [364]: df3
Out[364]: 
 A         B      C
0  1.047606  0.256090   26.0
1  3.497968  1.426469   86.0
2 -0.150862 -0.416203   46.0
3  0.724370  1.139976  212.0
4 -1.203098 -1.193477   26.0
5  1.346426  0.096706    7.0
6 -0.052599 -1.956850  184.0
7 -0.756495 -0.714337  206.0

In [365]: df3.dtypes
Out[365]: 
A    float32
B    float64
C    float64
dtype: object 

DataFrame.to_numpy()将返回数据类型的最低公共分母,即可以容纳结果中所有类型的同类数据类型 NumPy 数组。这可能会强制进行一些向上转型

In [366]: df3.to_numpy().dtype
Out[366]: dtype('float64') 

astype

您可以使用astype()方法将数据类型明确转换为另一种数据类型。即使数据类型未更改,这些方法默认也会返回一个副本(如果要更改此行为,请传递copy=False)。此外,如果 astype 操作无效,它们将引发异常。

向上转型始终遵循NumPy规则。如果操作涉及两种不同的数据类型,则将使用更通用的数据类型作为操作的结果。

In [367]: df3
Out[367]: 
 A         B      C
0  1.047606  0.256090   26.0
1  3.497968  1.426469   86.0
2 -0.150862 -0.416203   46.0
3  0.724370  1.139976  212.0
4 -1.203098 -1.193477   26.0
5  1.346426  0.096706    7.0
6 -0.052599 -1.956850  184.0
7 -0.756495 -0.714337  206.0

In [368]: df3.dtypes
Out[368]: 
A    float32
B    float64
C    float64
dtype: object

# conversion of dtypes
In [369]: df3.astype("float32").dtypes
Out[369]: 
A    float32
B    float32
C    float32
dtype: object 

使用astype()将一部分列转换为指定类型。

In [370]: dft = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]})

In [371]: dft[["a", "b"]] = dft[["a", "b"]].astype(np.uint8)

In [372]: dft
Out[372]: 
 a  b  c
0  1  4  7
1  2  5  8
2  3  6  9

In [373]: dft.dtypes
Out[373]: 
a    uint8
b    uint8
c    int64
dtype: object 

通过将字典传递给astype()将某些列转换为特定数据类型。

In [374]: dft1 = pd.DataFrame({"a": [1, 0, 1], "b": [4, 5, 6], "c": [7, 8, 9]})

In [375]: dft1 = dft1.astype({"a": np.bool_, "c": np.float64})

In [376]: dft1
Out[376]: 
 a  b    c
0   True  4  7.0
1  False  5  8.0
2   True  6  9.0

In [377]: dft1.dtypes
Out[377]: 
a       bool
b      int64
c    float64
dtype: object 

注意

当尝试使用astype()loc()将一部分列转换为指定类型时,会发生向上转换。

loc() 尝试适应我们正在分配的当前数据类型,而[]将覆盖它们,从右侧获取数据类型。因此,以下代码片段会产生意外结果。

In [378]: dft = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]})

In [379]: dft.loc[:, ["a", "b"]].astype(np.uint8).dtypes
Out[379]: 
a    uint8
b    uint8
dtype: object

In [380]: dft.loc[:, ["a", "b"]] = dft.loc[:, ["a", "b"]].astype(np.uint8)

In [381]: dft.dtypes
Out[381]: 
a    int64
b    int64
c    int64
dtype: object 

对象转换

pandas 提供各种函数来尝试强制将object数据类型转换为其他类型。在数据已经是正确类型但存储在object数组中的情况下,可以使用DataFrame.infer_objects()Series.infer_objects()方法进行软转换为正确类型。

In [382]: import datetime

In [383]: df = pd.DataFrame(
 .....:    [
 .....:        [1, 2],
 .....:        ["a", "b"],
 .....:        [datetime.datetime(2016, 3, 2), datetime.datetime(2016, 3, 2)],
 .....:    ]
 .....: )
 .....: 

In [384]: df = df.T

In [385]: df
Out[385]: 
 0  1                    2
0  1  a  2016-03-02 00:00:00
1  2  b  2016-03-02 00:00:00

In [386]: df.dtypes
Out[386]: 
0    object
1    object
2    object
dtype: object 

由于数据被转置,原始推断将所有列存储为对象,infer_objects���进行更正。

In [387]: df.infer_objects().dtypes
Out[387]: 
0             int64
1            object
2    datetime64[ns]
dtype: object 

以下函数可用于一维对象数组或标量,以执行将对象硬转换为指定类型:

  • to_numeric()(转换为数值数据类型)

    In [388]: m = ["1.1", 2, 3]
    
    In [389]: pd.to_numeric(m)
    Out[389]: array([1.1, 2\. , 3\. ]) 
    
  • to_datetime()(转换为日期时间对象)

    In [390]: import datetime
    
    In [391]: m = ["2016-07-09", datetime.datetime(2016, 3, 2)]
    
    In [392]: pd.to_datetime(m)
    Out[392]: DatetimeIndex(['2016-07-09', '2016-03-02'], dtype='datetime64[ns]', freq=None) 
    
  • to_timedelta()(转换为时间间隔对象)

    In [393]: m = ["5us", pd.Timedelta("1day")]
    
    In [394]: pd.to_timedelta(m)
    Out[394]: TimedeltaIndex(['0 days 00:00:00.000005', '1 days 00:00:00'], dtype='timedelta64[ns]', freq=None) 
    

要强制转换,我们可以传入一个errors参数,指定 pandas 如何处理无法转换为所需数据类型或对象的元素。默认情况下,errors='raise',意味着在转换过程中遇到任何错误都将被引发。但是,如果errors='coerce',这些错误将被忽略,pandas 将把有问题的元素转换为pd.NaT(对于日期时间和时间间隔)或np.nan(对于数值)。如果您正在读取大部分为所需数据类型(例如数值、日期时间)的数据,但偶尔混合有不符合规范的元素,您希望将其表示为缺失值,则这可能很有用:

In [395]: import datetime

In [396]: m = ["apple", datetime.datetime(2016, 3, 2)]

In [397]: pd.to_datetime(m, errors="coerce")
Out[397]: DatetimeIndex(['NaT', '2016-03-02'], dtype='datetime64[ns]', freq=None)

In [398]: m = ["apple", 2, 3]

In [399]: pd.to_numeric(m, errors="coerce")
Out[399]: array([nan,  2.,  3.])

In [400]: m = ["apple", pd.Timedelta("1day")]

In [401]: pd.to_timedelta(m, errors="coerce")
Out[401]: TimedeltaIndex([NaT, '1 days'], dtype='timedelta64[ns]', freq=None) 

除了对象转换外,to_numeric()还提供另一个参数downcast,该参数可以选择将新的(或已有的)数值数据向下转换为较小的数据类型,从而节省内存:

In [402]: m = ["1", 2, 3]

In [403]: pd.to_numeric(m, downcast="integer")  # smallest signed int dtype
Out[403]: array([1, 2, 3], dtype=int8)

In [404]: pd.to_numeric(m, downcast="signed")  # same as 'integer'
Out[404]: array([1, 2, 3], dtype=int8)

In [405]: pd.to_numeric(m, downcast="unsigned")  # smallest unsigned int dtype
Out[405]: array([1, 2, 3], dtype=uint8)

In [406]: pd.to_numeric(m, downcast="float")  # smallest float dtype
Out[406]: array([1., 2., 3.], dtype=float32) 

由于这些方法仅适用于一维数组、列表或标量;不能直接用于诸如数据框之类的多维对象。但是,通过apply(),我们可以高效地“应用”函数到每一列:

In [407]: import datetime

In [408]: df = pd.DataFrame([["2016-07-09", datetime.datetime(2016, 3, 2)]] * 2, dtype="O")

In [409]: df
Out[409]: 
 0                    1
0  2016-07-09  2016-03-02 00:00:00
1  2016-07-09  2016-03-02 00:00:00

In [410]: df.apply(pd.to_datetime)
Out[410]: 
 0          1
0 2016-07-09 2016-03-02
1 2016-07-09 2016-03-02

In [411]: df = pd.DataFrame([["1.1", 2, 3]] * 2, dtype="O")

In [412]: df
Out[412]: 
 0  1  2
0  1.1  2  3
1  1.1  2  3

In [413]: df.apply(pd.to_numeric)
Out[413]: 
 0  1  2
0  1.1  2  3
1  1.1  2  3

In [414]: df = pd.DataFrame([["5us", pd.Timedelta("1day")]] * 2, dtype="O")

In [415]: df
Out[415]: 
 0                1
0  5us  1 days 00:00:00
1  5us  1 days 00:00:00

In [416]: df.apply(pd.to_timedelta)
Out[416]: 
 0      1
0 0 days 00:00:00.000005 1 days
1 0 days 00:00:00.000005 1 days 

注意事项

integer类型数据执行选择操作可以轻松地将数据向上转换为floating。在不引入nans的情况下,输入数据的数据类型将被保留。另请参阅对整数 NA 的支持。

In [417]: dfi = df3.astype("int32")

In [418]: dfi["E"] = 1

In [419]: dfi
Out[419]: 
 A  B    C  E
0  1  0   26  1
1  3  1   86  1
2  0  0   46  1
3  0  1  212  1
4 -1 -1   26  1
5  1  0    7  1
6  0 -1  184  1
7  0  0  206  1

In [420]: dfi.dtypes
Out[420]: 
A    int32
B    int32
C    int32
E    int64
dtype: object

In [421]: casted = dfi[dfi > 0]

In [422]: casted
Out[422]: 
 A    B    C  E
0  1.0  NaN   26  1
1  3.0  1.0   86  1
2  NaN  NaN   46  1
3  NaN  1.0  212  1
4  NaN  NaN   26  1
5  1.0  NaN    7  1
6  NaN  NaN  184  1
7  NaN  NaN  206  1

In [423]: casted.dtypes
Out[423]: 
A    float64
B    float64
C      int32
E      int64
dtype: object 

浮点数数据类型保持不变。

In [424]: dfa = df3.copy()

In [425]: dfa["A"] = dfa["A"].astype("float32")

In [426]: dfa.dtypes
Out[426]: 
A    float32
B    float64
C    float64
dtype: object

In [427]: casted = dfa[df2 > 0]

In [428]: casted
Out[428]: 
 A         B      C
0  1.047606  0.256090   26.0
1  3.497968  1.426469   86.0
2       NaN       NaN   46.0
3       NaN  1.139976  212.0
4       NaN       NaN   26.0
5  1.346426  0.096706    7.0
6       NaN       NaN  184.0
7       NaN       NaN  206.0

In [429]: casted.dtypes
Out[429]: 
A    float32
B    float64
C    float64
dtype: object 

基于dtype选择列

select_dtypes()方法实现了基于dtype的列子集。

首先,让我们创建一个具有各种不同数据类型的DataFrame

In [430]: df = pd.DataFrame(
 .....:    {
 .....:        "string": list("abc"),
 .....:        "int64": list(range(1, 4)),
 .....:        "uint8": np.arange(3, 6).astype("u1"),
 .....:        "float64": np.arange(4.0, 7.0),
 .....:        "bool1": [True, False, True],
 .....:        "bool2": [False, True, False],
 .....:        "dates": pd.date_range("now", periods=3),
 .....:        "category": pd.Series(list("ABC")).astype("category"),
 .....:    }
 .....: )
 .....: 

In [431]: df["tdeltas"] = df.dates.diff()

In [432]: df["uint64"] = np.arange(3, 6).astype("u8")

In [433]: df["other_dates"] = pd.date_range("20130101", periods=3)

In [434]: df["tz_aware_dates"] = pd.date_range("20130101", periods=3, tz="US/Eastern")

In [435]: df
Out[435]: 
 string  int64  uint8  ...  uint64  other_dates            tz_aware_dates
0      a      1      3  ...       3   2013-01-01 2013-01-01 00:00:00-05:00
1      b      2      4  ...       4   2013-01-02 2013-01-02 00:00:00-05:00
2      c      3      5  ...       5   2013-01-03 2013-01-03 00:00:00-05:00

[3 rows x 12 columns] 

并且数据类型:

In [436]: df.dtypes
Out[436]: 
string                                object
int64                                  int64
uint8                                  uint8
float64                              float64
bool1                                   bool
bool2                                   bool
dates                         datetime64[ns]
category                            category
tdeltas                      timedelta64[ns]
uint64                                uint64
other_dates                   datetime64[ns]
tz_aware_dates    datetime64[ns, US/Eastern]
dtype: object 

select_dtypes()有两个参数includeexclude,允许你说“给我这些数据类型的列”(include)和/或“给我不包含这些数据类型的列”(exclude)。

例如,要选择bool列:

In [437]: df.select_dtypes(include=[bool])
Out[437]: 
 bool1  bool2
0   True  False
1  False   True
2   True  False 

你也可以在NumPy 数据类型层次结构中传递数据类型的名称:

In [438]: df.select_dtypes(include=["bool"])
Out[438]: 
 bool1  bool2
0   True  False
1  False   True
2   True  False 

select_dtypes()也适用于通用数据类型。

例如,要选择所有数值和布尔列,同时排除无符号整数:

In [439]: df.select_dtypes(include=["number", "bool"], exclude=["unsignedinteger"])
Out[439]: 
 int64  float64  bool1  bool2 tdeltas
0      1      4.0   True  False     NaT
1      2      5.0  False   True  1 days
2      3      6.0   True  False  1 days 

要选择字符串列,必须使用object数据类型:

In [440]: df.select_dtypes(include=["object"])
Out[440]: 
 string
0      a
1      b
2      c 

要查看numpy.number等通用dtype的所有子数据类型,可以定义一个返回子数据类型树的函数:

In [441]: def subdtypes(dtype):
 .....:    subs = dtype.__subclasses__()
 .....:    if not subs:
 .....:        return dtype
 .....:    return [dtype, [subdtypes(dt) for dt in subs]]
 .....: 

所有 NumPy 数据类型都是numpy.generic的子类:

In [442]: subdtypes(np.generic)
Out[442]: 
[numpy.generic,
 [[numpy.number,
 [[numpy.integer,
 [[numpy.signedinteger,
 [numpy.int8,
 numpy.int16,
 numpy.int32,
 numpy.int64,
 numpy.longlong,
 numpy.timedelta64]],
 [numpy.unsignedinteger,
 [numpy.uint8,
 numpy.uint16,
 numpy.uint32,
 numpy.uint64,
 numpy.ulonglong]]]],
 [numpy.inexact,
 [[numpy.floating,
 [numpy.float16, numpy.float32, numpy.float64, numpy.longdouble]],
 [numpy.complexfloating,
 [numpy.complex64, numpy.complex128, numpy.clongdouble]]]]]],
 [numpy.flexible,
 [[numpy.character, [numpy.bytes_, numpy.str_]],
 [numpy.void, [numpy.record]]]],
 numpy.bool_,
 numpy.datetime64,
 numpy.object_]] 

注意

pandas 还定义了categorydatetime64[ns, tz]类型,它们没有集成到正常的 NumPy 层次结构中,并且不会显示在上述函数中。文章来源地址https://www.toymoban.com/news/detail-859508.html

到了这里,关于Pandas 2.2 中文官方教程和指南(九·三)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [黑马程序员Pandas教程]——Pandas快速体验

    目录: 为什么要使用Python做数据开发 Python在数据开发领域的优势 为什么要学习Pandas 其他常用Python库介绍 主要内容介绍 Anaconda安装 Anaconda的虚拟环境管理 虚拟环境的作用 可以通过Anaconda界面创建虚拟环境 通过命令行创建虚拟环境 通过Anaconda管理界面安装包 也可以通过anac

    2024年02月06日
    浏览(49)
  • 使用Pandas进行数据处理和分析的入门指南

    摘要:本文将介绍如何使用Python的Pandas库进行数据处理和分析,包括数据导入、数据清洗、数据转换和简单分析等方面的内容。 在数据科学和数据分析领域,数据处理是一个关键的步骤。Python的Pandas库提供了强大且易于使用的工具,使数据处理变得简单和高效。本文将引导您

    2024年02月10日
    浏览(76)
  • NumPy 和 Pandas 数据分析实用指南:1~6 全

    原文:Hands-On Data Analysis with NumPy and pandas 协议:CC BY-NC-SA 4.0 译者:飞龙 在本章中,我们将介绍以下主题: 安装 Anaconda 探索 Jupyter 笔记本 探索 Jupyter 的替代品 管理 Anaconda 包 配置数据库 在本章中,我们将讨论如何安装和管理 Anaconda。 Anaconda 是一个包,我们将在本书的以下各

    2023年04月14日
    浏览(77)
  • 【人工智能技术专题】「入门到精通系列教程」零基础带你进军人工智能领域的全流程技术体系和实战指南(LLM、AGI和AIGC都是什么)

    人工智能是一个庞大的研究领域。虽然我们已经在人工智能的理论研究和算法开发方面取得了一定的进展,但是我们目前掌握的能力仍然非常有限。机器学习是人工智能的一个重要领域,它研究计算机如何模拟或实现人类的学习行为,以获取新的知识或技能,并通过重新组织

    2024年02月13日
    浏览(71)
  • Pandas 简单入门教程

    什么是Pandas? Pandas是一个开源的Python数据分析库,它提供了快速、灵活、易于使用的数据结构,旨在使数据清洗和分析变得简单快捷。 安装Pandas 你可以使用以下命令来安装Pandas: 导入Pandas 要使用Pandas,你需要将其导入到Python环境中: 数据结构 Pandas提供了两种数据结构: Se

    2023年04月20日
    浏览(43)
  • Pandas 安装与教程

    Pandas 是 Python 语言的一个扩展程序库,用于数据分析。 Pandas 是一个开放源码、BSD 许可的库,提供高性能、易于使用的数据结构和数据分析工具。 Pandas 名字衍生自术语 \\\"panel data\\\"(面板数据)和 \\\"Python data analysis\\\"(Python 数据分析)。 Pandas 一个强大的分析结构化数据的工具集

    2023年04月08日
    浏览(44)
  • Pandas库使用教程

    Pandas Pandas是一个强大的Python库,用于数据处理和分析,它提供了灵活的数据结构和数据操作功能,非常适合处理各种数据源,如CSV文件、Excel表格、SQL数据库等。 目录 介绍 安装 基本数据结构 Series DataFrame 数据读取与写入 读取csv、excel等文件数据 写入csv、excel等文件数据 数

    2024年02月09日
    浏览(23)
  • 5 | Pandas日期操作教程

    在数据分析和数据科学的领域中,经常会遇到时间序列数据。Pandas是Python中非常强大的数据处理库,提供了许多方便的日期操作和处理工具,用于处理时间序列数据。在本教程中,我们将介绍Pandas中常见的日期操作和处理方法,帮助您更好地理解和分析时间序列数据。

    2024年02月16日
    浏览(61)
  • Pycharm安装Sklearn、Pandas库保姆级教程

    第一步:进入开始菜单栏下的Anconda Prompt界面 第二步:进入pytorch环境,代码如下:  conda activate pytorch 第三步:输入conda list 可以查看是否安装Sklearn库和Pandas库  该环境下目前不存在Sklearn库和Pandas库  第四步:安装Sklearn库,代码如下: pip install scikit-learn -i https://pypi.tuna.ts

    2023年04月12日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包