首页Python【Python数据分析】3...

【Python数据分析】35.数据清洗与准备——字符串操作1


本系列文章配套代码获取有以下三种途径:

  • 可以在以下网站查看,该网站是使用JupyterLite搭建的web端Jupyter环境,因此无需在本地安装运行环境即可使用,首次运行浏览器需要下载一些配置文件(大约20M):

https://returu.github.io/Python_Data_Analysis/lab/index.html
链接:https://pan.baidu.com/s/1MYkeYeVAIRqbxezQECHwcA?pwd=mnsj 提取码:mnsj
  • 前往GitHub详情页面,单击 code 按钮,选择Download ZIP选项:
https://github.com/returu/Python_Data_Analysis

根据《Python for Data Analysis 3rd Edition》翻译整理

—————————————————–

Pandas允许你将字符串和正则表达式简洁地应用到整个数组上,此外还能处理数据缺失带来的困扰。

1.Python内建字符串方法:

在许多字符串处理和脚本应用中,Python内建的字符串方法就足够了。例如,可以使用 split将由逗号分隔的字符串拆分成几部分。

1>>> val = "a,b,  cdef"
2
3>>> val.split(",")
4['a''b''  cdef']

 split通常与 strip 结合使用以清除空格(包括换行符)。

1>>> pieces = [x.strip() for x in val.split(",")]
2>>> pieces
3['a''b''cdef']

这些子字符串可以使用加法与双冒号分隔符连接在一起。

1>>> first, second, third = pieces
2>>> first + "::" + second + "::" + third
3'a::b::cdef'

但这不是实用的通用方法。一种更快、更 Pythonic 的方法是,将列表或元组传递给字符串“::” join 方法

1>>"::".join(pieces)
2'a::b::cdef'

其他方法与定位子字符串有关。使用 Python 的 in 关键字是检测子字符串的最佳方法,尽管index 和 find 也能实现同样功能。

请注意,find和  index 之间的区别在于,如果未找到字符串,则 index  会引发异常,而find会返回 –1。

 1>>"a" in val
2True
3
4>>> val.index(",")
51
6
7>>> val.find(":")
8-1
9
10>>> val.index(":")
11ValueError: substring not found

相关地, count 返回某个特定子字符串在字符串中出现的次数。

1>>> val.count(",")
22

replace 会将一种模式替换为另一种模式。它也常用于通过传递一个空字符串来删除某个模式。

1>>> val.replace(",""::")
2'a::b::  cdef'
3>>> val.replace(",""")
4'ab  cdef'

Python 内建的字符串方法如下所示:

方法
说明
count 返回子串在字符串中非重叠出现的次数
endswith

如果字符串以后缀结尾则返回 True

startswith 如果字符串以前缀开头,则返回 True
join 使用字符串作为分隔符来连接一系列其他字符串
index 如果在字符串中找到,则返回第一次出现的传递子字符串的起始索引;如果未找到则引发 ValueError
find 返回子字符串在字符串中第一次出现的第一个字符的位置;类似于index,但如果未找到则返回 –1
rfind 返回子字符串在字符串中最后一次传时第一个字符的位置;如果未找到,则返回 –1
replace 用一个字符串替换另一个字符串
strip, rstrip, lstrip 修剪空白,分别包括两侧、右侧或左侧的换行符
split 使用传递的分隔符将字符串分解为子字符串列表
lower 将字母字符转换为小写
upper 将字母字符转换为大写
casefold 将字符转换为小写,并将任何特定于区域的变量字符串组合转换为常见的可比较形式
ljust, rjust 左对齐或右对齐;用空格(或其他一些填充字符)填充字符串的另一侧以返回具有最小宽度的字符串

2.正则表达式:

正则表达式提供了一种灵活的方式来搜索或匹配文本中的(通常更复杂的)字符串的模式。单个表达式,通常称为regex,是根据正则表达式语言形成的字符串。Python 内置的 re 模块负责将正则表达式应用于字符串。

 re 模块分为三个主题:模式匹配、替换和拆分。当然,这些都是相关的。

一个正则表达式描述了在文本中定位的一种模式,然后可以将其用于多种目标。

让我们看一个简单的例子:假设我们想用可变数量的空白字符(制表符、空格和换行符)拆分一个字符串,描述一个或多个空白字符的正则表达式是 s+(为了在正则表达式中避免转义符  的影响,可以使用原生字符串语法,比如r"C:x" ,而不是 "C:\x"

1>>> import re
2
3>>> text = "foo    bart baz  tqux"
4>>> re.split(r"s+",text)
5['foo''bar''baz''qux']

当你调用  re.split(r"s+", text) 时,正则表达式首先会被编译,然后正则表达式的split 方法在传入的文本上被调用。你可以使用  re.compile 自己编译正则表达式,形成一个可重用的正则表达式对象(如果你打算将相同的表达式应用于多个字符串,强烈建议使用  re.compile 创建一个正则表达式对象,这样做将节省 CPU 周期)。

1>>> regex = re.compile(r"s+")
2
3>>> regex.split(text)
4['foo''bar''baz''qux']

相反,如果想获得与正则表达式匹配的所有模式的列表,则可以使用 findall方法。

1>>> regex.findall(text)
2['    ''t ''  t']

match searchfindall密切相关。findall返回字符串中的所有匹配项,而 search仅返回第一个匹配项。match 更严格地,只在字符串的起始位置进行匹配。

例如,下面的一段文本和一个能够识别大多数电子邮件地址的正则表达式

1>>> text = """Dave dave@google.com
2Steve steve@gmail.com
3Rob rob@gmail.com
4Ryan ryan@yahoo.com"""

5
6>>> pattern = r"[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}"
7
8# re.IGNORECASE使正则表达式不区分大小写
9>>> regex = re.compile(pattern , flags=re.IGNORECASE)

在文本上使用 findall 方法会生成一个电子邮件地址列表。

1>>> regex.findall(text)
2['dave@google.com''steve@gmail.com''rob@gmail.com''ryan@yahoo.com']

search 返回文本中第一个匹配到的电子邮件地址。对于前面提到的正则表达式,匹配对象只能告诉我们模式在字符串中的开始和结束位置。

1>>> m = regex.search(text)
2>>> m
3<re.Match object; span=(520), match='dave@google.com'>
4>>> text[m.start():m.end()]
5'dave@google.com'

regex.match 返回 None,因为只有当模式出现在字符串的开头时它才会匹配。

1>>> print(regex.match(text))
2None

相关地,sub 将返回一个新字符串,原字符串中的模式会被新字符串替换。

1>>> print(regex.sub("REDACTED", text))
2Dave REDACTED
3Steve REDACTED
4Rob REDACTED
5Ryan REDACTED

假设你要查找电子邮件地址并同时将每个地址分成三个部分:用户名、域名和域名后缀。需要在要分割的模式部分周围加上括号。此时使用findall 将返回一个元组列表。

1>>> pattern = r"([A-Z0-9._%+-]+)@([A-Z0-9.-]+).([A-Z]{2,4})"
2>>> regex = re.compile(pattern, flags=re.IGNORECASE)
3>>> regex.findall(text)
4[('dave''google''com'),
5 ('steve''gmail''com'),
6 ('rob''gmail''com'),
7 ('ryan''yahoo''com')]

上面这个修改后的正则表达式生成的匹配对象的 groups 方法返回模式组件的元组。

1>>> m = regex.match("wesm@bright.net")
2>>> m.groups()
3('wesm''bright''net')

sub 也可以使用特殊符号,如1 和2,访问每个匹配对象中的分组。符号1代表的是第一个匹配分组,符号2代表的是第二个匹配分组,以此类推。

1>>> print(regex.sub(r"Username: 1, Domain: 2, Suffix: 3", text))
2Dave Username: dave, Domain: google, Suffix: com
3Steve Username: steve, Domain: gmail, Suffix: com
4Rob Username: rob, Domain: gmail, Suffix: com
5Ryan Username: ryan, Domain: yahoo, Suffix: com

正则表达式方法如下所示:

方法
说明
findall 将字符串中所有不重叠的匹配模式以列表形式返回
finditer findall类似,但是返回的是迭代器
match 在字符串的起始位置匹配模式,并可选择将模式组件匹配到分组中;如果模式匹配,则返回匹配对象,否则返回 None
search 扫描字符串的匹配模式,如果扫描到则返回匹配对象;与match不同,匹配可以在字符串中的任何位置,而不是仅在起始位置
split 根据模式,将字符串拆分为多个部分
sub, subn 用替换表达式替换字符串中所有的匹配 (sub) 或第 n 次出现的匹配串 (subn);使用符号1, 2, …来引用替换字符串中的匹配组元素


本篇文章来源于微信公众号: 码农设计师

RELATED ARTICLES

欢迎留下您的宝贵建议

Please enter your comment!
Please enter your name here

- Advertisment -

Most Popular

Recent Comments