2020-08-05--Pandas-04--文本数据处理

str属性

文本数据也就是我们常说的字符串,Pandas 为 Series 提供了 str 属性,通过它可以方便的对每个元素进行操作。

import pandas as pd
import numpy as np

index = pd.Index(data=["Tom", "Bob", "Mary", "James", "Andy", "Alice"], name="name")

data = {
    "age": [18, 30, np.nan, 40, np.nan, 30],
    "city": ["Bei Jing ", "Shang Hai ", "Guang Zhou", "Shen Zhen", np.nan, " "],
    "sex": [None, "male", "female", "male", np.nan, "unknown"],
    "birth": ["2000-02-10", "1988-10-17", None, "1978-08-08", np.nan, "1988-10-17"]
}

user_info = pd.DataFrame(data=data, index=index)

# 将出生日期转为时间戳
user_info["birth"] = pd.to_datetime(user_info.birth)
print(user_info)
#         age        city      sex      birth
# name
# Tom    18.0   Bei Jing      None 2000-02-10
# Bob    30.0  Shang Hai      male 1988-10-17
# Mary    NaN  Guang Zhou   female        NaT
# James  40.0   Shen Zhen     male 1978-08-08
# Andy    NaN         NaN      NaN        NaT
# Alice  30.0              unknown 1988-10-17

在之前已经了解过,在对 Series 中每个元素处理时,我们可以使用 map 或 apply 方法。

比如,我想要将每个城市都转为小写,可以使用map()/apply()函数来处理。

user_info.city = user_info.city.map(lambda x: x.lower())
print(user_info)       # Series对象
# AttributeError: 'float' object has no attribute 'lower'

报错信息:float类型的数据没有lower属性

但是如果数据中的数据类型过于复杂的话,什么类型都有,不能保证每个数据都有lower(),所以要使用str()

str()

# 将city转为小写,先转为str类型
user_info.city = user_info.city.str.lower()
print(user_info)
#         age        city      sex      birth
# name
# Tom    18.0   bei jing      None 2000-02-10
# Bob    30.0  shang hai      male 1988-10-17
# Mary    NaN  guang zhou   female        NaT
# James  40.0   shen zhen     male 1978-08-08
# Andy    NaN         NaN      NaN        NaT
# Alice  30.0              unknown 1988-10-17
# str属性限定初始值为objext类型Series对象

可以看到,通过 str 属性来访问之后用到的方法名与 Python 内置的字符串的方法名一样。并且能够自动排除缺失值。

我们再来试试其他一些方法。例如,统计每个字符串的长度。

# 统计city列的字符长度
user_info.city = user_info.city.str.len()
print(user_info)
#         age  city      sex      birth
# name                                 
# Tom    18.0   9.0     None 2000-02-10
# Bob    30.0  10.0     male 1988-10-17
# Mary    NaN  10.0   female        NaT
# James  40.0   9.0     male 1978-08-08
# Andy    NaN   NaN      NaN        NaT
# Alice  30.0   1.0  unknown 1988-10-17

这都是针对于Series对象的,返回的都是Series对象。

这里做的是原地操作:改变了原数据,将修改后的Series对象传给user_info的city列(Series对象)中,达到类似于替换的效果。

替换和分割

使用 .str 属性也支持替换与分割操作。

先来看下替换操作,例如:将空字符串替换成下划线。

# 替换字符
user_info.city = user_info.city.str.replace(' ','_')
print(user_info)
#         age        city      sex      birth
# name                                       
# Tom    18.0   bei_jing_     None 2000-02-10
# Bob    30.0  shang_hai_     male 1988-10-17
# Mary    NaN  guang_zhou   female        NaT
# James  40.0   shen_zhen     male 1978-08-08
# Andy    NaN         NaN      NaN        NaT
# Alice  30.0           _  unknown 1988-10-17

replace 方法还支持正则表达式,例如将所有开头为 s 的城市替换为空字符串。

# 正则匹配替换字符
user_info.city = user_info.city.str.replace("^s.*", " ")
print(user_info)
#         age        city      sex      birth
# name                                       
# Tom    18.0   bei_jing_     None 2000-02-10
# Bob    30.0                 male 1988-10-17
# Mary    NaN  guang_zhou   female        NaT
# James  40.0                 male 1978-08-08
# Andy    NaN         NaN      NaN        NaT
# Alice  30.0           _  unknown 1988-10-17

分割

例如根据空字符串来分割某一列。

# 分割
user_info.city = user_info.city.str.split(' ')
print(user_info)
#         age            city      sex      birth
# name
# Tom    18.0   [Bei, Jing, ]     None 2000-02-10
# Bob    30.0  [Shang, Hai, ]     male 1988-10-17
# Mary    NaN   [Guang, Zhou]   female        NaT
# James  40.0    [Shen, Zhen]     male 1978-08-08
# Andy    NaN             NaN      NaN        NaT
# Alice  30.0            [, ]  unknown 1988-10-17

分割列表中的元素可以使用 .str.get(index).str[index]符号进行访问:

# 分割并取值
user_info.city = user_info.city.str.split(' ').str[1]
print(user_info)
# .str返回:

# 数据修改为:
#         age  city      sex      birth
# name
# Tom    18.0  Jing     None 2000-02-10
# Bob    30.0   Hai     male 1988-10-17
# Mary    NaN  Zhou   female        NaT
# James  40.0  Zhen     male 1978-08-08
# Andy    NaN   NaN      NaN        NaT
# Alice  30.0        unknown 1988-10-17

设置参数 expand=True 可以轻松扩展此项以返回 DataFrame。

df = user_info.city.str.split(' ',expand=True)
print(df)
#            0     1     2
# name                    
# Tom      Bei  Jing      
# Bob    Shang   Hai      
# Mary   Guang  Zhou  None
# James   Shen  Zhen  None
# Andy     NaN   NaN   NaN
# Alice               None

提取子串

既然是在操作字符串,很自然,你可能会想到是否可以从一个长的字符串中提取出子串。答案是可以的。

1.提取第一个匹配的子串

extract('正则',expand=True)

extract 方法接受一个正则表达式并至少包含一个捕获组,指定参数 expand=True 可以保证每次都返回 DataFrame。

例如,现在想要匹配空字符串前面的所有的字母,可以使用如下操作:

print(user_info)
#         age        city      sex      birth
# name
# Tom    18.0   Bei Jing      None 2000-02-10
# Bob    30.0  Shang Hai      male 1988-10-17
# Mary    NaN  Guang Zhou   female        NaT
# James  40.0   Shen Zhen     male 1978-08-08
# Andy    NaN         NaN      NaN        NaT
# Alice  30.0              unknown 1988-10-17

# 匹配空字符串之前的内容
c = user_info.city.str.extract('(\w+)\s+',expand=True)
print(c)               # DataFrame类型
#            0
# name
# Tom      Bei
# Bob    Shang
# Mary   Guang
# James   Shen
# Andy     NaN
# Alice    NaN

如果使用多个组提取正则表达式会返回一个 DataFrame,每个组只有一列。

例如,想要匹配出空字符串前面和后面的所有字母,操作如下:

# 匹配空格前后的所有字符串,返回DataFrame
c = user_info.city.str.extract('(\w+)\s+(\w+)',expand=True)
print(c)
#            0     1
# name
# Tom      Bei  Jing
# Bob    Shang   Hai
# Mary   Guang  Zhou
# James   Shen  Zhen
# Andy     NaN   NaN
# Alice    NaN   NaN

匹配所有子串

extract 只能够匹配出第一个子串,使用 extractall 可以匹配出所有的子串。

例如,将所有组的空白字符串前面的字母都匹配出来,可以如下操作。

# 匹配所有空格之前的字符串
c = user_info.city.str.extractall("(\w+)\s+")
print(c)
#                  0
# name  match
# Tom   0        Bei
#       1       Jing
# Bob   0      Shang
#       1        Hai
# Mary  0      Guang
# James 0       Shen

测试是否包含子串

除了可以匹配出子串外,我们还可以使用 contains 来测试是否包含子串。例如,想要测试城市是否包含子串 “Hai”。

# 匹配包含city项包含Hai的数据,返回Series,数据为bool值
c = user_info.city.str.contains('Hai')
print(c)
# name
# Tom      False
# Bob       True
# Mary     False
# James    False
# Andy       NaN
# Alice    False
# Name: city, dtype: object

# 将上边返回的bool值的Series作为花式索引
user_info = user_info[c]
print(user_info)             # 返回DataFrame对象
#        age        city   sex      birth
# name
# Bob   30.0  Shang Hai   male 1988-10-17

返回的bool值的Series对象可以作为花式索引,在DataFrame中获取相应的数据项。、

当然了,正则表达式也是支持的。例如,想要测试是否是以字母 “S” 开头。

c = user_info.city.str.contains("^S")

生成哑变量

这是一个神奇的功能,通过 get_dummies 方法可以将字符串转为哑变量,sep 参数是指定哑变量之间的分隔符。来看看效果吧。、

# 哑变量
c = user_info.city.replace(' ','').str.get_dummies()
print(c)
#        Bei Jing   Guang Zhou  Shang Hai   Shen Zhen  zhengzhou
# name                                                          
# Tom            1           0           0          0          0
# Bob            0           0           1          0          0
# Mary           0           1           0          0          0
# James          0           0           0          1          0
# Andy           0           0           0          0          1
# Alice          0           0           0          0          0

这样,它提取出了 Bei, Guang, Hai, Jing, Shang, Shen, Zhen, Zhou 这些哑变量,并对每个变量下使用 0 或 1 来表达。实际上与 One-Hot(狂热编码)是一回事。听不懂没关系,之后将机器学习相关知识时会详细介绍这里。

方法摘要

方法 描述
cat() 连接字符串
split() 在分隔符上分割字符串
rsplit() 从字符串末尾开始分隔字符串
get() 索引到每个元素(检索第i个元素)
join() 使用分隔符在系列的每个元素中加入字符串
get_dummies() 在分隔符上分割字符串,返回虚拟变量的DataFrame
contains() 如果每个字符串都包含pattern / regex,则返回布尔数组
replace() 用其他字符串替换pattern / regex的出现
repeat() 重复值(s.str.repeat(3)等同于x * 3 t2 >)
pad() 将空格添加到字符串的左侧,右侧或两侧
center() 相当于str.center
ljust() 相当于str.ljust
rjust() 相当于str.rjust
zfill() 等同于str.zfill
wrap() 将长长的字符串拆分为长度小于给定宽度的行
slice() 切分Series中的每个字符串
slice_replace() 用传递的值替换每个字符串中的切片
count() 计数模式的发生
startswith() 相当于每个元素的str.startswith(pat)
endswith() 相当于每个元素的str.endswith(pat)
findall() 计算每个字符串的所有模式/正则表达式的列表
match() 在每个元素上调用re.match,返回匹配的组作为列表
extract() 在每个元素上调用re.search,为每个元素返回一行DataFrame,为每个正则表达式捕获组返回一列
extractall() 在每个元素上调用re.findall,为每个匹配返回一行DataFrame,为每个正则表达式捕获组返回一列
len() 计算字符串长度
strip() 相当于str.strip
rstrip() 相当于str.rstrip
lstrip() 相当于str.lstrip
partition() 等同于str.partition
rpartition() 等同于str.rpartition
lower() 相当于str.lower
upper() 相当于str.upper
find() 相当于str.find
rfind() 相当于str.rfind
index() 相当于str.index
rindex() 相当于str.rindex
capitalize() 相当于str.capitalize
swapcase() 相当于str.swapcase
normalize() 返回Unicode标准格式。相当于unicodedata.normalize
translate() 等同于str.translate
isalnum() 等同于str.isalnum
isalpha() 等同于str.isalpha
isdigit() 相当于str.isdigit
isspace() 等同于str.isspace
islower() 相当于str.islower
isupper() 相当于str.isupper
istitle() 相当于str.istitle
isnumeric() 相当于str.isnumeric
isdecimal() 相当于str.isdecimal

你可能感兴趣的:(2020-08-05--Pandas-04--文本数据处理)