数据处理,也是风控非常重要的一个环节,甚至说是模型成败的关键环节。因此,娴熟简洁的数据处理技巧,是提高建模效率和建模质量的必要能力。
向量化操作的概述
对于文本数据的处理(清洗),是现实工作中的数据时不可或缺的功能,在这一节中,我们将介绍Pandas的字符串操作。Python内置一系列强大的字符串处理方法,但这些方法只能处理单个字符串,处理一个序列的字符串时,需要用到for循环。
那么,有没有办法,不用循环就能同时处理多个字符串呢,Pandas的向量化操作(vectorized string operation)就提供了这样的方法。Pandas为可能存在字符串的Series和Index对象提供了str属性,不仅能够进行向量化操作,还能够处理缺失值。
向量化的操作使我们不必担心数组的长度和维度,只需要关系操作功能,尤为强大的是,除了支持常用的字符串操作方法,还集成了正则表达式的大部分功能,这使得pandas在处理字符串列时,具有非常大的魔力。
例如,要计算每个单词中‘a’的个数,下面一行代码就可以搞定,非常高效
s = pd.Series(['amazon','alibaba','baidu'])
s.str.count('a')
0 2
1 3
2 1
假如用内置的字符串函数进行操作,需要进行遍历,且Python原生的遍历操作无法处理缺失值。
#用循环进行处理
s = ['amazon','alibaba','baidu']
[i.count('a') for i in s]
[2, 3, 1]#存在缺失值时,打印报错
s = ['amazon','alibaba','baidu',None]
[i.count('a') for i in s]
AttributeError: 'NoneType' object has no attribute 'lower'
Pandas的向量化操作,能够正确的处理缺失值,无报错信息,如下
s = pd.Series(['amazon','alibaba','baidu',None])
s.str.count('a')
Out[36]:
0 2.0
1 3.0
2 1.0
3 NaN
dtype: float64
通过上面的例子,对向量化进行简单总结,向量化是一种同时操作整个数组而不是一次操作一个元素的方法,下面从看看具体怎么应用。
向量化的字符串处理方法
Pandas的字符串属的方法几乎包括了大部分Python的内置字符串方法(内置共有45个方法),下面将列举一些常见的方法的用法,例如上面的count()方法将会返回某个字符的个数,而len方法将会返回整个字符的长度。
下面选取部分函数举例,其他函数参考字符串模块
1、len()
import pandas as pd
import numpy as np s = pd.Series(['amazon','alibaba','Baidu'])
s.str.len()
0 6
1 7
2 5
2、lower()
大小写转换,转换成小写字母
s = pd.Series(['Amazon','alibaba','Baidu'])
s.str.lower()
0 amazon
1 alibaba
2 baidu
3、zfill()
右对齐,前面用0填充到指定字符串长度
s = pd.Series(['56783','34','987766721','326'])
s.str.zfill(10)
0 0000056783
1 0000000034
2 0987766721
3 0000000326
字符串的方法很多,这里就不一一举例了,大家可以参考字符串处理的文章。
向量化的正则表达式
Pandas的字符串方法根据Python标准库的re模块实现了正则表达式,下面将介绍Pandas的str属性内置的正则表达式相关方法
1、split()
split,按指定字符或表达式分割字符串,类似split的方法返回一个列表类型的序列
1)基本用法
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.str.split.html
Series.str.split(pat=None,n=- 1, expand=False, *, regex=None )
2)参数解释
pat:str 或编译的正则表达式,可选。要拆分的字符串或正则表达式。如果未指定,则在空格处拆分。
n:int,默认 -1(全部)。限制输出中的拆分数量, None , 0 和 -1 将被解释为返回所有拆分。
expand:布尔值,默认为 False。将拆分的字符串展开为单独的列。
-
如果 True ,返回 DataFrame/MultiIndex 扩展维度。
-
如果 False ,则返回包含字符串列表的系列/索引。
regex:布尔值,默认无。确定 passed-in 模式是否为正则表达式:
-
如果 True ,假设 passed-in 模式是正则表达式
-
如果 False ,则将模式视为文字字符串。
-
如果 None 和 pat 长度为 1,则将 pat 视为文字字符串。
-
如果 None 和 pat 长度不为 1,则将 pat 视为正则表达式。
-
如果 pat 是已编译的正则表达式,则不能设置为 False
注 意:n 关键字的处理取决于找到的拆分数量:
-
如果发现拆分 > n ,请先进行 n 拆分
-
如果发现拆分 n ,则进行所有拆分
-
如果对于某一行,找到的拆分数 n ,则追加 None 以填充到 n if expand=True
如果使用 expand=True ,Series 和 Index 调用者分别返回 DataFrame 和 MultiIndex 对象。使用带有pat 的regex=False 作为编译的正则表达式会引发错误。
3)案例分析
#按数字分割
s = pd.Series(['QQ1252号码','QQ1353加我','我389的'])
s.str.split('\d+')
0 [QQ, 号码]
1 [QQ, 加我]
2 [我, 的]# 按固定字符分割
s = pd.Series(['a_b_c', 'c_d_e', np.nan, 'f_g_h'])
s.str.split('_')0 [a, b, c]
1 [c, d, e]
2 NaN
3 [f, g, h]#切分后的列表中的元素可以通过get方法或者 [] 方法进行读取
s.str.split('_').str.get(1)
Out[96]:
0 b
1 d
2 NaN
3 g#使用expand方法可以轻易地将这种返回展开为一个数据表
s.str.split('_', expand=True)0 1 2
0 a b c
1 c d e
2 NaN NaN NaN
3 f g h#同样,我们也可以限制切分的次数:
s.str.split('_', expand=True, n=1)0 1
0 a b_c
1 c d_e
2 NaN NaN
3 f g_h
2、rsplit()
rsplit与split相似,不同的是,这个切分的方向是反的,即,从字串的尾端向首段切分
1)基础用法
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.str.rsplit.html
Series.str.rsplit(pat=None, n=- 1, expand=False)
2)参数解释
pat:str 或编译的正则表达式,可选。要拆分的字符串或正则表达式。如果未指定,则在空格处拆分。
n:int,默认 -1(全部)。限制输出中的拆分数量。None , 0 和 -1 将被解释为返回所有拆分。
expand:布尔值,默认为 False。将拆分的字符串展开为单独的列。
-
如果 True ,返回 DataFrame/MultiIndex 扩展维度。
-
如果 False ,则返回包含字符串列表的系列/索引。
3)案例分析
s = pd.Series(['QQ1252号码','QQ1353加我','我389的'])
s.str.rsplit('_', expand=True, n=1)0 1
0 a_b c
1 c_d e
2 NaN NaN
3 f_g h
3、replace ()
1)基本用法
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.str.replace.html
Series.str.replace(pat, repl, n=- 1, case=None, flags=0, regex=None)
2)参数解释
pat:str 或编译的正则表达式,字符串可以是字符序列或正则表达式。
repl:str 或可调用,替换字符串或可调用对象。可调用对象传递正则表达式匹配对象,并且必须返回要使用的替换字符串。
n:int,默认 -1(全部)从一开始就更换的数量。
case:布尔值,默认无。确定替换是否区分大小写:
-
如果为 True,则区分大小写(如果 pat 是字符串,则默认为)
-
设置为 False 不区分大小写
-
如果 pat 是已编译的正则表达式,则无法设置。
flags:int,默认 0(无标志)。正则表达式模块标志,例如重新忽略。如果 pat 是已编译的正则表达式,则无法设置。
regex:布尔值,默认为真。确定 passed-in 模式是否为正则表达式:
-
如果为 True,则假定 passed-in 模式是正则表达式。
-
如果为 False,则将模式视为文字字符串
-
如果 pat 是已编译的正则表达式或 repl 是可调用的,则不能设置为 False。
3)案例分析
replace方法默认使用正则表达式
s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca','', np.nan, 'CABA', 'dog', 'cat'])s.str.replace('^.a|dog', 'XX-XX ', case=False)
Out[27]:
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 tpd.Series(['foo', 'fuz', np.nan]).str.replace('f.', 'ba', regex=True)
0 bao
1 baz
2 NaNpd.Series(['f.o', 'fuz', np.nan]).str.replace('f.', 'ba', regex=False)
0 bao
1 fuz
2 NaN
4、findall()
1)基础用法
Series.str.findall(pat, flags=0)
2)参数解释
pat:正则表达式
flags:Flags from re module, e.g. re.IGNORECASE (default is 0, which means no flags),是否忽略大小写。
3)案例分析
import re
#提取聊天记录中的QQ号
s=pd.Series(['QQ号码123452124','QQ123356123','我的Q123356189','Q号123356111注意','加我Q号123356124有惊喜'])
s.str.findall('\d+')
0 [123452124]
1 [123356123]
2 [123356189]
3 [123356111]
4 [123356124]s.str.findall('Q')
0 [Q, Q]
1 [Q, Q]
2 [Q]
3 [Q]
4 [Q]s.str.findall('q')
0 []
1 []
2 []
3 []
4 []s.str.findall('q', flags=re.IGNORECASE)0 [Q, Q]
1 [Q, Q]
2 [Q]
3 [Q]
4 [Q]