Pandas 2.2 中文官方教程和指南(十五)

2024-04-25 19:54:15 浏览数 (2)

原文:pandas.pydata.org/docs/

处理文本数据

原文:pandas.pydata.org/docs/user_guide/text.html

文本数据类型

在 pandas 中有两种存储文本数据的方式:

  1. object -dtype NumPy 数组。
  2. StringDtype 扩展类型。

我们建议使用StringDtype来存储文本数据。

在 pandas 1.0 之前,object dtype 是唯一的选项。这在很多方面都是不幸的:

  1. 你可能会在object dtype 数组中意外存储字符串和非字符串的混合。最好有一个专用的 dtype。
  2. object dtype 会破坏 dtype 特定的操作,比如DataFrame.select_dtypes()。没有明确的方法可以仅选择文本而排除非文本但仍为 object-dtype 的列。
  3. 在阅读代码时,object dtype 数组的内容比'string'不够清晰。

目前,字符串和arrays.StringArrayobject dtype 数组的性能大致相同。我们期待未来的增强将显著提高StringArray的性能并降低内存开销。

警告

StringArray 目前被视为实验性质。实现和部分 API 可能会在没有警告的情况下发生变化。

为了向后兼容,我们仍然将object dtype 作为我们推断字符串列表的默认类型。

代码语言:javascript复制
In [1]: pd.Series(["a", "b", "c"])
Out[1]: 
0    a
1    b
2    c
dtype: object 

要明确请求string dtype,请指定dtype

代码语言:javascript复制
In [2]: pd.Series(["a", "b", "c"], dtype="string")
Out[2]: 
0    a
1    b
2    c
dtype: string

In [3]: pd.Series(["a", "b", "c"], dtype=pd.StringDtype())
Out[3]: 
0    a
1    b
2    c
dtype: string 

或在创建SeriesDataFrame之后进行astype

代码语言:javascript复制
In [4]: s = pd.Series(["a", "b", "c"])

In [5]: s
Out[5]: 
0    a
1    b
2    c
dtype: object

In [6]: s.astype("string")
Out[6]: 
0    a
1    b
2    c
dtype: string 

你也可以在非字符串数据上使用StringDtype/"string"作为 dtype,并将其转换为string dtype:

代码语言:javascript复制
In [7]: s = pd.Series(["a", 2, np.nan], dtype="string")

In [8]: s
Out[8]: 
0       a
1       2
2    <NA>
dtype: string

In [9]: type(s[1])
Out[9]: str 

或者从现有的 pandas 数据中转换:

代码语言:javascript复制
In [10]: s1 = pd.Series([1, 2, np.nan], dtype="Int64")

In [11]: s1
Out[11]: 
0       1
1       2
2    <NA>
dtype: Int64

In [12]: s2 = s1.astype("string")

In [13]: s2
Out[13]: 
0       1
1       2
2    <NA>
dtype: string

In [14]: type(s2[0])
Out[14]: str 
行为差异

这些是StringDtype对象与object dtype 不同的地方

对于 StringDtype,返回数字输出的 string 访问器方法将始终返回可空整数 dtype,而不是根据 NA 值的存在返回 int 或 float dtype。返回布尔值输出的方法将返回可空布尔 dtype。

代码语言:javascript复制
In [15]: s = pd.Series(["a", None, "b"], dtype="string")

In [16]: s
Out[16]: 
0       a
1    <NA>
2       b
dtype: string

In [17]: s.str.count("a")
Out[17]: 
0       1
1    <NA>
2       0
dtype: Int64

In [18]: s.dropna().str.count("a")
Out[18]: 
0    1
2    0
dtype: Int64 

两个输出都是Int64 dtype。与 object-dtype 进行比较

代码语言:javascript复制
In [19]: s2 = pd.Series(["a", None, "b"], dtype="object")

In [20]: s2.str.count("a")
Out[20]: 
0    1.0
1    NaN
2    0.0
dtype: float64

In [21]: s2.dropna().str.count("a")
Out[21]: 
0    1
2    0
dtype: int64 

当存在 NA 值时,输出 dtype 为 float64。对于返回布尔值的方法也是如此。

代码语言:javascript复制
In [22]: s.str.isdigit()
Out[22]: 
0    False
1     <NA>
2    False
dtype: boolean

In [23]: s.str.match("a")
Out[23]: 
0     True
1     <NA>
2    False
dtype: boolean 

一些字符串方法,比如Series.str.decode()StringArray上不可用,因为StringArray只保存字符串,而不是字节。

在比较操作中,arrays.StringArray和由StringArray支持的Series将返回一个具有BooleanDtype的对象,而不是bool dtype 对象。在StringArray中的缺失值将在比较操作中传播,而不总是像numpy.nan那样比较不相等。

本文档其余部分中的所有内容同样适用于stringobject dtype。 ## 字符串方法

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

代码语言:javascript复制
In [24]: s = pd.Series(
 ....:    ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
 ....: )
 ....: 

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

In [26]: s.str.upper()
Out[26]: 
0       A
1       B
2       C
3    AABA
4    BACA
5    <NA>
6    CABA
7     DOG
8     CAT
dtype: string

In [27]: s.str.len()
Out[27]: 
0       1
1       1
2       1
3       4
4       4
5    <NA>
6       4
7       3
8       3
dtype: Int64 
代码语言:javascript复制
In [28]: idx = pd.Index([" jack", "jill ", " jesse ", "frank"])

In [29]: idx.str.strip()
Out[29]: Index(['jack', 'jill', 'jesse', 'frank'], dtype='object')

In [30]: idx.str.lstrip()
Out[30]: Index(['jack', 'jill ', 'jesse ', 'frank'], dtype='object')

In [31]: idx.str.rstrip()
Out[31]: Index([' jack', 'jill', ' jesse', 'frank'], dtype='object') 

Index 上的字符串方法特别适用于清理或转换 DataFrame 列。例如,您可能有带有前导或尾随空格的列:

代码语言:javascript复制
In [32]: df = pd.DataFrame(
 ....:    np.random.randn(3, 2), columns=[" Column A ", " Column B "], index=range(3)
 ....: )
 ....: 

In [33]: df
Out[33]: 
 Column A   Column B 
0   0.469112  -0.282863
1  -1.509059  -1.135632
2   1.212112  -0.173215 

由于df.columns是一个 Index 对象,我们可以使用.str访问器

代码语言:javascript复制
In [34]: df.columns.str.strip()
Out[34]: Index(['Column A', 'Column B'], dtype='object')

In [35]: df.columns.str.lower()
Out[35]: Index([' column a ', ' column b '], dtype='object') 

然后可以使用这些字符串方法根据需要清理列。在这里,我们删除前导和尾随空格,将所有名称转换为小写,并用下划线替换任何剩余的空格:

代码语言:javascript复制
In [36]: df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_")

In [37]: df
Out[37]: 
 column_a  column_b
0  0.469112 -0.282863
1 -1.509059 -1.135632
2  1.212112 -0.173215 

注意

如果您有一个Series,其中许多元素重复(即Series中的唯一元素数量远小于Series的长度),将原始Series转换为category类型之后,使用.str.<method>.dt.<property>可能更快。性能差异来自于category类型的Series上的字符串操作是在.categories上执行的,而不是在Series的每个元素上执行。

请注意,具有字符串.categoriescategory类型Series与字符串类型的Series相比存在一些限制(例如,如果scategory类型的Series,则无法将字符串相加:s " " s不起作用)。此外,对于这样的Series,不可用于操作list类型元素的.str方法。

警告

Series 的类型是推断的,并且允许的类型(即字符串)。

一般来说,.str访问器仅用于字符串。除了极少数例外情况外,不支持其他用途,并且可能在以后被禁用。 ## 拆分和替换字符串

split这样的方法返回一个列表的 Series:

代码语言:javascript复制
In [38]: s2 = pd.Series(["a_b_c", "c_d_e", np.nan, "f_g_h"], dtype="string")

In [39]: s2.str.split("_")
Out[39]: 
0    [a, b, c]
1    [c, d, e]
2         <NA>
3    [f, g, h]
dtype: object 

可以使用get[]符号访问拆分列表中的元素:

代码语言:javascript复制
In [40]: s2.str.split("_").str.get(1)
Out[40]: 
0       b
1       d
2    <NA>
3       g
dtype: object

In [41]: s2.str.split("_").str[1]
Out[41]: 
0       b
1       d
2    <NA>
3       g
dtype: object 

可以轻松扩展此操作以使用expand返回 DataFrame。

代码语言:javascript复制
In [42]: s2.str.split("_", expand=True)
Out[42]: 
 0     1     2
0     a     b     c
1     c     d     e
2  <NA>  <NA>  <NA>
3     f     g     h 

当原始Series具有StringDtype时,输出列也将全部是StringDtype

也可以限制拆分的数量:

代码语言:javascript复制
In [43]: s2.str.split("_", expand=True, n=1)
Out[43]: 
 0     1
0     a   b_c
1     c   d_e
2  <NA>  <NA>
3     f   g_h 

rsplit类似于split,只是它是从字符串末尾到字符串开头的方向进行操作:

代码语言:javascript复制
In [44]: s2.str.rsplit("_", expand=True, n=1)
Out[44]: 
 0     1
0   a_b     c
1   c_d     e
2  <NA>  <NA>
3   f_g     h 

replace方法可以选择使用正则表达式:

代码语言:javascript复制
In [45]: s3 = pd.Series(
 ....:    ["A", "B", "C", "Aaba", "Baca", "", np.nan, "CABA", "dog", "cat"],
 ....:    dtype="string",
 ....: )
 ....: 

In [46]: s3
Out[46]: 
0       A
1       B
2       C
3    Aaba
4    Baca
5 
6    <NA>
7    CABA
8     dog
9     cat
dtype: string

In [47]: s3.str.replace("^.a|dog", "XX-XX ", case=False, regex=True)
Out[47]: 
0           A
1           B
2           C
3    XX-XX ba
4    XX-XX ca
5 
6        <NA>
7    XX-XX BA
8      XX-XX 
9     XX-XX t
dtype: string 

在 2.0 版本中更改。

使用regex=True的单个字符模式也将被视为正则表达式:

代码语言:javascript复制
In [48]: s4 = pd.Series(["a.b", ".", "b", np.nan, ""], dtype="string")

In [49]: s4
Out[49]: 
0     a.b
1       .
2       b
3    <NA>
4 
dtype: string

In [50]: s4.str.replace(".", "a", regex=True)
Out[50]: 
0     aaa
1       a
2       a
3    <NA>
4 
dtype: string 

如果您想要对字符串进行字面替换(相当于str.replace()),您可以将可选的regex参数设置为False,而不是转义每个字符。在这种情况下,patrepl都必须是字符串:

代码语言:javascript复制
In [51]: dollars = pd.Series(["12", "-$10", "$10,000"], dtype="string")

# These lines are equivalent
In [52]: dollars.str.replace(r"-$", "-", regex=True)
Out[52]: 
0         12
1        -10
2    $10,000
dtype: string

In [53]: dollars.str.replace("-$", "-", regex=False)
Out[53]: 
0         12
1        -10
2    $10,000
dtype: string 

replace方法还可以接受一个可调用对象作为替换。它会对每个pat使用re.sub()进行调用。可调用对象应该期望一个位置参数(一个正则表达式对象)并返回一个字符串。

代码语言:javascript复制
# Reverse every lowercase alphabetic word
In [54]: pat = r"[a-z] "

In [55]: def repl(m):
 ....:    return m.group(0)[::-1]
 ....: 

In [56]: pd.Series(["foo 123", "bar baz", np.nan], dtype="string").str.replace(
 ....:    pat, repl, regex=True
 ....: )
 ....: 
Out[56]: 
0    oof 123
1    rab zab
2       <NA>
dtype: string

# Using regex groups
In [57]: pat = r"(?P<one>w ) (?P<two>w ) (?P<three>w )"

In [58]: def repl(m):
 ....:    return m.group("two").swapcase()
 ....: 

In [59]: pd.Series(["Foo Bar Baz", np.nan], dtype="string").str.replace(
 ....:    pat, repl, regex=True
 ....: )
 ....: 
Out[59]: 
0     bAR
1    <NA>
dtype: string 

replace方法还接受来自re.compile()的编译的正则表达式对象作为模式。所有标志应包含在编译的正则表达式对象中。

代码语言:javascript复制
In [60]: import re

In [61]: regex_pat = re.compile(r"^.a|dog", flags=re.IGNORECASE)

In [62]: s3.str.replace(regex_pat, "XX-XX ", regex=True)
Out[62]: 
0           A
1           B
2           C
3    XX-XX ba
4    XX-XX ca
5 
6        <NA>
7    XX-XX BA
8      XX-XX 
9     XX-XX t
dtype: string 

在调用带有编译的正则表达式对象的replace时包含一个flags参数将引发ValueError

代码语言:javascript复制
In [63]: s3.str.replace(regex_pat, 'XX-XX ', flags=re.IGNORECASE)
---------------------------------------------------------------------------
ValueError: case and flags cannot be set when pat is a compiled regex 

removeprefixremovesuffix与 Python 3.9 中添加的str.removeprefixstr.removesuffix具有相同的效果 <docs.python.org/3/library/stdtypes.html#str.removeprefix>`__:

在 1.4.0 版本中新增。

代码语言:javascript复制
In [64]: s = pd.Series(["str_foo", "str_bar", "no_prefix"])

In [65]: s.str.removeprefix("str_")
Out[65]: 
0          foo
1          bar
2    no_prefix
dtype: object

In [66]: s = pd.Series(["foo_str", "bar_str", "no_suffix"])

In [67]: s.str.removesuffix("_str")
Out[67]: 
0          foo
1          bar
2    no_suffix
dtype: object 
```## 连接

有几种方法可以连接`Series`或`Index`,可以是与自身或其他对象连接,都基于`cat()`,或者`Index.str.cat`。

### 将单个 Series 连接成字符串

`Series`(或`Index`)的内容可以进行连接:

```py
In [68]: s = pd.Series(["a", "b", "c", "d"], dtype="string")

In [69]: s.str.cat(sep=",")
Out[69]: 'a,b,c,d' 

如果未指定,用于分隔符的关键字sep默认为空字符串,sep=''

代码语言:javascript复制
In [70]: s.str.cat()
Out[70]: 'abcd' 

默认情况下,会忽略缺失值。使用na_rep,可以为缺失值指定一个表示:

代码语言:javascript复制
In [71]: t = pd.Series(["a", "b", np.nan, "d"], dtype="string")

In [72]: t.str.cat(sep=",")
Out[72]: 'a,b,d'

In [73]: t.str.cat(sep=",", na_rep="-")
Out[73]: 'a,b,-,d' 
将一个 Series 和类似列表的东西连接成一个 Series

cat()的第一个参数可以是类似列表的对象,只要它与调用的Series(或Index)的长度匹配即可。

代码语言:javascript复制
In [74]: s.str.cat(["A", "B", "C", "D"])
Out[74]: 
0    aA
1    bB
2    cC
3    dD
dtype: string 

任一侧存在缺失值都会导致结果中也存在缺失值,除非指定了na_rep

代码语言:javascript复制
In [75]: s.str.cat(t)
Out[75]: 
0      aa
1      bb
2    <NA>
3      dd
dtype: string

In [76]: s.str.cat(t, na_rep="-")
Out[76]: 
0    aa
1    bb
2    c-
3    dd
dtype: string 
将一个 Series 和类似数组的东西连接成一个 Series

参数others也可以是二维的。在这种情况下,行数必须与调用的Series(或Index)的长度匹配。

代码语言:javascript复制
In [77]: d = pd.concat([t, s], axis=1)

In [78]: s
Out[78]: 
0    a
1    b
2    c
3    d
dtype: string

In [79]: d
Out[79]: 
 0  1
0     a  a
1     b  b
2  <NA>  c
3     d  d

In [80]: s.str.cat(d, na_rep="-")
Out[80]: 
0    aaa
1    bbb
2    c-c
3    ddd
dtype: string 
将一个 Series 和一个带索引的对象连接成一个 Series,并进行对齐

对于与SeriesDataFrame连接,可以通过设置join关键字来在连接之前对齐索引。

代码语言:javascript复制
In [81]: u = pd.Series(["b", "d", "a", "c"], index=[1, 3, 0, 2], dtype="string")

In [82]: s
Out[82]: 
0    a
1    b
2    c
3    d
dtype: string

In [83]: u
Out[83]: 
1    b
3    d
0    a
2    c
dtype: string

In [84]: s.str.cat(u)
Out[84]: 
0    aa
1    bb
2    cc
3    dd
dtype: string

In [85]: s.str.cat(u, join="left")
Out[85]: 
0    aa
1    bb
2    cc
3    dd
dtype: string 

对于join,可以使用常规选项之一('left', 'outer', 'inner', 'right')。特别是,对齐也意味着不同长度不再需要一致。

代码语言:javascript复制
In [86]: v = pd.Series(["z", "a", "b", "d", "e"], index=[-1, 0, 1, 3, 4], dtype="string")

In [87]: s
Out[87]: 
0    a
1    b
2    c
3    d
dtype: string

In [88]: v
Out[88]: 
-1    z
 0    a
 1    b
 3    d
 4    e
dtype: string

In [89]: s.str.cat(v, join="left", na_rep="-")
Out[89]: 
0    aa
1    bb
2    c-
3    dd
dtype: string

In [90]: s.str.cat(v, join="outer", na_rep="-")
Out[90]: 
-1    -z
 0    aa
 1    bb
 2    c-
 3    dd
 4    -e
dtype: string 

others是一个DataFrame时,可以使用相同的对齐:

代码语言:javascript复制
In [91]: f = d.loc[[3, 2, 1, 0], :]

In [92]: s
Out[92]: 
0    a
1    b
2    c
3    d
dtype: string

In [93]: f
Out[93]: 
 0  1
3     d  d
2  <NA>  c
1     b  b
0     a  a

In [94]: s.str.cat(f, join="left", na_rep="-")
Out[94]: 
0    aaa
1    bbb
2    c-c
3    ddd
dtype: string 
将一个系列和许多对象连接成一个系列

几个类似数组的项目(特别是:SeriesIndexnp.ndarray的一维变体)可以组合在一个类似列表的容器中(包括迭代器、dict-视图等)。

代码语言:javascript复制
In [95]: s
Out[95]: 
0    a
1    b
2    c
3    d
dtype: string

In [96]: u
Out[96]: 
1    b
3    d
0    a
2    c
dtype: string

In [97]: s.str.cat([u, u.to_numpy()], join="left")
Out[97]: 
0    aab
1    bbd
2    cca
3    ddc
dtype: string 

传递的类似列表中没有索引的所有元素(例如np.ndarray)必须与调用的Series(或Index)的长度匹配,但SeriesIndex的长度可以是任意的(只要不使用join=None禁用对齐):

代码语言:javascript复制
In [98]: v
Out[98]: 
-1    z
 0    a
 1    b
 3    d
 4    e
dtype: string

In [99]: s.str.cat([v, u, u.to_numpy()], join="outer", na_rep="-")
Out[99]: 
-1    -z--
0     aaab
1     bbbd
2     c-ca
3     dddc
4     -e--
dtype: string 

如果在一个包含不同索引的others列表上使用join='right',这些索引的并集将被用作最终连接的基础:

代码语言:javascript复制
In [100]: u.loc[[3]]
Out[100]: 
3    d
dtype: string

In [101]: v.loc[[-1, 0]]
Out[101]: 
-1    z
 0    a
dtype: string

In [102]: s.str.cat([u.loc[[3]], v.loc[[-1, 0]]], join="right", na_rep="-")
Out[102]: 
 3    dd-
-1    --z
 0    a-a
dtype: string 

使用.str进行索引

您可以使用[]表示法直接按位置索引。如果索引超出字符串的末尾,结果将是一个NaN

代码语言:javascript复制
In [103]: s = pd.Series(
 .....:    ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
 .....: )
 .....: 

In [104]: s.str[0]
Out[104]: 
0       A
1       B
2       C
3       A
4       B
5    <NA>
6       C
7       d
8       c
dtype: string

In [105]: s.str[1]
Out[105]: 
0    <NA>
1    <NA>
2    <NA>
3       a
4       a
5    <NA>
6       A
7       o
8       a
dtype: string 

提取子字符串

提取每个主题中的第一个匹配项(extract)

extract方法接受至少一个捕获组的正则表达式。

提取具有多个组的正则表达式将返回一个每个组一列的 DataFrame。

代码语言:javascript复制
In [106]: pd.Series(
 .....:    ["a1", "b2", "c3"],
 .....:    dtype="string",
 .....: ).str.extract(r"([ab])(d)", expand=False)
 .....: 
Out[106]: 
 0     1
0     a     1
1     b     2
2  <NA>  <NA> 

不匹配的元素返回一个填充有NaN的行。因此,一系列混乱的字符串可以被“转换”为一个具有相同索引的清理或更有用的字符串的系列或DataFrame,而不需要使用get()来访问元组或re.match对象。结果的数据类型始终为对象,即使没有找到匹配项,结果仅包含NaN

命名组如

代码语言:javascript复制
In [107]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(
 .....:    r"(?P<letter>[ab])(?P<digit>d)", expand=False
 .....: )
 .....: 
Out[107]: 
 letter digit
0      a     1
1      b     2
2   <NA>  <NA> 

和可选组如

代码语言:javascript复制
In [108]: pd.Series(
 .....:    ["a1", "b2", "3"],
 .....:    dtype="string",
 .....: ).str.extract(r"([ab])?(d)", expand=False)
 .....: 
Out[108]: 
 0  1
0     a  1
1     b  2
2  <NA>  3 

也可以使用。请注意,正则表达式中的任何捕获组名称将用作列名;否则将使用捕获组编号。

使用一个组的正则表达式提取返回一个列的DataFrame,如果expand=True

代码语言:javascript复制
In [109]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"ab", expand=True)
Out[109]: 
 0
0     1
1     2
2  <NA> 

如果expand=False,则返回一个 Series。

代码语言:javascript复制
In [110]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"ab", expand=False)
Out[110]: 
0       1
1       2
2    <NA>
dtype: string 

使用正则表达式调用带有一个捕获组的Index,如果expand=True,则返回一个列的DataFrame

代码语言:javascript复制
In [111]: s = pd.Series(["a1", "b2", "c3"], ["A11", "B22", "C33"], dtype="string")

In [112]: s
Out[112]: 
A11    a1
B22    b2
C33    c3
dtype: string

In [113]: s.index.str.extract("(?P<letter>[a-zA-Z])", expand=True)
Out[113]: 
 letter
0      A
1      B
2      C 

如果expand=False,则返回一个Index

代码语言:javascript复制
In [114]: s.index.str.extract("(?P<letter>[a-zA-Z])", expand=False)
Out[114]: Index(['A', 'B', 'C'], dtype='object', name='letter') 

使用具有多个捕获组的正则表达式调用Index,如果expand=True,则返回一个DataFrame

代码语言:javascript复制
In [115]: s.index.str.extract("(?P<letter>[a-zA-Z])([0-9] )", expand=True)
Out[115]: 
 letter   1
0      A  11
1      B  22
2      C  33 

如果expand=False,则引发ValueError

代码语言:javascript复制
In [116]: s.index.str.extract("(?P<letter>[a-zA-Z])([0-9] )", expand=False)
---------------------------------------------------------------------------
ValueError  Traceback (most recent call last)
Cell In[116], line 1
----> 1 s.index.str.extract("(?P<letter>[a-zA-Z])([0-9] )", expand=False)

File ~/work/pandas/pandas/pandas/core/strings/accessor.py:137, in forbid_nonstring_types.<locals>._forbid_nonstring_types.<locals>.wrapper(self, *args, **kwargs)
  132     msg = (
  133         f"Cannot use .str.{func_name} with values of "
  134         f"inferred dtype '{self._inferred_dtype}'."
  135     )
  136     raise TypeError(msg)
--> 137 return func(self, *args, **kwargs)

File ~/work/pandas/pandas/pandas/core/strings/accessor.py:2743, in StringMethods.extract(self, pat, flags, expand)
  2740     raise ValueError("pattern contains no capture groups")
  2742 if not expand and regex.groups > 1 and isinstance(self._data, ABCIndex):
-> 2743     raise ValueError("only one regex group is supported with Index")
  2745 obj = self._data
  2746 result_dtype = _result_dtype(obj)

ValueError: only one regex group is supported with Index 

下表总结了extract(expand=False)的行为(第一列为输入主题,正则表达式中的组数为第一行)

1 组

>1 组

Index

Index

ValueError

Series

Series

DataFrame

提取每个主题中的所有匹配项(extractall)

与仅返回第一个匹配项的extract不同,

代码语言:javascript复制
In [117]: s = pd.Series(["a1a2", "b1", "c1"], index=["A", "B", "C"], dtype="string")

In [118]: s
Out[118]: 
A    a1a2
B      b1
C      c1
dtype: string

In [119]: two_groups = "(?P<letter>[a-z])(?P<digit>[0-9])"

In [120]: s.str.extract(two_groups, expand=True)
Out[120]: 
 letter digit
A      a     1
B      b     1
C      c     1 

extractall方法返回每个匹配项。extractall的结果始终是一个带有MultiIndexDataFrameMultiIndex的最后一级命名为match,表示主题中的顺序。

代码语言:javascript复制
In [121]: s.str.extractall(two_groups)
Out[121]: 
 letter digit
 match 
A 0          a     1
 1          a     2
B 0          b     1
C 0          c     1 

当系列中的每个主题字符串恰好有一个匹配时,

代码语言:javascript复制
In [122]: s = pd.Series(["a3", "b3", "c2"], dtype="string")

In [123]: s
Out[123]: 
0    a3
1    b3
2    c2
dtype: string 

然后extractall(pat).xs(0, level='match')extract(pat)给出相同的结果。

代码语言:javascript复制
In [124]: extract_result = s.str.extract(two_groups, expand=True)

In [125]: extract_result
Out[125]: 
 letter digit
0      a     3
1      b     3
2      c     2

In [126]: extractall_result = s.str.extractall(two_groups)

In [127]: extractall_result
Out[127]: 
 letter digit
 match 
0 0          a     3
1 0          b     3
2 0          c     2

In [128]: extractall_result.xs(0, level="match")
Out[128]: 
 letter digit
0      a     3
1      b     3
2      c     2 

Index还支持.str.extractall。它返回一个与具有默认索引(从 0 开始)的Series.str.extractall具有相同结果的DataFrame

代码语言:javascript复制
In [129]: pd.Index(["a1a2", "b1", "c1"]).str.extractall(two_groups)
Out[129]: 
 letter digit
 match 
0 0          a     1
 1          a     2
1 0          b     1
2 0          c     1

In [130]: pd.Series(["a1a2", "b1", "c1"], dtype="string").str.extractall(two_groups)
Out[130]: 
 letter digit
 match 
0 0          a     1
 1          a     2
1 0          b     1
2 0          c     1 

测试匹配或包含模式的字符串

您可以检查元素是否包含模式:

代码语言:javascript复制
In [131]: pattern = r"[0-9][a-z]"

In [132]: pd.Series(
 .....:    ["1", "2", "3a", "3b", "03c", "4dx"],
 .....:    dtype="string",
 .....: ).str.contains(pattern)
 .....: 
Out[132]: 
0    False
1    False
2     True
3     True
4     True
5     True
dtype: boolean 

或者元素是否匹配模式:

代码语言:javascript复制
In [133]: pd.Series(
 .....:    ["1", "2", "3a", "3b", "03c", "4dx"],
 .....:    dtype="string",
 .....: ).str.match(pattern)
 .....: 
Out[133]: 
0    False
1    False
2     True
3     True
4    False
5     True
dtype: boolean 
代码语言:javascript复制
In [134]: pd.Series(
 .....:    ["1", "2", "3a", "3b", "03c", "4dx"],
 .....:    dtype="string",
 .....: ).str.fullmatch(pattern)
 .....: 
Out[134]: 
0    False
1    False
2     True
3     True
4    False
5    False
dtype: boolean 

注意

matchfullmatchcontains之间的区别在于严格性:fullmatch测试整个字符串是否与正则表达式匹配;match测试正则表达式是否在字符串的第一个字符处匹配;contains测试字符串中是否在任何位置匹配正则表达式。

这三种匹配模式在re包中对应的函数分别是re.fullmatch,re.match和re.search。

matchfullmatchcontainsstartswithendswith等方法接受额外的na参数,因此缺失值可以被视为 True 或 False:

代码语言:javascript复制
In [135]: s4 = pd.Series(
 .....:    ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
 .....: )
 .....: 

In [136]: s4.str.contains("A", na=False)
Out[136]: 
0     True
1    False
2    False
3     True
4    False
5    False
6     True
7    False
8    False
dtype: boolean 

创建指示变量

您可以从字符串列中提取虚拟变量。例如,如果它们由'|'分隔:

代码语言:javascript复制
In [137]: s = pd.Series(["a", "a|b", np.nan, "a|c"], dtype="string")

In [138]: s.str.get_dummies(sep="|")
Out[138]: 
 a  b  c
0  1  0  0
1  1  1  0
2  0  0  0
3  1  0  1 

字符串Index还支持get_dummies,它返回一个MultiIndex

代码语言:javascript复制
In [139]: idx = pd.Index(["a", "a|b", np.nan, "a|c"])

In [140]: idx.str.get_dummies(sep="|")
Out[140]: 
MultiIndex([(1, 0, 0),
 (1, 1, 0),
 (0, 0, 0),
 (1, 0, 1)],
 names=['a', 'b', 'c']) 

另请参见get_dummies()

方法摘要

方法

描述

cat()

连接字符串

split()

使用分隔符拆分字符串

rsplit()

从字符串末尾开始使用分隔符拆分字符串

get()

索引到每个元素(检索第 i 个元素)

join()

使用传递的分隔符连接 Series 中每个元素的字符串

get_dummies()

使用分隔符拆分字符串,返回包含虚拟变量的 DataFrame

contains()

如果每个字符串包含模式/正则表达式,则返回布尔数组

replace()

用其他字符串或可调用对象的返回值替换模式/正则表达式/字符串的出现

removeprefix()

从字符串中移除前缀,即仅在字符串以前缀开头时才移除。

removesuffix()

从字符串中移除后缀,即仅在字符串以后缀结尾时才移除。

repeat()

复制值(s.str.repeat(3) 等同于 x * 3)

pad()

在字符串的左侧、右侧或两侧添加空格

center()

等同于 str.center

ljust()

等同于 str.ljust

rjust()

等同于 str.rjust

zfill()

等同于 str.zfill

wrap()

将长字符串拆分为长度小于给定宽度的行

slice()

对 Series 中的每个字符串进行切片

slice_replace()

用传递的值替换每个字符串中的切片

count()

计算模式的出现次数

startswith()

对每个元素等同于 str.startswith(pat)

endswith()

对每个元素等同于 str.endswith(pat)

findall()

计算每个字符串中模式/正则表达式的所有出现

match()

对每个元素调用 re.match,返回匹配的组列表

extract()

对每个元素调用re.search,返回一个 DataFrame,每个元素一行,每个正则表达式捕获组一列

extractall()

对每个元素调用re.findall,返回一个 DataFrame,每个匹配项一行,每个正则表达式捕获组一列

len()

计算字符串长度

strip()

等同于 str.strip

rstrip()

等同于 str.rstrip

lstrip()

等同于 str.lstrip

partition()

等同于 str.partition

rpartition()

等同于 str.rpartition

lower()

等同于 str.lower

casefold()

等同于 str.casefold

upper()

等同于 str.upper

find()

等同于 str.find

rfind()

等同于 str.rfind

index()

等同于 str.index

rindex()

等同于 str.rindex

capitalize()

等同于 str.capitalize

swapcase()

等同于 str.swapcase

normalize()

返回 Unicode 正规形式。等同于unicodedata.normalize

translate()

等同于 str.translate

isalnum()

等同于 str.isalnum

isalpha()

等同于 str.isalpha

isdigit()

等同于 str.isdigit

isspace()

等同于 str.isspace

islower()

等同于 str.islower

isupper()

等同于 str.isupper

istitle()

等同于 str.istitle

isnumeric()

等同于 str.isnumeric

isdecimal()

等同于 str.isdecimal

文本数据类型

在 pandas 中有两种存储文本数据的方式:

  1. object -dtype NumPy 数组。
  2. StringDtype 扩展类型。

我们建议使用StringDtype来存储文本数据。

在 pandas 1.0 之前,object dtype 是唯一的选择。这在很多方面都是不幸的:

  1. object dtype 数组中可能会意外存储字符串和非字符串的混合。最好使用专用的 dtype。
  2. object dtype 会破坏 dtype 特定的操作,比如DataFrame.select_dtypes()。没有明确的方法可以仅选择文本而排除非文本但仍为 object-dtype 的列。
  3. 阅读代码时,object dtype 数组的内容不如'string'清晰。

目前,object dtype 类型的字符串数组和arrays.StringArray的性能大致相同。我们期待未来的增强将显著提高StringArray的性能并降低内存开销。

警告

StringArray目前被视为实验性质。实现和部分 API 可能会在没有警告的情况下发生变化。

为了向后兼容,我们推断字符串列表的默认类型仍然是object dtype

代码语言:javascript复制
In [1]: pd.Series(["a", "b", "c"])
Out[1]: 
0    a
1    b
2    c
dtype: object 

要明确请求string dtype,请指定dtype

代码语言:javascript复制
In [2]: pd.Series(["a", "b", "c"], dtype="string")
Out[2]: 
0    a
1    b
2    c
dtype: string

In [3]: pd.Series(["a", "b", "c"], dtype=pd.StringDtype())
Out[3]: 
0    a
1    b
2    c
dtype: string 

在创建SeriesDataFrame之后使用astype

代码语言:javascript复制
In [4]: s = pd.Series(["a", "b", "c"])

In [5]: s
Out[5]: 
0    a
1    b
2    c
dtype: object

In [6]: s.astype("string")
Out[6]: 
0    a
1    b
2    c
dtype: string 

你也可以在非字符串数据上使用StringDtype/"string"作为 dtype,它将被转换为string dtype:

代码语言:javascript复制
In [7]: s = pd.Series(["a", 2, np.nan], dtype="string")

In [8]: s
Out[8]: 
0       a
1       2
2    <NA>
dtype: string

In [9]: type(s[1])
Out[9]: str 

或者从现有的 pandas 数据转换:

代码语言:javascript复制
In [10]: s1 = pd.Series([1, 2, np.nan], dtype="Int64")

In [11]: s1
Out[11]: 
0       1
1       2
2    <NA>
dtype: Int64

In [12]: s2 = s1.astype("string")

In [13]: s2
Out[13]: 
0       1
1       2
2    <NA>
dtype: string

In [14]: type(s2[0])
Out[14]: str 
行为差异

这些是StringDtype对象的行为与object dtype 不同的地方

对于StringDtype,返回numeric输出的 string 访问器方法将始终返回可空整数 dtype,而不是根据 NA 值的存在而返回 int 或 float dtype。返回boolean输出的方法将返回可空布尔 dtype。

代码语言:javascript复制
In [15]: s = pd.Series(["a", None, "b"], dtype="string")

In [16]: s
Out[16]: 
0       a
1    <NA>
2       b
dtype: string

In [17]: s.str.count("a")
Out[17]: 
0       1
1    <NA>
2       0
dtype: Int64

In [18]: s.dropna().str.count("a")
Out[18]: 
0    1
2    0
dtype: Int64 

两个输出都是Int64 dtype。与 object-dtype 进行比较

代码语言:javascript复制
In [19]: s2 = pd.Series(["a", None, "b"], dtype="object")

In [20]: s2.str.count("a")
Out[20]: 
0    1.0
1    NaN
2    0.0
dtype: float64

In [21]: s2.dropna().str.count("a")
Out[21]: 
0    1
2    0
dtype: int64 

当存在 NA 值时,输出 dtype 为 float64。返回布尔值的方法也是如此。

代码语言:javascript复制
In [22]: s.str.isdigit()
Out[22]: 
0    False
1     <NA>
2    False
dtype: boolean

In [23]: s.str.match("a")
Out[23]: 
0     True
1     <NA>
2    False
dtype: boolean 

一些字符串方法,比如Series.str.decode()StringArray上不可用,因为StringArray只保存字符串,而不是字节。

在比较操作中,arrays.StringArray和由StringArray支持的Series将返回一个带有BooleanDtype的对象,而不是bool dtype 对象。在StringArray中的缺失值将在比较操作中传播,而不像numpy.nan那样总是比较不相等。

本文档其余部分中的其他内容同样适用于stringobject dtype。### 行为差异

这些是StringDtype对象的行为与object dtype 不同的地方

对于StringDtype,返回numeric输出的 string 访问器方法将始终返回可空整数 dtype,而不是根据 NA 值的存在而返回 int 或 float dtype。返回boolean输出的方法将返回可空布尔 dtype。

代码语言:javascript复制
In [15]: s = pd.Series(["a", None, "b"], dtype="string")

In [16]: s
Out[16]: 
0       a
1    <NA>
2       b
dtype: string

In [17]: s.str.count("a")
Out[17]: 
0       1
1    <NA>
2       0
dtype: Int64

In [18]: s.dropna().str.count("a")
Out[18]: 
0    1
2    0
dtype: Int64 

两个输出都是Int64 dtype。与 object-dtype 进行比较

代码语言:javascript复制
In [19]: s2 = pd.Series(["a", None, "b"], dtype="object")

In [20]: s2.str.count("a")
Out[20]: 
0    1.0
1    NaN
2    0.0
dtype: float64

In [21]: s2.dropna().str.count("a")
Out[21]: 
0    1
2    0
dtype: int64 

当存在 NA 值时,输出 dtype 为 float64。返回布尔值的方法也是如此。

代码语言:javascript复制
In [22]: s.str.isdigit()
Out[22]: 
0    False
1     <NA>
2    False
dtype: boolean

In [23]: s.str.match("a")
Out[23]: 
0     True
1     <NA>
2    False
dtype: boolean 

一些字符串方法,比如Series.str.decode()StringArray上不可用,因为StringArray只保存字符串,而不是字节。

在比较操作中,由StringArray支持的arrays.StringArraySeries将返回一个具有BooleanDtype的对象,而不是bool dtype 对象。在StringArray中的缺失值将在比较操作中传播,而不像numpy.nan那样总是比较不相等。

本文档其余部分中的所有内容同样适用于stringobject dtype。

字符串方法

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

代码语言:javascript复制
In [24]: s = pd.Series(
 ....:    ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
 ....: )
 ....: 

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

In [26]: s.str.upper()
Out[26]: 
0       A
1       B
2       C
3    AABA
4    BACA
5    <NA>
6    CABA
7     DOG
8     CAT
dtype: string

In [27]: s.str.len()
Out[27]: 
0       1
1       1
2       1
3       4
4       4
5    <NA>
6       4
7       3
8       3
dtype: Int64 
代码语言:javascript复制
In [28]: idx = pd.Index([" jack", "jill ", " jesse ", "frank"])

In [29]: idx.str.strip()
Out[29]: Index(['jack', 'jill', 'jesse', 'frank'], dtype='object')

In [30]: idx.str.lstrip()
Out[30]: Index(['jack', 'jill ', 'jesse ', 'frank'], dtype='object')

In [31]: idx.str.rstrip()
Out[31]: Index([' jack', 'jill', ' jesse', 'frank'], dtype='object') 

索引上的字符串方法特别适用于清理或转换 DataFrame 列。例如,您可能有带有前导或尾随空格的列:

代码语言:javascript复制
In [32]: df = pd.DataFrame(
 ....:    np.random.randn(3, 2), columns=[" Column A ", " Column B "], index=range(3)
 ....: )
 ....: 

In [33]: df
Out[33]: 
 Column A   Column B 
0   0.469112  -0.282863
1  -1.509059  -1.135632
2   1.212112  -0.173215 

由于df.columns是一个 Index 对象,我们可以使用.str访问器

代码语言:javascript复制
In [34]: df.columns.str.strip()
Out[34]: Index(['Column A', 'Column B'], dtype='object')

In [35]: df.columns.str.lower()
Out[35]: Index([' column a ', ' column b '], dtype='object') 

然后可以使用这些字符串方法根据需要清理列。在这里,我们删除前导和尾随空格,将所有���称转换为小写,并用下划线替换任何剩余的空格:

代码语言:javascript复制
In [36]: df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_")

In [37]: df
Out[37]: 
 column_a  column_b
0  0.469112 -0.282863
1 -1.509059 -1.135632
2  1.212112 -0.173215 

注意

如果您有一个Series,其中有很多重复的元素(即Series中唯一元素的数量远小于Series的长度),将原始Series转换为category类型,然后在其上使用.str.<method>.dt.<property>可能会更快。性能差异在于,对于category类型的Series,字符串操作是在.categories上而不是在Series的每个元素上进行的。

请注意,具有字符串.categoriescategory类型的Series与字符串类型的Series相比存在一些限制(例如,如果scategory类型的Series,则无法将字符串添加到彼此:s " " s不起作用)。此外,对list类型元素进行操作的.str方法在此类Series上不可用。

警告

系列的类型是推断的,允许的类型为(即字符串)。

一般来说,.str访问器仅用于处理字符串。除了极少数例外情况外,不支持其他用途,并且可能在以后被禁用。

拆分和替换字符串

split这样的方法会返回一个列表的 Series:

代码语言:javascript复制
In [38]: s2 = pd.Series(["a_b_c", "c_d_e", np.nan, "f_g_h"], dtype="string")

In [39]: s2.str.split("_")
Out[39]: 
0    [a, b, c]
1    [c, d, e]
2         <NA>
3    [f, g, h]
dtype: object 

可以使用get[]表示法访问拆分列表中的元素:

代码语言:javascript复制
In [40]: s2.str.split("_").str.get(1)
Out[40]: 
0       b
1       d
2    <NA>
3       g
dtype: object

In [41]: s2.str.split("_").str[1]
Out[41]: 
0       b
1       d
2    <NA>
3       g
dtype: object 

使用expand很容易扩展到返回 DataFrame。

代码语言:javascript复制
In [42]: s2.str.split("_", expand=True)
Out[42]: 
 0     1     2
0     a     b     c
1     c     d     e
2  <NA>  <NA>  <NA>
3     f     g     h 

当原始Series具有StringDtype时,输出列也将全部是StringDtype

也可以限制拆分的数量:

代码语言:javascript复制
In [43]: s2.str.split("_", expand=True, n=1)
Out[43]: 
 0     1
0     a   b_c
1     c   d_e
2  <NA>  <NA>
3     f   g_h 

rsplit类似于split,只是它是从字符串的末尾到字符串的开头的方向工作:

代码语言:javascript复制
In [44]: s2.str.rsplit("_", expand=True, n=1)
Out[44]: 
 0     1
0   a_b     c
1   c_d     e
2  <NA>  <NA>
3   f_g     h 

replace可选使用正则表达式:

代码语言:javascript复制
In [45]: s3 = pd.Series(
 ....:    ["A", "B", "C", "Aaba", "Baca", "", np.nan, "CABA", "dog", "cat"],
 ....:    dtype="string",
 ....: )
 ....: 

In [46]: s3
Out[46]: 
0       A
1       B
2       C
3    Aaba
4    Baca
5 
6    <NA>
7    CABA
8     dog
9     cat
dtype: string

In [47]: s3.str.replace("^.a|dog", "XX-XX ", case=False, regex=True)
Out[47]: 
0           A
1           B
2           C
3    XX-XX ba
4    XX-XX ca
5 
6        <NA>
7    XX-XX BA
8      XX-XX 
9     XX-XX t
dtype: string 

版本 2.0���的更改。

使用regex=True的单个字符模式也将被视为正则表达式:

代码语言:javascript复制
In [48]: s4 = pd.Series(["a.b", ".", "b", np.nan, ""], dtype="string")

In [49]: s4
Out[49]: 
0     a.b
1       .
2       b
3    <NA>
4 
dtype: string

In [50]: s4.str.replace(".", "a", regex=True)
Out[50]: 
0     aaa
1       a
2       a
3    <NA>
4 
dtype: string 

如果要对字符串进行字面替换(相当于str.replace()),可以将可选的regex参数设置为False,而不是转义每个字符。在这种情况下,patrepl都必须是字符串:

代码语言:javascript复制
In [51]: dollars = pd.Series(["12", "-$10", "$10,000"], dtype="string")

# These lines are equivalent
In [52]: dollars.str.replace(r"-$", "-", regex=True)
Out[52]: 
0         12
1        -10
2    $10,000
dtype: string

In [53]: dollars.str.replace("-$", "-", regex=False)
Out[53]: 
0         12
1        -10
2    $10,000
dtype: string 

replace方法还可以将可调用对象作为替换。它会使用re.sub()对每个pat进行调用。可调用对象应该期望一个位置参数(一个正则表达式对象)并返回一个字符串。

代码语言:javascript复制
# Reverse every lowercase alphabetic word
In [54]: pat = r"[a-z] "

In [55]: def repl(m):
 ....:    return m.group(0)[::-1]
 ....: 

In [56]: pd.Series(["foo 123", "bar baz", np.nan], dtype="string").str.replace(
 ....:    pat, repl, regex=True
 ....: )
 ....: 
Out[56]: 
0    oof 123
1    rab zab
2       <NA>
dtype: string

# Using regex groups
In [57]: pat = r"(?P<one>w ) (?P<two>w ) (?P<three>w )"

In [58]: def repl(m):
 ....:    return m.group("two").swapcase()
 ....: 

In [59]: pd.Series(["Foo Bar Baz", np.nan], dtype="string").str.replace(
 ....:    pat, repl, regex=True
 ....: )
 ....: 
Out[59]: 
0     bAR
1    <NA>
dtype: string 

replace方法还接受从re.compile()编译的正则表达式对象作为模式。所有标志应包含在编译的正则表达式对象中。

代码语言:javascript复制
In [60]: import re

In [61]: regex_pat = re.compile(r"^.a|dog", flags=re.IGNORECASE)

In [62]: s3.str.replace(regex_pat, "XX-XX ", regex=True)
Out[62]: 
0           A
1           B
2           C
3    XX-XX ba
4    XX-XX ca
5 
6        <NA>
7    XX-XX BA
8      XX-XX 
9     XX-XX t
dtype: string 

在使用编译的正则表达式对象调用replace时包含flags参数将引发ValueError

代码语言:javascript复制
In [63]: s3.str.replace(regex_pat, 'XX-XX ', flags=re.IGNORECASE)
---------------------------------------------------------------------------
ValueError: case and flags cannot be set when pat is a compiled regex 

removeprefixremovesuffix与 Python 3.9 中添加的str.removeprefixstr.removesuffix具有相同的效果 <docs.python.org/3/library/stdtypes.html#str.removeprefix>`__:

版本 1.4.0 中的新功能。

代码语言:javascript复制
In [64]: s = pd.Series(["str_foo", "str_bar", "no_prefix"])

In [65]: s.str.removeprefix("str_")
Out[65]: 
0          foo
1          bar
2    no_prefix
dtype: object

In [66]: s = pd.Series(["foo_str", "bar_str", "no_suffix"])

In [67]: s.str.removesuffix("_str")
Out[67]: 
0          foo
1          bar
2    no_suffix
dtype: object 

连接

有几种方法可以连接SeriesIndex,无论是与自身还是其他对象,都基于cat()Index.str.cat

将单个 Series 连接成字符串

可以连接Series(或Index)的内容:

代码语言:javascript复制
In [68]: s = pd.Series(["a", "b", "c", "d"], dtype="string")

In [69]: s.str.cat(sep=",")
Out[69]: 'a,b,c,d' 

如果未指定,分隔符的关键字sep默认为空字符串,sep=''

代码语言:javascript复制
In [70]: s.str.cat()
Out[70]: 'abcd' 

默认情况下,缺失值会被忽略。使用na_rep,它们可以被赋予一个表示:

代码语言:javascript复制
In [71]: t = pd.Series(["a", "b", np.nan, "d"], dtype="string")

In [72]: t.str.cat(sep=",")
Out[72]: 'a,b,d'

In [73]: t.str.cat(sep=",", na_rep="-")
Out[73]: 'a,b,-,d' 
将 Series 和类似列表的内容连接成 Series

cat()的第一个参数可以是类似列表的对象,只要它与调用的Series(或Index)的长度匹配。

代码语言:javascript复制
In [74]: s.str.cat(["A", "B", "C", "D"])
Out[74]: 
0    aA
1    bB
2    cC
3    dD
dtype: string 

任一侧的缺失值也会导致结果中的缺失值,除非指定了na_rep

代码语言:javascript复制
In [75]: s.str.cat(t)
Out[75]: 
0      aa
1      bb
2    <NA>
3      dd
dtype: string

In [76]: s.str.cat(t, na_rep="-")
Out[76]: 
0    aa
1    bb
2    c-
3    dd
dtype: string 
将 Series 和类似数组的内容连接成 Series

参数others也可以是二维的。在这种情况下,行数必须与调用的Series(或Index)的长度匹配。

代码语言:javascript复制
In [77]: d = pd.concat([t, s], axis=1)

In [78]: s
Out[78]: 
0    a
1    b
2    c
3    d
dtype: string

In [79]: d
Out[79]: 
 0  1
0     a  a
1     b  b
2  <NA>  c
3     d  d

In [80]: s.str.cat(d, na_rep="-")
Out[80]: 
0    aaa
1    bbb
2    c-c
3    ddd
dtype: string 
将 Series 和索引对象连接成 Series,进行对齐

对于与SeriesDataFrame连接,可以通过设置join关键字来在连接之前对齐索引。

代码语言:javascript复制
In [81]: u = pd.Series(["b", "d", "a", "c"], index=[1, 3, 0, 2], dtype="string")

In [82]: s
Out[82]: 
0    a
1    b
2    c
3    d
dtype: string

In [83]: u
Out[83]: 
1    b
3    d
0    a
2    c
dtype: string

In [84]: s.str.cat(u)
Out[84]: 
0    aa
1    bb
2    cc
3    dd
dtype: string

In [85]: s.str.cat(u, join="left")
Out[85]: 
0    aa
1    bb
2    cc
3    dd
dtype: string 

对于join的常见选项(其中之一为'left', 'outer', 'inner', 'right')都是可用的。特别是,对齐也意味着不同长度不再需要一致。

代码语言:javascript复制
In [86]: v = pd.Series(["z", "a", "b", "d", "e"], index=[-1, 0, 1, 3, 4], dtype="string")

In [87]: s
Out[87]: 
0    a
1    b
2    c
3    d
dtype: string

In [88]: v
Out[88]: 
-1    z
 0    a
 1    b
 3    d
 4    e
dtype: string

In [89]: s.str.cat(v, join="left", na_rep="-")
Out[89]: 
0    aa
1    bb
2    c-
3    dd
dtype: string

In [90]: s.str.cat(v, join="outer", na_rep="-")
Out[90]: 
-1    -z
 0    aa
 1    bb
 2    c-
 3    dd
 4    -e
dtype: string 

others是一个DataFrame时,可以使用相同的对齐方式:

代码语言:javascript复制
In [91]: f = d.loc[[3, 2, 1, 0], :]

In [92]: s
Out[92]: 
0    a
1    b
2    c
3    d
dtype: string

In [93]: f
Out[93]: 
 0  1
3     d  d
2  <NA>  c
1     b  b
0     a  a

In [94]: s.str.cat(f, join="left", na_rep="-")
Out[94]: 
0    aaa
1    bbb
2    c-c
3    ddd
dtype: string 
将一个 Series 和多个对象连接成一个 Series

几个类似数组的项目(具体来说:SeriesIndexnp.ndarray的一维变体)可以组合在一个类似列表的容器中(包括迭代器,dict视图等)。

代码语言:javascript复制
In [95]: s
Out[95]: 
0    a
1    b
2    c
3    d
dtype: string

In [96]: u
Out[96]: 
1    b
3    d
0    a
2    c
dtype: string

In [97]: s.str.cat([u, u.to_numpy()], join="left")
Out[97]: 
0    aab
1    bbd
2    cca
3    ddc
dtype: string 

传递的类似列表中没有索引的所有元素(例如np.ndarray)必须与调用的Series(或Index)的长度匹配,但SeriesIndex的长度可以是任意的(只要不使用join=None禁用对齐):

代码语言:javascript复制
In [98]: v
Out[98]: 
-1    z
 0    a
 1    b
 3    d
 4    e
dtype: string

In [99]: s.str.cat([v, u, u.to_numpy()], join="outer", na_rep="-")
Out[99]: 
-1    -z--
0     aaab
1     bbbd
2     c-ca
3     dddc
4     -e--
dtype: string 

如果在包含不同索引的others列表上使用join='right',则这些索引的并集将被用作最终连接的基础:

代码语言:javascript复制
In [100]: u.loc[[3]]
Out[100]: 
3    d
dtype: string

In [101]: v.loc[[-1, 0]]
Out[101]: 
-1    z
 0    a
dtype: string

In [102]: s.str.cat([u.loc[[3]], v.loc[[-1, 0]]], join="right", na_rep="-")
Out[102]: 
 3    dd-
-1    --z
 0    a-a
dtype: string 
将一个单独的 Series 连接成一个字符串

可以连接Series(或Index)的内容:

代码语言:javascript复制
In [68]: s = pd.Series(["a", "b", "c", "d"], dtype="string")

In [69]: s.str.cat(sep=",")
Out[69]: 'a,b,c,d' 

如果未指定,分隔符的关键字sep默认为空字符串,sep=''

代码语言:javascript复制
In [70]: s.str.cat()
Out[70]: 'abcd' 

默认情况下,缺失值会被忽略。使用na_rep,它们可以被赋予一个表示:

代码语言:javascript复制
In [71]: t = pd.Series(["a", "b", np.nan, "d"], dtype="string")

In [72]: t.str.cat(sep=",")
Out[72]: 'a,b,d'

In [73]: t.str.cat(sep=",", na_rep="-")
Out[73]: 'a,b,-,d' 
将一个 Series 和类似列表的东西连接成一个 Series

cat()的第一个参数可以是一个类似列表的对象,只要它与调用的Series(或Index)的长度匹配即可。

代码语言:javascript复制
In [74]: s.str.cat(["A", "B", "C", "D"])
Out[74]: 
0    aA
1    bB
2    cC
3    dD
dtype: string 

任一侧的缺失值也会导致结果中的缺失值,除非指定了na_rep

代码语言:javascript复制
In [75]: s.str.cat(t)
Out[75]: 
0      aa
1      bb
2    <NA>
3      dd
dtype: string

In [76]: s.str.cat(t, na_rep="-")
Out[76]: 
0    aa
1    bb
2    c-
3    dd
dtype: string 
将一个 Series 和类似数组的东西连接成一个 Series

参数others也可以是二维的。在这种情况下,行数必须与调用的Series(或Index)的长度相匹配。

代码语言:javascript复制
In [77]: d = pd.concat([t, s], axis=1)

In [78]: s
Out[78]: 
0    a
1    b
2    c
3    d
dtype: string

In [79]: d
Out[79]: 
 0  1
0     a  a
1     b  b
2  <NA>  c
3     d  d

In [80]: s.str.cat(d, na_rep="-")
Out[80]: 
0    aaa
1    bbb
2    c-c
3    ddd
dtype: string 
将一个 Series 和一个带索引的对象连接成一个 Series,带有对齐

对于与SeriesDataFrame连接,可以通过设置join关键字来在连接之前对齐索引。

代码语言:javascript复制
In [81]: u = pd.Series(["b", "d", "a", "c"], index=[1, 3, 0, 2], dtype="string")

In [82]: s
Out[82]: 
0    a
1    b
2    c
3    d
dtype: string

In [83]: u
Out[83]: 
1    b
3    d
0    a
2    c
dtype: string

In [84]: s.str.cat(u)
Out[84]: 
0    aa
1    bb
2    cc
3    dd
dtype: string

In [85]: s.str.cat(u, join="left")
Out[85]: 
0    aa
1    bb
2    cc
3    dd
dtype: string 

对于join的常见选项(其中之一为'left', 'outer', 'inner', 'right')都是可用的。特别是,对齐也意味着不同长度不再需要一致。

代码语言:javascript复制
In [86]: v = pd.Series(["z", "a", "b", "d", "e"], index=[-1, 0, 1, 3, 4], dtype="string")

In [87]: s
Out[87]: 
0    a
1    b
2    c
3    d
dtype: string

In [88]: v
Out[88]: 
-1    z
 0    a
 1    b
 3    d
 4    e
dtype: string

In [89]: s.str.cat(v, join="left", na_rep="-")
Out[89]: 
0    aa
1    bb
2    c-
3    dd
dtype: string

In [90]: s.str.cat(v, join="outer", na_rep="-")
Out[90]: 
-1    -z
 0    aa
 1    bb
 2    c-
 3    dd
 4    -e
dtype: string 

others是一个DataFrame时,可以使用相同的对齐方式:

代码语言:javascript复制
In [91]: f = d.loc[[3, 2, 1, 0], :]

In [92]: s
Out[92]: 
0    a
1    b
2    c
3    d
dtype: string

In [93]: f
Out[93]: 
 0  1
3     d  d
2  <NA>  c
1     b  b
0     a  a

In [94]: s.str.cat(f, join="left", na_rep="-")
Out[94]: 
0    aaa
1    bbb
2    c-c
3    ddd
dtype: string 
将一个 Series 和多个对象连接成一个 Series

几个类似数组的项目(具体来说:SeriesIndexnp.ndarray的一维变体)可以组合在一个类似列表的容器中(包括迭代器,dict视图等)。

代码语言:javascript复制
In [95]: s
Out[95]: 
0    a
1    b
2    c
3    d
dtype: string

In [96]: u
Out[96]: 
1    b
3    d
0    a
2    c
dtype: string

In [97]: s.str.cat([u, u.to_numpy()], join="left")
Out[97]: 
0    aab
1    bbd
2    cca
3    ddc
dtype: string 

传递的类似列表中没有索引的所有元素(例如np.ndarray)必须与调用的Series(或Index)的长度匹配,但SeriesIndex的长度可以是任意的(只要不使用join=None禁用对齐):

代码语言:javascript复制
In [98]: v
Out[98]: 
-1    z
 0    a
 1    b
 3    d
 4    e
dtype: string

In [99]: s.str.cat([v, u, u.to_numpy()], join="outer", na_rep="-")
Out[99]: 
-1    -z--
0     aaab
1     bbbd
2     c-ca
3     dddc
4     -e--
dtype: string 

如果在包含不同索引的others列表上使用join='right',则这些索引的并集将被用作最终连接的基础:

代码语言:javascript复制
In [100]: u.loc[[3]]
Out[100]: 
3    d
dtype: string

In [101]: v.loc[[-1, 0]]
Out[101]: 
-1    z
 0    a
dtype: string

In [102]: s.str.cat([u.loc[[3]], v.loc[[-1, 0]]], join="right", na_rep="-")
Out[102]: 
 3    dd-
-1    --z
 0    a-a
dtype: string 

使用.str进行索引

您可以使用 [] 符号直接按位置索引。如果索引超出字符串的末尾,结果将是一个 NaN

代码语言:javascript复制
In [103]: s = pd.Series(
 .....:    ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
 .....: )
 .....: 

In [104]: s.str[0]
Out[104]: 
0       A
1       B
2       C
3       A
4       B
5    <NA>
6       C
7       d
8       c
dtype: string

In [105]: s.str[1]
Out[105]: 
0    <NA>
1    <NA>
2    <NA>
3       a
4       a
5    <NA>
6       A
7       o
8       a
dtype: string 

提取子字符串

提取每个主题中的第一个匹配项(extract)

extract 方法接受至少一个捕获组的 正则表达式。

提取具有多个组的正则表达式将返回一个每组一列的 DataFrame。

代码语言:javascript复制
In [106]: pd.Series(
 .....:    ["a1", "b2", "c3"],
 .....:    dtype="string",
 .....: ).str.extract(r"([ab])(d)", expand=False)
 .....: 
Out[106]: 
 0     1
0     a     1
1     b     2
2  <NA>  <NA> 

不匹配的元素返回一个填充有 NaN 的行。因此,一系列混乱的字符串可以“转换”为一个具有相同索引的已清理或更有用的字符串的 Series 或 DataFrame,而无需使用 get() 访问元组或 re.match 对象。结果的 dtype 始终为 object,即使未找到匹配项,结果仅包含 NaN

命名组如

代码语言:javascript复制
In [107]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(
 .....:    r"(?P<letter>[ab])(?P<digit>d)", expand=False
 .....: )
 .....: 
Out[107]: 
 letter digit
0      a     1
1      b     2
2   <NA>  <NA> 

和可选组

代码语言:javascript复制
In [108]: pd.Series(
 .....:    ["a1", "b2", "3"],
 .....:    dtype="string",
 .....: ).str.extract(r"([ab])?(d)", expand=False)
 .....: 
Out[108]: 
 0  1
0     a  1
1     b  2
2  <NA>  3 

也可以使用。请注意,正则表达式中的任何捕获组名称将用于列名;否则将使用捕获组编号。

提取具有一个组的正则表达式将返回一个列的 DataFrame,如果 expand=True

代码语言:javascript复制
In [109]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"ab", expand=True)
Out[109]: 
 0
0     1
1     2
2  <NA> 

如果 expand=False,则返回一个 Series。

代码语言:javascript复制
In [110]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"ab", expand=False)
Out[110]: 
0       1
1       2
2    <NA>
dtype: string 

对具有正好一个捕获组的正则表达式的 Index 调用,如果 expand=True,则返回一个列。

代码语言:javascript复制
In [111]: s = pd.Series(["a1", "b2", "c3"], ["A11", "B22", "C33"], dtype="string")

In [112]: s
Out[112]: 
A11    a1
B22    b2
C33    c3
dtype: string

In [113]: s.index.str.extract("(?P<letter>[a-zA-Z])", expand=True)
Out[113]: 
 letter
0      A
1      B
2      C 

如果 expand=False,则返回一个 Index

代码语言:javascript复制
In [114]: s.index.str.extract("(?P<letter>[a-zA-Z])", expand=False)
Out[114]: Index(['A', 'B', 'C'], dtype='object', name='letter') 

对具有多个捕获组的正则表达式的 Index 调用,如果 expand=True,则返回一个 DataFrame。

代码语言:javascript复制
In [115]: s.index.str.extract("(?P<letter>[a-zA-Z])([0-9] )", expand=True)
Out[115]: 
 letter   1
0      A  11
1      B  22
2      C  33 

如果 expand=False,则引发 ValueError

代码语言:javascript复制
In [116]: s.index.str.extract("(?P<letter>[a-zA-Z])([0-9] )", expand=False)
---------------------------------------------------------------------------
ValueError  Traceback (most recent call last)
Cell In[116], line 1
----> 1 s.index.str.extract("(?P<letter>[a-zA-Z])([0-9] )", expand=False)

File ~/work/pandas/pandas/pandas/core/strings/accessor.py:137, in forbid_nonstring_types.<locals>._forbid_nonstring_types.<locals>.wrapper(self, *args, **kwargs)
  132     msg = (
  133         f"Cannot use .str.{func_name} with values of "
  134         f"inferred dtype '{self._inferred_dtype}'."
  135     )
  136     raise TypeError(msg)
--> 137 return func(self, *args, **kwargs)

File ~/work/pandas/pandas/pandas/core/strings/accessor.py:2743, in StringMethods.extract(self, pat, flags, expand)
  2740     raise ValueError("pattern contains no capture groups")
  2742 if not expand and regex.groups > 1 and isinstance(self._data, ABCIndex):
-> 2743     raise ValueError("only one regex group is supported with Index")
  2745 obj = self._data
  2746 result_dtype = _result_dtype(obj)

ValueError: only one regex group is supported with Index 

下表总结了 extract(expand=False) 的行为(输入主题在第一列,正则表达式中的组数在第一行)

1 组

>1 组

Index

Index

ValueError

Series

Series

DataFrame

提取每个主题中的所有匹配项(extractall)

与仅返回第一个匹配项的 extract 不同,

代码语言:javascript复制
In [117]: s = pd.Series(["a1a2", "b1", "c1"], index=["A", "B", "C"], dtype="string")

In [118]: s
Out[118]: 
A    a1a2
B      b1
C      c1
dtype: string

In [119]: two_groups = "(?P<letter>[a-z])(?P<digit>[0-9])"

In [120]: s.str.extract(two_groups, expand=True)
Out[120]: 
 letter digit
A      a     1
B      b     1
C      c     1 

extractall 方法返回每个匹配项。extractall 的结果始终是一个具有行上的 MultiIndex 的 DataFrame。MultiIndex 的最后一级命名为 match,表示主题中的顺序。

代码语言:javascript复制
In [121]: s.str.extractall(two_groups)
Out[121]: 
 letter digit
 match 
A 0          a     1
 1          a     2
B 0          b     1
C 0          c     1 

当 Series 中的每个主题字符串恰好有一个匹配项时,

代码语言:javascript复制
In [122]: s = pd.Series(["a3", "b3", "c2"], dtype="string")

In [123]: s
Out[123]: 
0    a3
1    b3
2    c2
dtype: string 

然后 extractall(pat).xs(0, level='match') 给出与 extract(pat) 相同的结果。

代码语言:javascript复制
In [124]: extract_result = s.str.extract(two_groups, expand=True)

In [125]: extract_result
Out[125]: 
 letter digit
0      a     3
1      b     3
2      c     2

In [126]: extractall_result = s.str.extractall(two_groups)

In [127]: extractall_result
Out[127]: 
 letter digit
 match 
0 0          a     3
1 0          b     3
2 0          c     2

In [128]: extractall_result.xs(0, level="match")
Out[128]: 
 letter digit
0      a     3
1      b     3
2      c     2 

Index 还支持 .str.extractall。它返回一个 DataFrame,其结果与具有默认索引(从 0 开始)的 Series.str.extractall 相同。

代码语言:javascript复制
In [129]: pd.Index(["a1a2", "b1", "c1"]).str.extractall(two_groups)
Out[129]: 
 letter digit
 match 
0 0          a     1
 1          a     2
1 0          b     1
2 0          c     1

In [130]: pd.Series(["a1a2", "b1", "c1"], dtype="string").str.extractall(two_groups)
Out[130]: 
 letter digit
 match 
0 0          a     1
 1          a     2
1 0          b     1
2 0          c     1 
提取每个主题中的第一个匹配项(extract)

extract 方法接受至少一个捕获组的 正则表达式。

提取具有多个组的正则表达式将返回一个每组一列的 DataFrame。

代码语言:javascript复制
In [106]: pd.Series(
 .....:    ["a1", "b2", "c3"],
 .....:    dtype="string",
 .....: ).str.extract(r"([ab])(d)", expand=False)
 .....: 
Out[106]: 
 0     1
0     a     1
1     b     2
2  <NA>  <NA> 

不匹配的元素返回一个填充有 NaN 的行。因此,一系列混乱的字符串可以“转换”为一个具有相同索引的已清理或更有用的字符串的 Series 或 DataFrame,而无需使用 get() 访问元组或 re.match 对象。结果的 dtype 始终为 object,即使未找到匹配项,结果仅包含 NaN

命名组如

代码语言:javascript复制
In [107]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(
 .....:    r"(?P<letter>[ab])(?P<digit>d)", expand=False
 .....: )
 .....: 
Out[107]: 
 letter digit
0      a     1
1      b     2
2   <NA>  <NA> 

和可选���

代码语言:javascript复制
In [108]: pd.Series(
 .....:    ["a1", "b2", "3"],
 .....:    dtype="string",
 .....: ).str.extract(r"([ab])?(d)", expand=False)
 .....: 
Out[108]: 
 0  1
0     a  1
1     b  2
2  <NA>  3 

也可以使用。请注意,正则表达式中的任何捕获组名称将用于列名;否则将使用捕获组编号。

使用一个组提取正则表达式,如果expand=True,则返回一个列的DataFrame

代码语言:javascript复制
In [109]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"ab", expand=True)
Out[109]: 
 0
0     1
1     2
2  <NA> 

如果expand=False,则返回一个 Series。

代码语言:javascript复制
In [110]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"ab", expand=False)
Out[110]: 
0       1
1       2
2    <NA>
dtype: string 

对具有正好一个捕获组的正则表达式调用Index,如果expand=True,则返回一个列的DataFrame

代码语言:javascript复制
In [111]: s = pd.Series(["a1", "b2", "c3"], ["A11", "B22", "C33"], dtype="string")

In [112]: s
Out[112]: 
A11    a1
B22    b2
C33    c3
dtype: string

In [113]: s.index.str.extract("(?P<letter>[a-zA-Z])", expand=True)
Out[113]: 
 letter
0      A
1      B
2      C 

如果expand=False,则返回一个Index

代码语言:javascript复制
In [114]: s.index.str.extract("(?P<letter>[a-zA-Z])", expand=False)
Out[114]: Index(['A', 'B', 'C'], dtype='object', name='letter') 

对具有多个捕获组的正则表达式调用Index,如果expand=True,则返回一个DataFrame

代码语言:javascript复制
In [115]: s.index.str.extract("(?P<letter>[a-zA-Z])([0-9] )", expand=True)
Out[115]: 
 letter   1
0      A  11
1      B  22
2      C  33 

如果expand=False,则会引发ValueError

代码语言:javascript复制
In [116]: s.index.str.extract("(?P<letter>[a-zA-Z])([0-9] )", expand=False)
---------------------------------------------------------------------------
ValueError  Traceback (most recent call last)
Cell In[116], line 1
----> 1 s.index.str.extract("(?P<letter>[a-zA-Z])([0-9] )", expand=False)

File ~/work/pandas/pandas/pandas/core/strings/accessor.py:137, in forbid_nonstring_types.<locals>._forbid_nonstring_types.<locals>.wrapper(self, *args, **kwargs)
  132     msg = (
  133         f"Cannot use .str.{func_name} with values of "
  134         f"inferred dtype '{self._inferred_dtype}'."
  135     )
  136     raise TypeError(msg)
--> 137 return func(self, *args, **kwargs)

File ~/work/pandas/pandas/pandas/core/strings/accessor.py:2743, in StringMethods.extract(self, pat, flags, expand)
  2740     raise ValueError("pattern contains no capture groups")
  2742 if not expand and regex.groups > 1 and isinstance(self._data, ABCIndex):
-> 2743     raise ValueError("only one regex group is supported with Index")
  2745 obj = self._data
  2746 result_dtype = _result_dtype(obj)

ValueError: only one regex group is supported with Index 

下表总结了extract(expand=False)的行为(第一列为输入主题,第一行为正则表达式中的组数)

1 组

>1 组

Index

Index

ValueError

Series

Series

DataFrame

提取每个主题中的所有匹配(extractall)

与仅返回第一个匹配的extract不同,

代码语言:javascript复制
In [117]: s = pd.Series(["a1a2", "b1", "c1"], index=["A", "B", "C"], dtype="string")

In [118]: s
Out[118]: 
A    a1a2
B      b1
C      c1
dtype: string

In [119]: two_groups = "(?P<letter>[a-z])(?P<digit>[0-9])"

In [120]: s.str.extract(two_groups, expand=True)
Out[120]: 
 letter digit
A      a     1
B      b     1
C      c     1 

extractall方法返回每个匹配。extractall的结果始终是具有其行上的MultiIndexDataFrameMultiIndex的最后一级命名为match,表示主题中的顺序。

代码语言:javascript复制
In [121]: s.str.extractall(two_groups)
Out[121]: 
 letter digit
 match 
A 0          a     1
 1          a     2
B 0          b     1
C 0          c     1 

当 Series 中的每个主题字符串正好有一个匹配时,

代码语言:javascript复制
In [122]: s = pd.Series(["a3", "b3", "c2"], dtype="string")

In [123]: s
Out[123]: 
0    a3
1    b3
2    c2
dtype: string 

然后extractall(pat).xs(0, level='match')给出���extract(pat)相同的结果。

代码语言:javascript复制
In [124]: extract_result = s.str.extract(two_groups, expand=True)

In [125]: extract_result
Out[125]: 
 letter digit
0      a     3
1      b     3
2      c     2

In [126]: extractall_result = s.str.extractall(two_groups)

In [127]: extractall_result
Out[127]: 
 letter digit
 match 
0 0          a     3
1 0          b     3
2 0          c     2

In [128]: extractall_result.xs(0, level="match")
Out[128]: 
 letter digit
0      a     3
1      b     3
2      c     2 

Index也支持.str.extractall。它返回一个DataFrame,其结果与具有默认索引(从 0 开始)的Series.str.extractall相同。

代码语言:javascript复制
In [129]: pd.Index(["a1a2", "b1", "c1"]).str.extractall(two_groups)
Out[129]: 
 letter digit
 match 
0 0          a     1
 1          a     2
1 0          b     1
2 0          c     1

In [130]: pd.Series(["a1a2", "b1", "c1"], dtype="string").str.extractall(two_groups)
Out[130]: 
 letter digit
 match 
0 0          a     1
 1          a     2
1 0          b     1
2 0          c     1 

测试匹配或包含模式的字符串

您可以检查元素是否包含模式:

代码语言:javascript复制
In [131]: pattern = r"[0-9][a-z]"

In [132]: pd.Series(
 .....:    ["1", "2", "3a", "3b", "03c", "4dx"],
 .....:    dtype="string",
 .....: ).str.contains(pattern)
 .....: 
Out[132]: 
0    False
1    False
2     True
3     True
4     True
5     True
dtype: boolean 

或者元素是否匹配模式:

代码语言:javascript复制
In [133]: pd.Series(
 .....:    ["1", "2", "3a", "3b", "03c", "4dx"],
 .....:    dtype="string",
 .....: ).str.match(pattern)
 .....: 
Out[133]: 
0    False
1    False
2     True
3     True
4    False
5     True
dtype: boolean 
代码语言:javascript复制
In [134]: pd.Series(
 .....:    ["1", "2", "3a", "3b", "03c", "4dx"],
 .....:    dtype="string",
 .....: ).str.fullmatch(pattern)
 .....: 
Out[134]: 
0    False
1    False
2     True
3     True
4    False
5    False
dtype: boolean 

注意

matchfullmatchcontains之间的区别是严格性:fullmatch测试整个字符串是否与正则表达式匹配;match测试字符串的第一个字符是否有正则表达式的匹配;contains测试字符串中是否有正则表达式的匹配。

这三种匹配模式的re包中对应的函数分别是re.fullmatch、re.match和re.search。

matchfullmatchcontainsstartswithendswith等方法接受额外的na参数,以便将缺失值视为 True 或 False:

代码语言:javascript复制
In [135]: s4 = pd.Series(
 .....:    ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
 .....: )
 .....: 

In [136]: s4.str.contains("A", na=False)
Out[136]: 
0     True
1    False
2    False
3     True
4    False
5    False
6     True
7    False
8    False
dtype: boolean 

创建指示变量

您可以从字符串列中提取虚拟变量。例如,如果它们由'|'分隔:

代码语言:javascript复制
In [137]: s = pd.Series(["a", "a|b", np.nan, "a|c"], dtype="string")

In [138]: s.str.get_dummies(sep="|")
Out[138]: 
 a  b  c
0  1  0  0
1  1  1  0
2  0  0  0
3  1  0  1 

字符串Index也支持get_dummies,它返回一个MultiIndex

代码语言:javascript复制
In [139]: idx = pd.Index(["a", "a|b", np.nan, "a|c"])

In [140]: idx.str.get_dummies(sep="|")
Out[140]: 
MultiIndex([(1, 0, 0),
 (1, 1, 0),
 (0, 0, 0),
 (1, 0, 1)],
 names=['a', 'b', 'c']) 

查看get_dummies()

方法摘要

方法

描述

cat()

连接字符串

split()

在分隔符上拆分字符串

rsplit()

在字符串上的分隔符上工作,从字符串的末尾开始分割

get()

索引到每个元素(检索第 i 个元素)

join()

使用传递的分隔符将 Series 中每个元素的字符串连接起来

get_dummies()

在分隔符上拆分字符串,返回虚拟变量的 DataFrame

contains()

如果每个字符串包含模式/正则表达式,则返回布尔数组

replace()

用其他字符串或可调用函数的返回值替换模式/正则表达式/字符串的出现

removeprefix()

从字符串中删除前缀,即仅在字符串以前缀开头时才删除。

removesuffix()

从字符串中删除后缀,即仅在字符串以后缀结尾时才删除。

repeat()

复制值(s.str.repeat(3)等同于x * 3)

pad()

在字符串的左侧、右侧或两侧添加空格

center()

等同于str.center

ljust()

等同于str.ljust

rjust()

等同于str.rjust

zfill()

等同于str.zfill

wrap()

将长字符串拆分为长度小于给定宽度的行

slice()

切片 Series 中的每个字符串

slice_replace()

用传递的值替换每个字符串中的切片

count()

计算模式出现的次数

startswith()

对每个元素等同于str.startswith(pat)

endswith()

对每个元素等同于str.endswith(pat)

findall()

计算每个字符串的模式/正则表达式的所有出现的列表

match()

对每个元素调用re.match,返回匹配的组成列表

extract()

对每个元素调用re.search,返回一个 DataFrame,每个元素一行,每个正则表达式捕获组一列

extractall()

对每个元素调用re.findall,返回一个 DataFrame,每个匹配一行,每个正则表达式捕获组一列

len()

计算字符串长度

strip()

等同于str.strip

rstrip()

等同于str.rstrip

lstrip()

等同于str.lstrip

partition()

等同于str.partition

rpartition()

等同于str.rpartition

lower()

等同于str.lower

casefold()

等同于str.casefold

upper()

等同于str.upper

find()

等同于 str.find

rfind()

等同于 str.rfind

index()

等同于 str.index

rindex()

等同于 str.rindex

capitalize()

等同于 str.capitalize

swapcase()

等同于 str.swapcase

normalize()

返回 Unicode 正规形式。等同于 unicodedata.normalize

translate()

等同于 str.translate

isalnum()

等同于 str.isalnum

isalpha()

等同于 str.isalpha

isdigit()

等同于 str.isdigit

isspace()

等同于 str.isspace

islower()

等同于 str.islower

isupper()

等同于 str.isupper

istitle()

等同于 str.istitle

isnumeric()

等同于 str.isnumeric

isdecimal()

等同于 str.isdecimal

0 人点赞