5 使用 .str 索引
可以使用 []
符号直接按位置进行索引,如果索引超过字符串的长度,结果将是 NaN
In [96]: s = pd.Series(
....: ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
....: )
....:
In [97]: s.str[0]
Out[97]:
0 A
1 B
2 C
3 A
4 B
5 <NA>
6 C
7 d
8 c
dtype: string
In [98]: s.str[1]
Out[98]:
0 <NA>
1 <NA>
2 <NA>
3 a
4 a
5 <NA>
6 A
7 o
8 a
dtype: string
6 提取子字符串
6.1 提取第一个匹配项(extract)
在 0.23
版本之前,extract
方法的参数 expand
默认为 False
。当 expand=False
时,expand
会根据正则表达式模式返回一个 Series
、Index
或 DataFrame
当 expand=True
时,它总是返回一个 DataFrame
,这种方式更加符合用户的需求,从 0.23.0
版本开始就是默认的
extract
方法接受一个至少包含一个捕获组的正则表达式
如果是包含多个组的正则表达式将返回一个 DataFrame
,每个捕获组是一列
In [99]: pd.Series(
....: ["a1", "b2", "c3"],
....: dtype="string",
....: ).str.extract(r"([ab])(\d)", expand=False)
....:
Out[99]:
0 1
0 a 1
1 b 2
2 <NA> <NA>
未匹配的行会填充 NaN
,可以从混乱的字符串序列中提取出有规则的信息。
对于命名分组
In [100]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(
.....: r"(?P<letter>[ab])(?P<digit>\d)", expand=False
.....: )
.....:
Out[100]:
letter digit
0 a 1
1 b 2
2 <NA> <NA>
对于可选的分组
In [101]: pd.Series(
.....: ["a1", "b2", "3"],
.....: dtype="string",
.....: ).str.extract(r"([ab])?(\d)", expand=False)
.....:
Out[101]:
0 1
0 a 1
1 b 2
2 <NA> 3
注意:正则表达式中的任何捕获组名称都将用作列名,否则将使用捕获组号
如果 expand=True
,则返回一个 DataFrame
In [102]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"[ab](\d)", expand=True)
Out[102]:
0
0 1
1 2
2 <NA>
如果 expand=False
,则返回一个 Series
In [103]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"[ab](\d)", expand=False)
Out[103]:
0 1
1 2
2 <NA>
dtype: string
对于索引,如果 expand=True
,且只有一个捕获组则返回一个只有一列的 DataFrame
In [104]: s = pd.Series(["a1", "b2", "c3"], ["A11", "B22", "C33"], dtype="string")
In [105]: s
Out[105]:
A11 a1
B22 b2
C33 c3
dtype: string
In [106]: s.index.str.extract("(?P<letter>[a-zA-Z])", expand=True)
Out[106]:
letter
0 A
1 B
2 C
此时,如果 expand=False
将会返回一个 Index
In [107]: s.index.str.extract("(?P<letter>[a-zA-Z])", expand=False)
Out[107]: Index(['A', 'B', 'C'], dtype='object', name='letter')
对于索引,正则表达式设置多个分组将返回 DataFrame
In [108]: s.index.str.extract("(?P<letter>[a-zA-Z])([0-9]+)", expand=True)
Out[108]:
letter 1
0 A 11
1 B 22
2 C 33
如果 expand=False
将会抛出 ValueError
异常
>>> s.index.str.extract("(?P<letter>[a-zA-Z])([0-9]+)", expand=False)
ValueError: only one regex group is supported with Index
6.2 提取所有匹配(extractall)
对于 extract
只返回第一个匹配项
In [109]: s = pd.Series(["a1a2", "b1", "c1"], index=["A", "B", "C"], dtype="string")
In [110]: s
Out[110]:
A a1a2
B b1
C c1
dtype: string
In [111]: two_groups = "(?P<letter>[a-z])(?P<digit>[0-9])"
In [112]: s.str.extract(two_groups, expand=True)
Out[112]:
letter digit
A a 1
B b 1
C c 1
与 extract
不同,extractall
方法返回每个匹配项,其结果始终是具有 MultiIndex
的 DataFrame
。
MultiIndex
的最后一级名为 match
,标示的是匹配的顺序
In [113]: s.str.extractall(two_groups)
Out[113]:
letter digit
match
A 0 a 1
1 a 2
B 0 b 1
C 0 c 1
对于只有一个匹配的 Series
In [114]: s = pd.Series(["a3", "b3", "c2"], dtype="string")
In [115]: s
Out[115]:
0 a3
1 b3
2 c2
dtype: string
extractall(pat).xs(0, level='match')
与 extract(pat)
的结果一致
In [116]: extract_result = s.str.extract(two_groups, expand=True)
In [117]: extract_result
Out[117]:
letter digit
0 a 3
1 b 3
2 c 2
In [118]: extractall_result = s.str.extractall(two_groups)
In [119]: extractall_result
Out[119]:
letter digit
match
0 0 a 3
1 0 b 3
2 0 c 2
In [120]: extractall_result.xs(0, level="match")
Out[120]:
letter digit
0 a 3
1 b 3
2 c 2
Index
也支持 .str.extractall
,它返回一个 DataFrame
,其结果与 Series.str
相同。
In [121]: pd.Index(["a1a2", "b1", "c1"]).str.extractall(two_groups)
Out[121]:
letter digit
match
0 0 a 1
1 a 2
1 0 b 1
2 0 c 1
In [122]: pd.Series(["a1a2", "b1", "c1"], dtype="string").str.extractall(two_groups)
Out[122]:
letter digit
match
0 0 a 1
1 a 2
1 0 b 1
2 0 c 1
7 测试字符串匹配与包含
您可以检查字符串元素中是否包含正则匹配模式
In [123]: pattern = r"[0-9][a-z]"
In [124]: pd.Series(
.....: ["1", "2", "3a", "3b", "03c", "4dx"],
.....: dtype="string",
.....: ).str.contains(pattern)
.....:
Out[124]:
0 False
1 False
2 True
3 True
4 True
5 True
dtype: boolean
或者字符串元素是否与模式匹配
In [125]: pd.Series(
.....: ["1", "2", "3a", "3b", "03c", "4dx"],
.....: dtype="string",
.....: ).str.match(pattern)
.....:
Out[125]:
0 False
1 False
2 True
3 True
4 False
5 True
dtype: boolean
而在 1.1.0
版本中
In [126]: pd.Series(
.....: ["1", "2", "3a", "3b", "03c", "4dx"],
.....: dtype="string",
.....: ).str.fullmatch(pattern)
.....:
Out[126]:
0 False
1 False
2 True
3 True
4 False
5 False
dtype: boolean
注意:
match
、fullmatch
和 contains
之间的区别是:
-
fullmatch
:测试整个字符串是否与正则表达式完全匹配 -
match
:测试字符串的开头是否与正则表达式匹配 -
contains
:测试字符串中的任何位置是否存在正则表达式的匹配
这三个函数于 re
模块的 re.fullmatch
、re.match
和 re.search
对应
像 match
, fullmatch
, contains
, startswith
和 endswith
有一个额外的 na
参数,用于将缺失值替换为 True
或 False
In [127]: s4 = pd.Series(
.....: ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
.....: )
.....:
In [128]: s4.str.contains("A", na=False)
Out[128]:
0 True
1 False
2 False
3 True
4 False
5 False
6 True
7 False
8 False
dtype: boolean
8 创建指标变量
您可以从字符串列中提取指标变量。例如,如果使用 '|'
分隔的字符串
In [129]: s = pd.Series(["a", "a|b", np.nan, "a|c"], dtype="string")
In [130]: s.str.get_dummies(sep="|")
Out[130]:
a b c
0 1 0 0
1 1 1 0
2 0 0 0
3 1 0 1
字符串 Index
也支持 get_dummies
,它返回一个 MultiIndex
In [131]: idx = pd.Index(["a", "a|b", np.nan, "a|c"])
In [132]: idx.str.get_dummies(sep="|")
Out[132]:
MultiIndex([(1, 0, 0),
(1, 1, 0),
(0, 0, 0),
(1, 0, 1)],
names=['a', 'b', 'c'])