目录
使用文本数据
Series和Index配备了一组字符串处理方法,可以轻松地对阵列的每个元素进行操作。也许最重要的是,这些方法会自动排除缺失/ NA值。这些是通过str
属性访问的,通常具有与等效(标量)内置字符串方法匹配的名称:
In [1]: s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])
# 转小写
In [2]: s.str.lower()
Out[2]:
0 a
1 b
2 c
3 aaba
4 baca
5 NaN
6 caba
7 dog
8 cat
dtype: object
# 转大写
In [3]: s.str.upper()
Out[3]:
0 A
1 B
2 C
3 AABA
4 BACA
5 NaN
6 CABA
7 DOG
8 CAT
dtype: object
# 转长度
In [4]: s.str.len()
Out[4]:
0 1.0
1 1.0
2 1.0
3 4.0
4 4.0
5 NaN
6 4.0
7 3.0
8 3.0
dtype: float64
In [5]: idx = pd.Index([' jack', 'jill ', ' jesse ', 'frank'])
# 去除前后空格
In [6]: idx.str.strip()
Out[6]: Index(['jack', 'jill', 'jesse', 'frank'], dtype='object')
# 去除前空格
In [7]: idx.str.lstrip()
Out[7]: Index(['jack', 'jill ', 'jesse ', 'frank'], dtype='object')
# 去除后空格
In [8]: idx.str.rstrip()
Out[8]: Index([' jack', 'jill', ' jesse', 'frank'], dtype='object')
Index上的字符串方法对于清理或转换DataFrame列特别有用。例如,您可能有包含前导或尾随空格的列:
In [9]: df = pd.DataFrame(randn(3, 2), columns=[' Column A ', ' Column B '],
...: index=range(3))
...:
In [10]: df
Out[10]:
Column A Column B
0 -1.425575 -1.336299
1 0.740933 1.032121
2 -1.585660 0.913812
由于df.columns
是Index对象,我们可以使用.str
访问器
In [11]: df.columns.str.strip()
Out[11]: Index(['Column A', 'Column B'], dtype='object')
In [12]: df.columns.str.lower()
Out[12]: Index([' column a ', ' column b '], dtype='object')
然后可以根据需要使用这些字符串方法清理列。这里我们删除前导和尾随空格,小写所有名称,并用下划线替换任何剩余的空格:
In [13]: df.columns = df.columns.str.strip().str.lower().str.replace(' ', '_')
In [14]: df
Out[14]:
column_a column_b
0 -1.425575 -1.336299
1 0.740933 1.032121
2 -1.585660 0.913812
注意:如果你有一个
Series
重复大量元素的地方(即它中的独特元素的数量Series
比它的长度小很多Series
),将原始元素转换Series
为类型之一category
然后使用.str.<method>
或者更快就可以更快.dt.<property>
。性能差异来自以下事实:对于Series
类型category
,字符串操作是在.categories
和不在每个元素上完成的Series
。请注意,带字符串
Series
的类型在类型字符串的比较中有一些限制(例如,您不能相互添加字符串:如果是类型,则无法工作)。此外, 在这样的类型上不能使用对 类型元素进行操作的方法。category
.categories
Series
s + " " +s
s
Series
category
.str
list
Series
拆分和替换字符串
方法如split
返回一个列表的系列:
In [15]: s2 = pd.Series(['a_b_c', 'c_d_e', np.nan, 'f_g_h'])
In [16]: s2.str.split('_')
Out[16]:
0 [a, b, c]
1 [c, d, e]
2 NaN
3 [f, g, h]
dtype: object
可以使用get
或[]
表示法访问拆分列表中的元素:
In [17]: s2.str.split('_').str.get(1)
Out[17]:
0 b
1 d
2 NaN
3 g
dtype: object
In [18]: s2.str.split('_').str[1]
Out[18]:
0 b
1 d
2 NaN
3 g
dtype: object
很容易扩展它以使用返回DataFrame expand
。
In [19]: s2.str.split('_', expand=True)
Out[19]:
0 1 2
0 a b c
1 c d e
2 NaN NaN NaN
3 f g h
也可以限制拆分的数量:
In [20]: s2.str.split('_', expand=True, n=1)
Out[20]:
0 1
0 a b_c
1 c d_e
2 NaN NaN
3 f g_h
rsplit
类似于split
它除了反向工作,即从字符串的结尾到字符串的开头:
In [21]: s2.str.rsplit('_', expand=True, n=1)
Out[21]:
0 1
0 a_b c
1 c_d e
2 NaN NaN
3 f_g h
replace
默认情况下替换正则表达式:
In [22]: s3 = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca',
....: '', np.nan, 'CABA', 'dog', 'cat'])
....:
In [23]: s3
Out[23]:
0 A
1 B
2 C
3 Aaba
4 Baca
5
6 NaN
7 CABA
8 dog
9 cat
dtype: object
In [24]: s3.str.replace('^.a|dog', 'XX-XX ', case=False)
Out[24]:
0 A
1 B
2 C
3 XX-XX ba
4 XX-XX ca
5
6 NaN
7 XX-XX BA
8 XX-XX
9 XX-XX t
dtype: object
必须谨慎保持正则表达式!例如,以下代码将导致麻烦,因为$的正则表达式含义 :
# 考虑以下格式糟糕的财务数据
In [25]: dollars = pd.Series(['12', '-$10', '$10,000'])
# 这是你天真地期待的:
In [26]: dollars.str.replace('$', '')
Out[26]:
0 12
1 -10
2 10,000
dtype: object
# 但这并不是:
In [27]: dollars.str.replace('-$', '-')
Out[27]:
0 12
1 -$10
2 $10,000
dtype: object
# 我们需要摆脱特殊字符(用于1个len模式)
In [28]: dollars.str.replace(r'-\$', '-')
Out[28]:
0 12
1 -10
2 $10,000
dtype: object
版本0.23.0中的新功能。
如果确实需要文字替换字符串(相当于 str.replace()
),可以将可选regex
参数设置为 False
,而不是转义每个字符。在这种情况下,两个pat
和repl
必须是字符串:
# 这些线是等价的
In [29]: dollars.str.replace(r'-\$', '-')
Out[29]:
0 12
1 -10
2 $10,000
dtype: object
In [30]: dollars.str.replace('-$', '-', regex=False)
Out[30]:
0 12
1 -10
2 $10,000
dtype: object
版本0.20.0中的新功能。
该replace
方法还可以将可调用作为替换。每次pat
使用都会调用它re.sub()
。callable应该期望一个位置参数(一个正则表达式对象)并返回一个字符串。
# 颠倒每个小写字母的单词
In [31]: pat = r'[a-z]+'
In [32]: repl = lambda m: m.group(0)[::-1]
In [33]: pd.Series(['foo 123', 'bar baz', np.nan]).str.replace(pat, repl)
Out[33]:
0 oof 123
1 rab zab
2 NaN
dtype: object
# 使用正则表达式组
In [34]: pat = r"(?P<one>\w+) (?P<two>\w+) (?P<three>\w+)"
In [35]: repl = lambda m: m.group('two').swapcase()
In [36]: pd.Series(['Foo Bar Baz', np.nan]).str.replace(pat, repl)
Out[36]:
0 bAR
1 NaN
dtype: object
版本0.20.0中的新功能。
该replace
方法还接受来自re.compile()
模式的已编译正则表达式对象。所有标志都应包含在已编译的正则表达式对象中。
In [37]: import re
In [38]: regex_pat = re.compile(r'^.a|dog', flags=re.IGNORECASE)
In [39]: s3.str.replace(regex_pat, 'XX-XX ')
Out[39]:
0 A
1 B
2 C
3 XX-XX ba
4 XX-XX ca
5
6 NaN
7 XX-XX BA
8 XX-XX
9 XX-XX t
dtype: object
使用编译的正则表达式对象flags
调用时包含一个参数replace
将引发一个ValueError
。
In [40]: s3.str.replace(regex_pat, 'XX-XX ', flags=re.IGNORECASE)
---------------------------------------------------------------------------
ValueError: case and flags cannot be set when pat is a compiled regex
连接
有几种方法可以将一个Series
或多个方法Index
与自身或其他方法连接起来,所有这些方法都基于cat()
,或者。Index.str.cat
。
将单个系列连接成字符串
Series
(或Index
)的内容可以连接在一起:
In [41]: s = pd.Series(['a', 'b', 'c', 'd'])
In [42]: s.str.cat(sep=',')
Out[42]: 'a,b,c,d'
如果未指定,则sep
分隔符的关键字默认为空字符串,sep=''
:
In [43]: s.str.cat()
Out[43]: 'abcd'
默认情况下,将忽略缺失值。使用na_rep
,他们可以给出一个表示:
In [44]: t = pd.Series(['a', 'b', np.nan, 'd'])
In [45]: t.str.cat(sep=',')
Out[45]: 'a,b,d'
In [46]: t.str.cat(sep=',', na_rep='-')
Out[46]: 'a,b,-,d'
将系列和类似列表连接成一个系列
第一个参数cat()
可以是类似列表的对象,前提是它与调用Series
(或Index
)的长度匹配。
In [47]: s.str.cat(['A', 'B', 'C', 'D'])
Out[47]:
0 aA
1 bB
2 cC
3 dD
dtype: object
除非 na_rep
指定,否则任何一方缺少值都会导致结果中缺少值:
In [48]: s.str.cat(t)
Out[48]:
0 aa
1 bb
2 NaN
3 dd
dtype: object
In [49]: s.str.cat(t, na_rep='-')
Out[49]:
0 aa
1 bb
2 c-
3 dd
dtype: object
将系列和类似数组的类连接成一个系列
版本0.23.0中的新功能。
该参数others
也可以是二维的。在这种情况下,一个或多个行必须与调用Series
(或Index
)的长度匹配。
In [50]: d = pd.concat([t, s], axis=1)
In [51]: s
Out[51]:
0 a
1 b
2 c
3 d
dtype: object
In [52]: d
Out[52]:
0 1
0 a a
1 b b
2 NaN c
3 d d
In [53]: s.str.cat(d, na_rep='-')
Out[53]:
0 aaa
1 bbb
2 c-c
3 ddd
dtype: object
将系列和索引对象连接成一个系列,具有对齐
版本0.23.0中的新功能。
对于具有串联Series
或DataFrame
,可以通过设置对齐连接前的指标join
-关键词。
In [54]: u = pd.Series(['b', 'd', 'a', 'c'], index=[1, 3, 0, 2])
In [55]: s
Out[55]:
0 a
1 b
2 c
3 d
dtype: object
In [56]: u
Out[56]:
1 b
3 d
0 a
2 c
dtype: object
In [57]: s.str.cat(u)
Out[57]:
0 ab
1 bd
2 ca
3 dc
dtype: object
In [58]: s.str.cat(u, join='left')
Out[58]:
0 aa
1 bb
2 cc
3 dd
dtype: object
警告:如果
join
未传递关键字,则该方法cat()
将回退到版本0.23.0之前的行为(即无对齐),但FutureWarning
如果任何涉及的索引不同,则将引发a ,因为此默认值将更改为join='left'
将来的版本。
通常的选项可用于join
(其中之一)。特别地,对齐还意味着不同长度不再需要重合。'left', 'outer', 'inner','right'
In [59]: v = pd.Series(['z', 'a', 'b', 'd', 'e'], index=[-1, 0, 1, 3, 4])
In [60]: s
Out[60]:
0 a
1 b
2 c
3 d
dtype: object
In [61]: v
Out[61]:
-1 z
0 a
1 b
3 d
4 e
dtype: object
In [62]: s.str.cat(v, join='left', na_rep='-')
Out[62]:
0 aa
1 bb
2 c-
3 dd
dtype: object
In [63]: s.str.cat(v, join='outer', na_rep='-')
Out[63]:
-1 -z
0 aa
1 bb
2 c-
3 dd
4 -e
dtype: object
当others
a DataFrame
:时,可以使用相同的对齐方式:
In [64]: f = d.loc[[3, 2, 1, 0], :]
In [65]: s
Out[65]:
0 a
1 b
2 c
3 d
dtype: object
In [66]: f
Out[66]:
0 1
3 d d
2 NaN c
1 b b
0 a a
In [67]: s.str.cat(f, join='left', na_rep='-')
Out[67]:
0 aaa
1 bbb
2 c-c
3 ddd
dtype: object
将一系列和多个对象连接成一个系列
所有一维列表都可以任意组合在类似列表的容器中(包括迭代器,dict
-views等):
In [68]: s
Out[68]:
0 a
1 b
2 c
3 d
dtype: object
In [69]: u
Out[69]:
1 b
3 d
0 a
2 c
dtype: object
In [70]: s.str.cat([u, pd.Index(u.values), ['A', 'B', 'C', 'D'], map(str, u.index)], na_rep='-')
Out[70]:
0 abbA1
1 bddB3
2 caaC0
3 dccD2
dtype: object
所有元素的长度必须与调用Series
(或Index
)匹配,但具有索引的那些元素(如果join
不是None )除外:
In [71]: v
Out[71]:
-1 z
0 a
1 b
3 d
4 e
dtype: object
In [72]: s.str.cat([u, v, ['A', 'B', 'C', 'D']], join='outer', na_rep='-')
Out[72]:
-1 --z-
0 aaaA
1 bbbB
2 cc-C
3 dddD
4 --e-
dtype: object
如果join='right'
在others
包含不同索引的列表上使用,则这些索引的并集将用作最终串联的基础:
In [73]: u.loc[[3]]
Out[73]:
3 d
dtype: object
In [74]: v.loc[[-1, 0]]
Out[74]:
-1 z
0 a
dtype: object
In [75]: s.str.cat([u.loc[[3]], v.loc[[-1, 0]]], join='right', na_rep='-')
Out[75]:
-1 --z
0 a-a
3 dd-
dtype: object
索引与.str
您可以使用[]
符号直接按位置索引。如果索引超过字符串的结尾,则结果为a NaN
。
In [76]: s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan,
....: 'CABA', 'dog', 'cat'])
....:
In [77]: s.str[0]
Out[77]:
0 A
1 B
2 C
3 A
4 B
5 NaN
6 C
7 d
8 c
dtype: object
In [78]: s.str[1]
Out[78]:
0 NaN
1 NaN
2 NaN
3 a
4 a
5 NaN
6 A
7 o
8 a
dtype: object
提取子字符串
提取每个主题的第一场比赛(摘录)
警告:在版本0.18.0中,
extract
获得了expand
争论。当expand=False
它返回aSeries
,Index
或时DataFrame
,取决于主题和正则表达式模式(与0.18.0之前的行为相同)。当expand=True
它总是返回a时DataFrame
,从用户的角度来看,它更加一致并且不那么混乱。expand=True
是自版本0.23.0以来的默认值。
该extract
方法接受具有至少一个捕获组的正则表达式。
提取具有多个组的正则表达式将返回一个DataFrame,每个组包含一列。
In [79]: pd.Series(['a1', 'b2', 'c3']).str.extract('([ab])(\d)', expand=False)
Out[79]:
0 1
0 a 1
1 b 2
2 NaN NaN
不匹配的元素返回一行填充NaN
。因此,一系列杂乱的字符串可以“转换”为类似索引的系列或DataFrame中的清理或更有用的字符串,而无需get()
访问元组或re.match
对象。结果的dtype始终是object,即使找不到匹配且结果只包含NaN
。
命名组如
In [80]: pd.Series(['a1', 'b2', 'c3']).str.extract('(?P<letter>[ab])(?P<digit>\d)', expand=False)
Out[80]:
letter digit
0 a 1
1 b 2
2 NaN NaN
和可选组一样
In [81]: pd.Series(['a1', 'b2', '3']).str.extract('([ab])?(\d)', expand=False)
Out[81]:
0 1
0 a 1
1 b 2
2 NaN 3
也可以使用。请注意,正则表达式中的任何捕获组名称都将用于列名称; 否则将使用捕获组编号。
DataFrame
如果使用一个组提取正则表达式,则返回一个列expand=True
。
In [82]: pd.Series(['a1', 'b2', 'c3']).str.extract('[ab](\d)', expand=True)
Out[82]:
0
0 1
1 2
2 NaN
它返回一个Series if expand=False
。
In [83]: pd.Series(['a1', 'b2', 'c3']).str.extract('[ab](\d)', expand=False)
Out[83]:
0 1
1 2
2 NaN
dtype: object
调用上Index
用正则表达式可以精确到一个捕获组返回一个DataFrame
带有如果一列expand=True
。
In [84]: s = pd.Series(["a1", "b2", "c3"], ["A11", "B22", "C33"])
In [85]: s
Out[85]:
A11 a1
B22 b2
C33 c3
dtype: object
In [86]: s.index.str.extract("(?P<letter>[a-zA-Z])", expand=True)
Out[86]:
letter
0 A
1 B
2 C
它返回一个Index
if expand=False
。
In [87]: s.index.str.extract("(?P<letter>[a-zA-Z])", expand=False)
Out[87]: Index(['A', 'B', 'C'], dtype='object', name='letter')
Index
使用具有多个捕获组的正则表达式调用返回DataFrame
if expand=True
。
In [88]: s.index.str.extract("(?P<letter>[a-zA-Z])([0-9]+)", expand=True)
Out[88]:
letter 1
0 A 11
1 B 22
2 C 33
它提出ValueError
如果expand=False
。
>>> s.index.str.extract("(?P<letter>[a-zA-Z])([0-9]+)", expand=False)
ValueError: only one regex group is supported with Index
下表总结了extract(expand=False)
(第一列中的输入主题,第一行中的正则表达式中的组数)的行为
1组 | > 1组 | |
指数 | 指数 | ValueError异常 |
系列 | 系列 | 数据帧 |
提取每个主题的所有匹配(extractall)
版本0.18.0中的新功能。
与extract
(仅返回第一场比赛)不同,
In [89]: s = pd.Series(["a1a2", "b1", "c1"], index=["A", "B", "C"])
In [90]: s
Out[90]:
A a1a2
B b1
C c1
dtype: object
In [91]: two_groups = '(?P<letter>[a-z])(?P<digit>[0-9])'
In [92]: s.str.extract(two_groups, expand=True)
Out[92]:
letter digit
A a 1
B b 1
C c 1
该extractall
方法返回每个匹配。结果 extractall
总是DataFrame
带有MultiIndex
一行。最后一级MultiIndex
被命名match
并指示主题中的顺序。
In [93]: s.str.extractall(two_groups)
Out[93]:
letter digit
match
A 0 a 1
1 a 2
B 0 b 1
C 0 c 1
当系列中的每个主题字符串只有一个匹配时,
In [94]: s = pd.Series(['a3', 'b3', 'c2'])
In [95]: s
Out[95]:
0 a3
1 b3
2 c2
dtype: object
然后给出相同的结果 。extractall(pat).xs(0, level='match')
extract(pat)
In [96]: extract_result = s.str.extract(two_groups, expand=True)
In [97]: extract_result
Out[97]:
letter digit
0 a 3
1 b 3
2 c 2
In [98]: extractall_result = s.str.extractall(two_groups)
In [99]: extractall_result
Out[99]:
letter digit
match
0 0 a 3
1 0 b 3
2 0 c 2
In [100]: extractall_result.xs(0, level="match")
Out[100]:
letter digit
0 a 3
1 b 3
2 c 2
Index
也支持.str.extractall
。它返回的DataFrame
结果Series.str.extractall
与使用默认索引的结果相同(从0开始)。
版本0.19.0中的新功能。
In [101]: pd.Index(["a1a2", "b1", "c1"]).str.extractall(two_groups)
Out[101]:
letter digit
match
0 0 a 1
1 a 2
1 0 b 1
2 0 c 1
In [102]: pd.Series(["a1a2", "b1", "c1"]).str.extractall(two_groups)
Out[102]:
letter digit
match
0 0 a 1
1 a 2
1 0 b 1
2 0 c 1
测试匹配或包含模式的字符串
您可以检查元素是否包含模式:
In [103]: pattern = r'[0-9][a-z]'
In [104]: pd.Series(['1', '2', '3a', '3b', '03c']).str.contains(pattern)
Out[104]:
0 False
1 False
2 True
3 True
4 True
dtype: bool
或者元素是否与模式匹配:
In [105]: pd.Series(['1', '2', '3a', '3b', '03c']).str.match(pattern)
Out[105]:
0 False
1 False
2 True
3 True
4 False
dtype: bool
区别match
和contains
严格之间的区别:match
依赖严格re.match
,contains
依赖re.search
。
方法,如match
,contains
,startswith
,并endswith
采取额外的na
参数,所以遗漏值可以被认为是真或假:
In [106]: s4 = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])
In [107]: s4.str.contains('A', na=False)
Out[107]:
0 True
1 False
2 False
3 True
4 False
5 False
6 True
7 False
8 False
dtype: bool
创建指标变量
您可以从字符串列中提取虚拟变量。例如,如果它们被以下分隔'|'
:
In [108]: s = pd.Series(['a', 'a|b', np.nan, 'a|c'])
In [109]: s.str.get_dummies(sep='|')
Out[109]:
a b c
0 1 0 0
1 1 1 0
2 0 0 0
3 1 0 1
String Index
还支持get_dummies
返回a MultiIndex
。
版本0.18.1中的新功能。
In [110]: idx = pd.Index(['a', 'a|b', np.nan, 'a|c'])
In [111]: idx.str.get_dummies(sep='|')
Out[111]:
MultiIndex(levels=[[0, 1], [0, 1], [0, 1]],
labels=[[1, 1, 0, 1], [0, 1, 0, 0], [0, 0, 0, 1]],
names=['a', 'b', 'c'])
方法摘要
方法 | 描述 |
---|---|
cat() | 连接字符串 |
split() | 拆分分隔符上的字符串 |
rsplit() | 从字符串末尾开始分隔字符串上的字符串 |
get() | 索引到每个元素(检索第i个元素) |
join() | 使用传递的分隔符连接Series的每个元素中的字符串 |
get_dummies() | 在分隔符上拆分字符串,返回虚拟变量的DataFrame |
contains() | 如果每个字符串包含pattern / regex,则返回布尔数组 |
replace() | 将pattern / regex / string的出现替换为其他字符串或给定事件的可调用的返回值 |
repeat() | 重复值(s.str.repeat(3) 相当于)x * 3 |
pad() | 在字符串的左侧,右侧或两侧添加空格 |
center() | 相当于 str.center |
ljust() | 相当于 str.ljust |
rjust() | 相当于 str.rjust |
zfill() | 相当于 str.zfill |
wrap() | 将长字符串拆分为长度小于给定宽度的行 |
slice() | 切割系列中的每个字符串 |
slice_replace() | 用传递的值替换每个字符串中的切片 |
count() | 计算模式的出现次数 |
startswith() | 相当于str.startswith(pat) 每个元素 |
endswith() | 相当于str.endswith(pat) 每个元素 |
findall() | 计算每个字符串的所有出现的pattern / regex的列表 |
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 |
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 |