处理文本数据#

文本数据类型#

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

  1. object-dtype NumPy 数组。

  2. StringDtype扩展类型。

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

在 pandas 1.0 之前,objectdtype 是唯一的选择。由于多种原因,这是不幸的:

  1. 您可能会意外地将字符串和非字符串 混合object存储在dtype 数组中。最好有一个专用的 dtype。

  2. objectdtype 会破坏特定于 dtype 的操作,例如DataFrame.select_dtypes().没有明确的方法来选择文本,同时排除非文本但仍然是对象数据类型的列。

  3. 阅读代码时,dtype 数组的内容object不如'string'.

object目前, dtype 字符串数组和 dtype 数组 的性能arrays.StringArray大致相同。我们预计未来的增强功能将显着提高性能并降低 StringArray.

警告

StringArray目前被认为是实验性的。 API 的实现和部分可能会在没有警告的情况下发生更改。

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

 In [1]: pd.Series(["a", "b", "c"])
Out[1]: 
0    a
1    b
2    c
dtype: object

要显式请求stringdtype,请指定dtype

 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

或者创建orastype之后SeriesDataFrame

 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,它将转换为stringdtype:

 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 数据转换:

 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数据类型不同的地方

  1. 对于StringDtype, 返回数字输出的字符串访问器方法将始终返回可为空的整数数据类型,而不是 int 或 float 数据类型,具体取决于 NA 值的存在。返回布尔输出的方法将返回可为空的布尔数据类型。

     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
    

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

     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 值时,输出数据类型为 float64。对于返回布尔值的方法也是如此。

     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
    
  1. 某些字符串方法(如 )Series.str.decode()不可用,StringArray因为StringArray仅保存字符串,而不保存字节。

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

本文档其余部分中的所有其他内容同样适用于 stringdtype object

字符串方法#

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

 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
 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 列特别有用。例如,您的列可能带有前导或尾随空格:

 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访问器

 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')

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

 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远小于 的长度 ),则将原始类型转换为一种类型 ,然后在其上使用orSeries可能会更快。性能差异来自于以下事实:对于of 类型,字符串操作是在 上完成的,而不是在 的每个元素上 完成的。Seriescategory.str.<method>.dt.<property>Seriescategory.categoriesSeries

请注意,与 string 类型相比,带有 string 的a Seriesof 类型有一些限制(例如,您不能将字符串相互添加:如果是 a of 类型则不起作用)。此外, 对类型元素进行操作的方法在此类 .category.categoriesSeriess + " " + ssSeriescategory.strlistSeries

警告

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

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

分割和替换字符串#

split类似返回一系列列表的方法:

 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可以使用或符号来访问拆分列表中的元素[]

 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

使用 可以很容易地扩展它以返回 DataFrame expand

 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

当 OriginalSeries有时StringDtype,输出列也将全部StringDtype如此。

还可以限制分割数量:

 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但它以相反的方向工作,即从字符串的末尾到字符串的开头:

 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可以选择使用正则表达式

 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版本中有所改变。

单字符模式 withregex=True也将被视为正则表达式:

 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()),可以将可选参数设置regexFalse,而不是转义每个字符。在这种情况下, 和 都pat必须repl是字符串:

 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()。可调用函数应该需要一个位置参数(一个正则表达式对象)并返回一个字符串。

 # 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()作为模式。所有标志都应包含在编译的正则表达式对象中。

 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

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

 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

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

1.4.0 版本中的新增内容。

 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

连接#

有多种方法可以将SeriesorIndex与自身或其他连接,所有方法均基于cat()、 或 。Index.str.cat

将单个系列连接成字符串#

Seriesa (或)的内容Index可以连接起来:

 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=''

 In [70]: s.str.cat()
Out[70]: 'abcd'

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

 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'

将一个系列和类似列表的内容连接成一个系列#

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

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

两侧缺失值也会导致结果中缺失值,除非 na_rep指定:

 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

将一个系列和类似数组的东西连接成一个系列#

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

 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,并对齐#

对于与 aSeries或 的串联DataFrame,可以通过设置join- 关键字在串联之前对齐索引。

 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'

 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当是 a 时,可以使用相同的对齐方式DataFrame

 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 #

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

 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):

 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

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

 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.

 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方法接受具有至少一个捕获组的正则表达式。

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

 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。因此,一系列杂乱的字符串可以“转换”为类似索引的系列或清理过的或更有用的字符串的数据帧,而无需get()访问元组或re.match对象。结果的 dtype 始终为 object,即使未找到匹配且结果仅包含NaN.

命名组如

 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>

和可选的组,例如

 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 包含一列的 if expand=True

 In [109]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"[ab](\d)", expand=True)
Out[109]: 
      0
0     1
1     2
2  <NA>

如果 则返回一个系列expand=False

 In [110]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"[ab](\d)", expand=False)
Out[110]: 
0       1
1       2
2    <NA>
dtype: string

Index使用仅包含一个捕获组的正则表达式调用an 会返回DataFrame包含一列的 a if expand=True

 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

它返回一个Indexif expand=False

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

Index使用具有多个捕获组的正则表达式调用会返回DataFrameif expand=True

 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

它会引发ValueErrorif expand=False

 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组

指数

指数

值错误

系列

系列

数据框

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

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

 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始终是 a,其行上DataFrame有 a 。MultiIndex最后一级MultiIndex被命名match并指示主题中的顺序。

 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

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

 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)

 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.它返回的 a与具有默认索引(从 0 开始)的DataFramea 具有相同的结果。Series.str.extractall

 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

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

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

 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

或者元素是否匹配模式:

 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
 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

笔记

matchfullmatch、之间的区别contains是严格性: fullmatch测试整个字符串是否与正则表达式匹配; match测试从字符串第一个字符开始的正则表达式是否匹配;并contains测试字符串中任意位置是否存在正则表达式匹配。

re这三种匹配模式 在包中对应的函数分别是re.fullmatchre.matchre.search

matchfullmatchcontainsstartswith和 等方法endswith需要一个额外的na参数,因此缺失值可以被视为 True 或 False:

 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

创建指示变量#

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

 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

StringIndex还支持get_dummies返回MultiIndex.

 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()

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

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()

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

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