In [1]: import numpy as np
In [2]: import pandas as pd
1. str对象的设计意图
str
对象是定义在 Index
或 Series
上的属性,专门用于处理每个元素的文本内容,其内部定义了大量方法,因此对一个序列进行文本处理,首先需要获取其 str
对象。在Python标准库中也有 str
模块,为了使用上的便利,有许多函数的用法 pandas
照搬了它的设计,例如字母转为大写的操作:
In [3]: var = 'abcd'
In [4]: str.upper(var) # Python内置str模块
Out[4]: 'ABCD'
In [5]: s = pd.Series(['abcd', 'efg', 'hi'])
In [6]: s.str
Out[6]: <pandas.core.strings.accessor.StringMethods at 0x264028543c8>
In [7]: s.str.upper() # pandas中str对象上的upper方法
Out[7]:
0 ABCD
1 EFG
2 HI
dtype: object
根据文档 API
材料,在 pandas
的50个 str
对象方法中,有31个是和标准库中的 str
模块方法同名且功能一致,这为批量处理序列提供了有力的工具。
2. []索引器
对于 str
对象而言,可理解为其对字符串进行了序列化的操作,例如在一般的字符串中,通过 []
可以取出某个位置的元素:
In [8]: var[0]
Out[8]: 'a'
同时也能通过切片得到子串:
In [9]: var[-1: 0: -2]
Out[9]: 'db'
通过对 str
对象使用 []
索引器,可以完成完全一致的功能,并且如果超出范围则返回缺失值:
In [10]: s.str[0]
Out[10]:
0 a
1 e
2 h
dtype: object
In [11]: s.str[-1: 0: -2]
Out[11]:
0 db
1 g
2 i
dtype: object
In [12]: s.str[2]
Out[12]:
0 c
1 g
2 NaN
dtype: object
3. string类型
在上一章提到,从 pandas
的 1.0.0
版本开始,引入了 string
类型,其引入的动机在于:原来所有的字符串类型都会以 object
类型的 Series
进行存储,但 object
类型只应当存储混合类型,例如同时存储浮点、字符串、字典、列表、自定义类型等,因此字符串有必要同数值型或 category
一样,具有自己的数据存储类型,从而引入了 string
类型。
总体上说,绝大多数对于 object
和 string
类型的序列使用 str
对象方法产生的结果是一致,但是在下面提到的两点上有较大差异:
首先,应当尽量保证每一个序列中的值都是字符串的情况下才使用 str
属性,但这并不是必须的,其必要条件是序列中至少有一个可迭代(Iterable)对象,包括但不限于字符串、字典、列表。对于一个可迭代对象, string
类型的 str
对象和 object
类型的 str
对象返回结果可能是不同的。
In [13]: s = pd.Series([{1: 'temp_1', 2: 'temp_2'}, ['a', 'b'], 0.5, 'my_string'])
In [14]: s.str[1]
Out[14]:
0 temp_1
1 b
2 NaN
3 y
dtype: object
In [15]: s.astype('string').str[1]
Out[15]:
0 1
1 '
2 .
3 y
dtype: string
除了最后一个字符串元素,前三个元素返回的值都不同,其原因在于当序列类型为 object
时,是对于每一个元素进行 []
索引,因此对于字典而言,返回temp_1字符串,对于列表则返回第二个值,而第三个为不可迭代对象,返回缺失值,第四个是对字符串进行 []
索引。而 string
类型的 str
对象先把整个元素转为字面意义的字符串,例如对于列表而言,第一个元素即 “{“,而对于最后一个字符串元素而言,恰好转化前后的表示方法一致,因此结果和 object
类型一致。
除了对于某些对象的 str
序列化方法不同之外,两者另外的一个差别在于, string
类型是 Nullable
类型,但 object
不是。这意味着 string
类型的序列,如果调用的 str
方法返回值为整数 Series
和布尔 Series
时,其分别对应的 dtype
是 Int
和 boolean
的 Nullable
类型,而 object
类型则会分别返回 int/float
和 bool/object
,取决于缺失值的存在与否。同时,字符串的比较操作,也具有相似的特性, string
返回 Nullable
类型,但 object
不会。
In [16]: s = pd.Series(['a'])
In [17]: s.str.len()
Out[17]:
0 1
dtype: int64
In [18]: s.astype('string').str.len()
Out[18]:
0 1
dtype: Int64
In [19]: s == 'a'
Out[19]:
0 True
dtype: bool
In [20]: s.astype('string') == 'a'
Out[20]:
0 True
dtype: boolean
In [21]: s = pd.Series(['a', np.nan]) # 带有缺失值
In [22]: s.str.len()
Out[22]:
0 1.0
1 NaN
dtype: float64
In [23]: s.astype('string').str.len()
Out[23]:
0 1
1 <NA>
dtype: Int64
In [24]: s == 'a'
Out[24]:
0 True
1 False
dtype: bool
In [25]: s.astype('string') == 'a'
Out[25]:
0 True
1 <NA>
dtype: boolean
最后需要注意的是,对于全体元素为数值类型的序列,即使其类型为 object
或者 category
也不允许直接使用 str
属性。如果需要把数字当成 string
类型处理,可以使用 astype
强制转换为 string
类型的 Series
:
In [26]: s = pd.Series([12, 345, 6789])
In [27]: s.astype('string').str[1]
Out[27]:
0 2
1 4
2 7
dtype: string
下一节:这一节的两个表格来自于 learn-regex-zh 这个关于正则表达式项目,其使用 MIT 开源许可协议。这里只是介绍正则表达式的基本用法,需要系统学习的读者可参考 正则表达式必知必会 一书。