Pandas文本数据处理 | 轻松玩转Pandas(4)

无邪 AI派 | 禹都一只猫整理 1,938 views 0
# 导入相关库
import numpy as np
import pandas as pd

为什么要用str属性

  • 文本数据也就是我们常说的字符串,Pandas 为 Series 提供了 str 属性,通过它可以方便的对每个元素进行操作。
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)
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 方法。

user_info.city.map(lambda x: x.lower())
-------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-43-e661c5ad5c48> in <module>()
----> 1 user_info.city.map(lambda x: x.lower())

~/.virtualenvs/py3/lib/python3.6/site-packages/pandas/core/series.py in map(self, arg, na_action)
   2996         """
   2997         new_values = super(Series, self)._map_values(
-> 2998             arg, na_action=na_action)
   2999         return self._constructor(new_values,
   3000                                  index=self.index).__finalize__(self)

~/.virtualenvs/py3/lib/python3.6/site-packages/pandas/core/base.py in _map_values(self, mapper, na_action)
   1002
   1003         # mapper is a function
-> 1004         new_values = map_f(values, mapper)
   1005
   1006         return new_values

pandas/_libs/src/inference.pyx in pandas._libs.lib.map_infer()

<ipython-input-43-e661c5ad5c48> in <lambda>(x)
----> 1 user_info.city.map(lambda x: x.lower())
  • What?竟然出错了,错误原因是因为 float 类型的对象没有 lower 属性。这是因为缺失值(np.nan)属于float 类型。

这时候我们的 str 属性操作来了,来看看如何使用吧。

# 将文本转为小写
user_info.city.str.lower()
----------------------------
name
Tom       bei jing 
Bob      shang hai 
Mary     guang zhou
James     shen zhen
Andy            NaN
Alice              
Name: city, dtype: object

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

  • 我们再来试试其他一些方法。例如,统计每个字符串的长度。
user_info.city.str.len()
name
Tom       9.0
Bob      10.0
Mary     10.0
James     9.0
Andy      NaN
Alice     1.0
Name: city, dtype: float64

替换和分割

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

  • 先来看下替换操作,例如:将空字符串替换成下划线。
user_info.city.str.replace(" ", "_")
------------------------------
name
Tom       Bei_Jing_
Bob      Shang_Hai_
Mary     Guang_Zhou
James     Shen_Zhen
Andy            NaN
Alice             _
Name: city, dtype: object
  • replace方法还支持正则表达式,例如将所有开头为 S 的城市替换为空字符串。
user_info.city.str.replace("^S.*", " ")
------------------------------
name
Tom       Bei Jing 
Bob                
Mary     Guang Zhou
James              
Andy            NaN
Alice              
Name: city, dtype: object
  • 再来看下分割操作,例如根据空字符串来分割某一列。
user_info.city.str.split(" ")
-----------------------------
name
Tom       [Bei, Jing, ]
Bob      [Shang, Hai, ]
Mary      [Guang, Zhou]
James      [Shen, Zhen]
Andy                NaN
Alice              [, ]
Name: city, dtype: object
  • 分割列表中的元素可以使用 get 或 [] 符号进行访问:
user_info.city.str.split(" ").str.get(1)
----------------------------
name
Tom      Jing
Bob       Hai
Mary     Zhou
James    Zhen
Andy      NaN
Alice        
Name: city, dtype: object
----------------------------
user_info.city.str.split(" ").str[1]
----------------------------
name
Tom      Jing
Bob       Hai
Mary     Zhou
James    Zhen
Andy      NaN
Alice        
Name: city, dtype: object
  • 设置参数 expand=True  可以轻松扩展此项以返回 DataFrame
user_info.city.str.split(" ", expand=True)
-------------------------------
                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 方法接受一个正则表达式并至少包含一个捕获组
  2. 指定参数 expand=True 可以保证每次都返回 DataFrame。
  • 例如,现在想要匹配空字符串前面的所有的字母,可以使用如下操作:
user_info.city.str.extract("(\w+)\s+", expand=True)
---------------------------
               0
name
Tom      Bei
Bob       Shang
Mary     Guang
James    Shen
Andy     NaN
Alice      NaN

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

  • 例如,想要匹配出空字符串前面和后面的所有字母,操作如下:
user_info.city.str.extract("(\w+)\s+(\w+)", expand=True)
----------------------------------
                 0        1
name
Tom      Bei       Jing
Bob     Shang     Hai
Mary   Guang   Zhou
James   Shen    Zhen
Andy     NaN    NaN
Alice     NaN      NaN

匹配所有子串

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

  • 例如,将所有组的空白字符串前面的字母都匹配出来,可以如下操作
user_info.city.str.extractall("(\w+)\s+")
------------------------------
                              0
name  match
Tom     0              Bei
            1              Jing
Bob      0              Shang
            1               Hai
Mary    0              Guang
James   0             Shen

测试是否包含子串

除了可以匹配出子串外,我们还可以使用 contains 来测试是否包含子串。

  • 例如,想要测试城市是否包含子串 “Zh”。
user_info.city.str.contains("Zh")
------------------------
name
Tom      False
Bob      False
Mary      True
James     True
Andy       NaN
Alice    False
Name: city, dtype: object
  • 当然了,正则表达式也是支持的。例如,想要测试是否是以字母 “S” 开头。
user_info.city.str.contains("^S")
-------------------------------
name
Tom      False
Bob       True
Mary     False
James     True
Andy       NaN
Alice    False
Name: city, dtype: object

上述的东西,其实就是对字符串的一些操作而已,很简单

生成哑变量

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

             Bei  Guang  Hai  Jing  Shang  Shen  Zhen  Zhou
name
Tom         1      0       0     1          0           0     0     0
Bob          0      0       1     0          1           0     0     0
Mary        0      1       0     0          0           0     0     1
James      0      0        0     0          0          1     1     0
Andy        0      0       0      0          0          0     0     0
Alice         0      0       0      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

发表评论 取消回复
表情 图片 链接 代码

分享