1、字符串操作
Python能够成为流行的数据处理语言,部分原因是其简单易用的字符串和文本处理功能。大部分文本运算都直接做成了字符串对象的内置方法。对于更为复杂的模式匹配和文本操作,则可能需要用到正则表达式。pandas对此进行了加强,它使你能够对数组数据应用字符串表达式和正则表达式,而且能处理烦人的缺失数据。
2、字符串对象方法
对于大部分字符串处理应用而言,内置的字符串方法已经能够满足要求了。例如,以逗号分隔的字符串可以用split拆分成数段:
1.
In [
81
]: val =
'a,b, guido'
2.
3.
In [
82
]: val.split(
','
)
4.
Out[
82
]: [
'a'
,
'b'
,
' guido'
]
1.
In [
83
]: pieces = [x.strip()
for
x in val.split(
','
)]
2.
3.
In [
84
]: pieces
4.
Out[
84
]: [
'a'
,
'b'
,
'guido'
]
1.
In [
88
]: first, second, third = pieces
2.
3.
In [
89
]: first +
'::'
+ second +
'::'
+ third
4.
Out[
89
]:
'a::b::guido'
1.
In [
90
]:
'::'
.join(pieces)
2.
Out[
90
]:
'a::b::guido'
1.
In [
92
]:
'guido'
in val
2.
Out[
92
]: True
3.
4.
In [
93
]: val.index(
','
)
5.
Out[
93
]:
1
6.
7.
In [
95
]: val.find(
':'
)
8.
Out[
95
]: -
1
1.
In [
96
]: val.index(
':'
)
2.
---------------------------------------------------------------------------
3.
ValueError Traceback (most recent call last)
4.
/home/wss/program/python/<ipython-input-
96
-280f8b2856ce> in <module>()
5.
---->
1
val.index(
':'
)
6.
7.
ValueError: substring not found
1.
In [
97
]: val.count(
','
)
2.
Out[
97
]:
2
1.
In [
98
]: val.replace(
','
,
'::'
)
2.
Out[
98
]:
'a::b:: guido'
3.
4.
In [
99
]: val.replace(
','
,
''
)
5.
Out[
99
]:
'ab guido'
说明:
这些运算大部分都能使用正则表达式实现。
3、正则表达式
正则表达式(regex)提供了一种灵活的在文本中搜索或匹配字符串模式的方式。正则表达式是根据正则表达式语言编写的字符串。Python内置的re模块负责对字符串应用正则表达式。
推荐书籍:《Learn Regex The Hard Way》
re模块的函数可以分为三个大类:模式匹配、替换以及拆分。当然,它们之间是相辅相成的。一个regex描述了需要在文本中定位的一个模式,它可以用于许多目的。我们先来看一个简单的例子:假设我想要拆分一个字符串,分隔符为数量不定的一组空白符(制表符、空格、换行符等)。描述一个或多个空白符的regex是\s+:
1.
In [
100
]:
import
re
2.
3.
In [
101
]: text =
"foo bar\t baz \tqux"
4.
5.
In [
102
]: re.split(
'\s+'
, text)
6.
Out[
102
]: [
'foo'
,
'bar'
,
'baz'
,
'qux'
]
1.
In [
103
]: regex = re.compile(
'\s+'
)
2.
3.
In [
104
]: regex.split(text)
4.
Out[
104
]: [
'foo'
,
'bar'
,
'baz'
,
'qux'
]
1.
In [
105
]: regex.findall(text)
2.
Out[
105
]: [
' '
,
'\t '
,
' \t'
]
注意:
如果想避免正则表达式中不需要的转义(\),则可以使用原始字符串字面量如r'C:\x'(也可以编写其等价式'C:\\x')。
如果打算对许多字符串应用同一条正则表达式,强烈建议通过re.compile创建regex对象。这样将可以节省大量的CPU时间。
match和search跟findall功能类似。findall返回的是字符串中所有的匹配项,而search则只返回第一个匹配项。match更加严格,它只匹配字符串的首部。来看一个小例子,假设我们有一段文本以及一条能够识别大部分电子邮件地址的正则表达式:
01.
In [
106
]: text =
""
"Dave dave
@google
.com
02.
.....: Steve steve
@gmail
.com
03.
.....: Rob rob
@gmail
.com
04.
.....: Ryan ryan
@yahoo
.com
05.
.....:
""
"
06.
07.
In [
107
]: pattern = r
'[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'
08.
09.
In [
108
]: # re.IGNORECASE的作用是使用正则表达式对大小写不敏感
10.
11.
In [
109
]: regex = re.compile(pattern, flags=re.IGNORECASE)
1.
In [
116
]: regex.findall(text)
2.
Out[
116
]: [
'dave@google.com'
,
'steve@gmail.com'
,
'rob@gmail.com'
,
'ryan@yahoo.com'
]
1.
In [
117
]: m = regex.search(text)
2.
3.
In [
118
]: m
4.
Out[
118
]: <_sre.SRE_Match at
0x9dc81e0
>
5.
6.
In [
119
]: text[m.start():m.end()]
7.
Out[
119
]:
'dave@google.com'
1.
In [
120
]: print regex.match(text)
2.
None
1.
In [
121
]: print regex.sub(
'REDACTED'
, text)
2.
Dave REDACTED
3.
Steve REDACTED
4.
Rob REDACTED
5.
Ryan REDACTED
1.
In [
122
]: pattern = r
'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})'
2.
3.
In [
123
]: regex = re.compile(pattern, flags=re.IGNORECASE)
1.
In [
124
]: m = regex.match(
'wesm@bright.net'
)
2.
3.
In [
125
]: m.groups()
4.
Out[
125
]: (
'wesm'
,
'bright'
,
'net'
)
1.
In [
126
]: regex.findall(text)
2.
Out[
126
]:
3.
[(
'dave'
,
'google'
,
'com'
),
4.
(
'steve'
,
'gmail'
,
'com'
),
5.
(
'rob'
,
'gmail'
,
'com'
),
6.
(
'ryan'
,
'yahoo'
,
'com'
)]
1.
In [
127
]: print regex.sub(r
'Username: \1, Domain: \2, Suffix: \3'
, text)
2.
Dave Username: dave, Domain: google, Suffix: com
3.
Steve Username: steve, Domain: gmail, Suffix: com
4.
Rob Username: rob, Domain: gmail, Suffix: com
5.
Ryan Username: ryan, Domain: yahoo, Suffix: com
1.
regex = re.compile(r
""
"
2.
(?P<username>[A-Z0-
9
._%+-]+)
3.
@
4.
(?P<domain>[A-Z0-
9
.-]+)
5.
\.
6.
(?P<suffix>[A-Z]{
2
,
4
})
""
", flags=re.IGNORECASE|re.VERBOSE)
1.
In [
128
]: m = regex.match(
'wesm@bright.net'
)
2.
3.
In [
129
]: m.groupdict()
4.
Out[
129
]: {
'domain'
:
'bright'
,
'suffix'
:
'net'
,
'username'
:
'wesm'
}
4、pandas中矢量化的字符串函数
清理待分析的散乱数据时,常常需要做一些字符串规整化工作。更为复杂的情况是,含有字符串的列有时还含有缺失数据:
01.
In [
1
]: data = {
'Dave'
:
'dave@google.com'
,
'Steve'
:
'steve@gmail.com'
,
02.
...:
'Rob'
:
'rob@gmail.com'
,
'Wes'
: np.nan}
03.
04.
In [
2
]: data = pd.Series(data)
05.
06.
In [
3
]: data
07.
Out[
3
]:
08.
Dave dave
@google
.com
09.
Rob rob
@gmail
.com
10.
Steve steve
@gmail
.com
11.
Wes NaN
12.
13.
In [
4
]: data.isnull()
14.
Out[
4
]:
15.
Dave False
16.
Rob False
17.
Steve False
18.
Wes True
1.
In [
5
]: data.str.contains(
'gmail'
)
2.
Out[
5
]:
3.
Dave False
4.
Rob True
5.
Steve True
6.
Wes NaN
01.
In [
6
]: pattern
02.
Out[
6
]:
'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\\.([A-Z]{2,4})'
03.
04.
In [
7
]: data.str.findall(pattern, flags=re.IGNORECASE)
05.
Out[
7
]:
06.
Dave [(
'dave'
,
'google'
,
'com'
)]
07.
Rob [(
'rob'
,
'gmail'
,
'com'
)]
08.
Steve [(
'steve'
,
'gmail'
,
'com'
)]
09.
Wes NaN
01.
In [
8
]: matches = data.str.match(pattern, flags=re.IGNORECASE)
02.
03.
In [
9
]: matches
04.
Out[
9
]:
05.
Dave (
'dave'
,
'google'
,
'com'
)
06.
Rob (
'rob'
,
'gmail'
,
'com'
)
07.
Steve (
'steve'
,
'gmail'
,
'com'
)
08.
Wes NaN
09.
10.
In [
10
]: matches.str.get(
1
)
11.
Out[
10
]:
12.
Dave google
13.
Rob gmail
14.
Steve gmail
15.
Wes NaN
16.
17.
In [
11
]: matches.str[
0
]
18.
Out[
11
]:
19.
Dave dave
20.
Rob rob
21.
Steve steve
22.
Wes NaN
1.
In [
12
]: data.str[:
5
]
2.
Out[
12
]:
3.
Dave dave@
4.
Rob rob
@g
5.
Steve steve
6.
Wes NaN
联系客服