pd字符串处理

先说明一下,这些知识,也是我在学习有些书籍,然后写的知识点,也是用自己的理解写出来,例子有些是自己添加,有些是和书籍上一样的,是看我是否写错。我写这些博客也是自己学习的痕迹和以后方便自己复习,再回顾。所以本人也是一个学生。

1.python很多内建方法很适合处理string。2.而对于更复杂得模式,可以配合正则表达式。而pandas则混合了两种方式

1.字符串对象方法

大部分字符串可以使用python的内建的一些方法,比如我们使用split()分割函数就可以分割以逗号区分的字符串

import numpy as np
import pandas as pd

val='li,xun, like,study'
pieces=val.split(',')   #使用切分函数可以将字符串以逗号切分开然后存入一个列表
print(pieces)     #如果想将存入列表的一个个字符串取出,可以使用循环语句

#输出:
['li', 'xun', ' like', 'study']

在这上面的输出中我们可以看出有一个空号(like字符左边),内建函数strip()可以除去空格与换行符。strip()和split()经常搭配使用

for x in val.split(','):   #使用for循环输出每一个字符串
    print(x)

#输出:
li
xun
 like
study

#如果想要除去字符串中有的空格
for x in val.split(','):
    print(x.strip())       #输出去掉空格后的每个X

#输出:
li
xun
like
study


pieces1=[x.strip() for x in val.split(',')] #将切分后在加上去掉空格后的字符串存入列表
print(pieces1)

#输出:
['li', 'xun', 'like', 'study']

#可以使用+将 '::',','等字符连接起来
first,second,third,fourth=pieces1  #取出列表中的4个字符串
str=first+'::'+second+','+third+','+fourth
print(str)

#输出:
li::xun,like,study

#但上面的这种方法并不快速,我们可以使用join()
str2='::'.join(pieces1) #在每个字符串后面加上需要添加的标点符号
print(str2)

#输出:
li::xun::like::study
find 和 index 功能相同 但是find不能用于list(谨记),index找寻的字符串如果不存在会返回错误信息,而find会返回-1
print('xun'in pieces1) #判断字符串‘xun'是否在pieces1中
print(val.index('xun')) #返回某个字符串在字符串val的位置
print(val.index('li'))
print(val.find('li')) 

#输出:
True
3
0
0
print(val.count(','))  #统计某个substring出现的次数

#输出:
3

print(val.replace(',','::')) #将val中的',' 替换成 '::'

#输出:
li::xun:: like::study

python内建的string方法:

 

2.正则表达式

正则表达式能让我们寻找更复杂的模式(pattern).通常称一个表达式为regex,由正则表达语言来代表一个字符串模式。使用python内建的re模块来使用

re模块有以下三个类别:pattern matching(模式匹配),substitution(替换),splitting(分割)

一种表达式描述一种模式.

例子,假设我们想要根据空格,换行符等来分割一个字符串。用于描述一个或多个空格的regex是‘\s+’

import re

text = "foo    bar\t baz  \tqux"
print(re.split('\s+',text))

#输出:
['foo', 'bar', 'baz', 'qux']

当调用re.split('\s+',text)的时候,正则表达式第一次被组合编译,split()会被调用搜素text.我们可以使用re.compile去自己编译regex,可以生成一个多次使用的regex object

regex=re.compile('\s+')
print(regex.split(text))

#输出:
['foo', 'bar', 'baz', 'qux']

#如果想要得到一个符合regex的所有结果(符合有着空格,\t(换行符)的),我们可以使用findall(),它会返回一个列表,findall返回所有匹配的结果
print(regex.findall(text))

#输出:
['    ', '\t ', '  \t']

使用re.compile创建一个regex object是被强烈推荐的,如果你打算把一个表达式用于很多string上的话,这样可以节省CPU的资源。

findall()返回匹配的所有结果,search()只返回第一次匹配的结果,match只匹配string开始的位置

例子:找到所有符合格式的邮件的地址

text = """Dave dave@google.com 
          Steve steve@gmail.com 
          Rob rob@gmail.com 
          Ryan ryan@yahoo.com """
pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}' #写出邮件的正确书写格式,然后这是需要这样匹配的表达式,可以去看相关正则表达式的书籍学习为什么这样写
regex = re.compile(pattern, flags=re.IGNORECASE)    #生成一个新的regex,用于对于以后文本的匹配
print(regex.findall(text))

#输出:
['dave@google.com', 'steve@gmail.com', 'rob@gmail.com', 'ryan@yahoo.com']


#search返回符合条件的第一个匹配结果
m=regex.search(text)

#输出:
<_sre.SRE_Match object; span=(5, 20), match='dave@google.com'>

Match object会返回找到符合条件的第一个匹配结果的开始与结束位置,这里我们可以看到符合邮件格式条件的开始位置为text的第5个字符,结束为第20个位置

print(text[m.start():m.end()]) #输出text中符合条件的第一个匹配结果

#输出:
dave@google.com

print(regex.match(text))
#输出:
NOne       #为什么会输出None呢,因为刚才已经介绍了match只会去匹配string开头的位置,如果开头的位置符合条件就会返回结果,但是text开头的位置为Dave,所以返回为空

sub()它不像findall这些,它会返回一个新的string,它会将符合条件的模块(pattern)替换成指定的字符串

print(regex.sub('lixun',text))
#输出:
Dave lixun 
          Steve lixun 
          Rob lixun 
          Ryan lixun 

假设我们既想要找到邮件地址,又想将邮件地址分为3个部分用户名(username),域名(domain name),后缀名(domain suffix),那么我们就需要给每个匹配pattern(模块)加上一个括号

text = """Dave dave@google.com 
          Steve steve@gmail.com 
          Rob rob@gmail.com 
          Ryan ryan@yahoo.com """
pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})'
regex=re.compile(pattern,flags=re.IGNORECASE)
#1
m=regex.match('dave@google.com ')  #因为match匹配最开始的位置,所以只有添加一个字符串进去才不会返回为空
print(m)       #从输出中就可以看出函数的不同  m返回一个Match object
print(m.group()) #返回match 中的字符串
print(m.groups())  #groups 会返回一个tuple,包含多个pattern组份
 
#输出:
<_sre.SRE_Match object; span=(0, 15), match='dave@google.com'>
dave@google.com
('dave', 'google', 'com')

#2
print(regex.findall(text)) #返回一个a list of tuples
#输出:
[('dave', 'google', 'com'), ('steve', 'gmail', 'com'), ('rob', 'gmail', 'com'), ('ryan', 'yahoo', 'com')]

#3
sub也能访问groups的结果,但是要使用特殊符号\1,\2... \1表示匹配的第一个group,\2表示匹配的第二个group 以此类推

print(regex.sub(r'username:\1,domain:\2,suffix:\3',text))
#输出:
Dave username:dave,domain:google,suffix:com 
          Steve username:steve,domain:gmail,suffix:com 
          Rob username:rob,domain:gmail,suffix:com 
          Ryan username:ryan,domain:yahoo,suffix:com 

正则表达式的方法:

 

3.pandas中的字符串向量函数

我们都知道,在一些复杂的数据清理中,string都有缺失值

data = {'Dave': 'dave@google.com', 'Steve': 'steve@gmail.com',
        'Rob': 'rob@gmail.com', 'Wes': np.nan}
data=pd.Series(data)
print(data)
print(data.isnull())

#输出:
Dave     dave@google.com
Rob        rob@gmail.com
Steve    steve@gmail.com
Wes                  NaN
dtype: object
Dave     False
Rob      False
Steve    False
Wes       True
dtype: bool

可以把一些字符串方法和正则表达式(用lambda或其他函数)用于每一个value上,通过data.map,但是这样会得到NA(null)值。为了解决这个问题,series有一些数组导向的方法可以用于字符串操作,来跳过NA值。这些方法可以通过series的str属性;比如,我们想检查每个电子邮箱地址是否有'gmail' with str.contains

print(data.str)
print(data.str.contains('gmail'))

#输出:
<pandas.core.strings.StringMethods object at 0x02E25390>
Dave     False
Rob       True
Steve     True
Wes        NaN    #跳过了Nan值

正则表达式也可以用,配合任意的re选项,比如IGNORECASE

字符串向量化:

pattern =r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})'
print(data.str.findall(pattern, flags=re.IGNORECASE))   #字符串向量化

#输出:
Dave     [(dave, google, com)]
Rob        [(rob, gmail, com)]
Steve    [(steve, gmail, com)]
Wes                        NaN
dtype: object

print(data.str[:6])  #切片,从第0个字符到第5个字符
#输出:
Dave     dave@g
Rob      rob@gm
Steve    steve@
Wes         NaN

 

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页