文章目录
一、处理字符串
- 当我们遇到一个超级大的 DataFrame,里面有一列类型为字符串,要将每一行的字符串都用同一方式进行处理, 一般会想到遍历整合 DataFrame。
- 但是如果直接这样做的话将会耗费很长时间,有时几个小时都处理不完。 因此我们将学习 pandas 快速处理字符串方法。
1. 向量化字符串操作简介
- 量化操作简化了纯数值的数组操作语法,我们不需要再担心数组的长度或维度,只需要把中心放在操作上面。
- 而对字符串的向量化需要工具包的支持,如 Numpy 就没办法直接对字符串进行向量化操作,只能通过繁琐的循环来实现。 Pandas 则可以很好的处理这类问题。
2. str 方法的简介
Python 会处理字符串起来会很容易,作为工具包的 Pandas 同样可以简单快速的处理字符串,几乎把 Python 内置的字符串方法都给复制过来了,这种方法就是 Pandas 内置的 str 方法。
通俗来说就可以将 series 和 index 对象中包含字符串的部分简单看作单个字符串处理,达到批量简单快速处理的目的,str 方法有如下函数可供我们使用。
函数 | 含义 |
lower() | 将的字符串转换为小写 |
upper() | 将的字符串转换为大写 |
len() | 得出字符串的长度 |
strip() | 去除字符串两边的空格(包含换行符) |
split() | 用指定的分割符分割字符串 |
cat(sep=“”) | 用给定的分隔符连接字符串元素 |
contains(pattern) | 如果子字符串包含在元素中,则为每个元素返回一个布尔值 True,否则为 False |
replace(a,b) | 将值 a 替换为值 b |
count(pattern) | 返回每个字符串元素出现的次数 |
startswith(pattern) | 如果 Series 中的元素以指定的字符串开头,则返回 True |
endswith(pattern) | 如果 Series 中的元素以指定的字符串结尾,则返回 True |
findall(pattern) | 以列表的形式返出现的字符串 |
find(pattern) | 返回字符串第一次出现的索引位置 |
- 这里需要注意的是,上述所有字符串函数全部适用于 DataFrame 对象,同时也可以与 Python 内置的字符串函数一起使用,这些函数在处理 Series/DataFrame 对象的时候会自动忽略缺失值数据(NaN)。
- 首先,我们导入需要的 numpy 和 pandas 库。
import pandas as pd import numpy as np
- 1) lower() 函数可以将的字符串转换为小写。
s = pd.Series(['C', 'Python', 'java', 'go', np.nan, '1125','javascript']) s.str.lower() 0 c 1 python 2 java 3 go 4 NaN 5 1125 6 javascript dtype: object
- (2) upper() 将的字符串转换为大写。
s = pd.Series(['C', 'Python', 'java', 'go', np.nan, '1125','javascript']) s.str.upper() #0 C #1 PYTHON #2 JAVA #3 GO #4 NaN #5 1125 #6 JAVASCRIPT #dtype: object
- (3) len() 得出字符串的长度。
s = pd.Series(['C', 'Python', 'java', 'go', np.nan, '1125','javascript']) s.str.len() #0 1.0 #1 6.0 #2 4.0 #3 2.0 #4 NaN #5 4.0 #6 10.0 #dtype: float64
- 4) strip() 去除字符串两边的空格(包含换行符)。
s = pd.Series(['C ', ' Python\t \n', ' java ', 'go\t', np.nan, '\t1125 ','\tjavascript']) s_strip = s.str.strip(" ") s_strip #0 C #1 Python\t \n #2 java #3 go\t #4 NaN #5 \t1125 #6 \tjavascript #dtype: object
- (5) split() 用指定的分割符分割字符串。
s = pd.Series(['Zhang hua',' Py thon\n',' java ','go','11 25 ','javascript']) print(s.str.split(" ")) #0 [Zhang, hua] #1 [, Py, thon\n] #2 [, , , java, , , ] #3 [go] #4 [11, 25, ] #5 [javascript] #dtype: object
- 如果不带参数,会先执行 strip(),再默认以空格分割。
print(s.str.split()) #0 [Zhang, hua] #1 [Py, thon] #2 [java] #3 [go] #4 [11, 25] #5 [javascript] #dtype: object
- 我们也可以对 strip() 的参数进行设置。
print(s.str.strip().str.split(" ")) #0 [Zhang, hua] #1 [Py, thon] #2 [java] #3 [go] #4 [11, 25] #5 [javascript] #dtype: object
- (6) cat(sep=“”) 用给定的分隔符连接字符串元素。
- cat(sep=“”) 函数会自动忽略 NaN。
s = pd.Series(['C', 'Python', 'java', 'go', np.nan, '1125','javascript']) s_cat = s.str.cat(sep="_") s_cat #'C_Python_java_go_1125_javascript'
- (7) contains(pattern) 如果子字符串包含在元素中,则为每个元素返回一个布尔值 True,否则为 False。
- 我们可以取出 s 中包含空格的元素。
s = pd.Series(['C ',' Python','java','go','1125 ','javascript']) s.str.contains(" ") #0 True #1 True #2 False #3 False #4 True #5 False #dtype: bool
- 也可以将 True 返回原数据。
s[s.str.contains(" ")] #0 C #1 Python #4 1125 #dtype: object
- (8) replace(a,b) 将值 a 替换为值 b。
s =s = pd.Series(['C ',' Python','java','go','1125 ','javascript']) s.str.replace("java","python") #0 C #1 Python #2 python #3 go #4 1125 #5 pythonscript #dtype: object
- (9) count(pattern) 返回每个字符串元素出现的次数。
s = pd.Series(['C ','Python Python','Python','go','1125 ','javascript']) s.str.count("Python") #0 0 #1 2 #2 1 #3 0 #4 0 #5 0 #dtype: int64
(10) startswith(pattern) 如果 Series 中的元素以指定的字符串开头,则返回 True。
(11) endswith(pattern) 如果 Series 中的元素以指定的字符串结尾,则返回 True。
s = pd.Series(['C ',' Python','java','go','1125 ','javascript']) print(s.str.startswith("j")) #0 False #1 False #2 True #3 False #4 False #5 True #dtype: bool
- 12) repeat(value) 以指定的次数重复每个元素。
s = pd.Series(['C ',' Python','java','go','1125 ','javascript']) print(s.str.repeat(3)) #0 C C C #1 Python Python Python #2 javajavajava #3 gogogo #4 1125 1125 1125 #5 javascriptjavascriptjavascript #dtype: object
- (13) find(pattern) 返回字符串第一次出现的索引位置。
- 这里如果返回 -1 表示该字符串中没有出现指定的字符。
s = pd.Series(['C ',' Python','java','go','1125 ','javascript']) print(s.str.find("a")) #0 -1 #1 -1 #2 1 #3 -1 #4 -1 #5 1 #dtype: int64
- (14) findall(pattern) 以列表的形式返出现的字符串。
s = pd.Series(['C ',' Python','java','go','1125 ','javascript']) print(s.str.findall("a")) #0 [] #1 [] #2 [a, a] #3 [] #4 [] #5 [a, a] #dtype: object
二、apply() 函数详解
在日常的数据处理中,经常会对一个 DataFrame 进行逐行、逐列和逐元素的操作,对应这些操作,Pandas 中的 map()、apply() 和 applymap() 可以解决绝大部分这样的数据处理需求。
三种方法的使用和区别如下:
apply() 函数应用在 DataFrame 的行或列中。
applymap() 函数应用在 DataFrame 的每个元素中。
map() 函数应用在单独一列(Series)的每个元素中。
前面也说了 apply() 函数是一般性的“拆分-应用-合并”方法。 apply() 将一个函数作用于 DataFrame 中的每个行或者列,它既可以得到一个经过广播的标量值,也可以得到一个相同大小的结果数组。
我们先来看下函数形式:
df.apply(func, axis=0, raw=False, result_type=None, args=(), **kwds)
- 其参数含义如下:
- func 表示函数应用于每一列或每一行。
- axis 有 0 和 1 或者索引和列两种取值, 0 或“索引”表示将函数应用于每一列;1或“行”表示将函数应用于每一行。
- 我们先生成初始数据,并将列标签设置为 A 和 B。
df = pd.DataFrame([[4, 9]] * 3, columns=['A', 'B']) df A B 0 4 9 1 4 9 2 4 9
- 可以使用 apply() 函数对 A、B 两列进行求和(axis 参数默认为 0)。
df.apply(np.sum) #A 12 #B 27 #dtype: int64
- 我们将 axis 参数设置为 1,表示对每一行进行求和。
dfdf.apply(np.sum, axis=1) #0 13 #1 13 #2 13 #dtype: int64
- 或者我们使用 lambda 函数做简单的运算。
df.apply(lambda x: x + 1) # A B #0 5 10 #1 5 10 #2 5 10
- 但是这样使用起来非常不方便,每次都要定义 lambda 函数。因此可以通过 def 定义一个函数,然后再调用该函数,在实际处理中都是定义自己所需要的函数完成操作:
def cal_result(df, x, y): df['C'] = (df['A'] + df['B']) * x df['D'] = (df['A'] + df['B']) * y return df
- 我们使用自定义的函数进行计算,并生成 C、D 两列。
df.apply(cal_result, x=3, y=8, axis=1) # A B C D #0 4 9 39 104 #1 4 9 39 104 #2 4 9 39 104
在这里我们先定义了一个 cal_result 函数,它的作用是计算 A,B 列和的 x 倍和 y 倍添加到 C,D 列中。
这里有三种方式可以完成参数的赋值:
(1) 第一种方式直接通过关键字参数赋值,指定参数的值。
(2) 第二种方式是使用 args 关键字参数传入一个包含参数的元组。
(3) 第三种方式传入通过 ** 传入包含参数和值的字典。
apply() 函数的使用是很灵活的,再举一个例子,配合 loc 方法我们能够在最后一行得到一个总和:
df.loc[2] = df.apply(np.sum) df # A B #0 4 9 #1 4 9 #2 12 27
三、applymap() 函数详解
- applymap() 函数针对 DataFrame中 的元素进行操作,还是使用这个数据:
df.applymap(func)
。
df # A B #0 4 9 #1 4 9 #2 12 27
- 们使用 lambda 函数将其变为浮点型。
df.applymap(lambda x: '%.2f'%x) # A B #0 4.00 9.00 #1 4.00 9.00 #2 4.00 9.00
- 在这里可以看到 applymap() 函数操作的是其中的元素,并且是对整个 DataFrame 进行了格式化,我们也可以选择行或列中的元素。
- 对行进行选取。
df[['A']] # A #0 4 #1 4 #2 4
- 对列进行选取。
df[['A']].applymap(lambda x: '%.2f'%x) # A #0 4.00 #1 4.00 #2 4.00
- 需要注意的是这里必须使用 df[[‘A’]] ,表示这是一个 DataFrame,而不是一个 Series,如果使用 df[‘A’] 就会报错。同样从行取元素也要将它先转成 DataFrame。
df['A'].applymap(lambda x: '%.2f'%x) # 异常 #--------------------------------------------------------------------------- #AttributeError Traceback (most recent call last) #<ipython-input-11-585649caf30e> in <module>() #----> 1 df['A'].applymap(lambda x: '%.2f'%x) # 异常 # #E:\Anaconda\lib\site-packages\pandas\core\generic.py in __getattr__(self, name) # 5139 if self._info_axis._can_hold_identifiers_and_holds_name(name): # 5140 return self[name] #-> 5141 return object.__getattribute__(self, name) # 5142 # 5143 def __setattr__(self, name: str, value) -> None: # #AttributeError: 'Series' object has no attribute 'applymap'
- 还需要注意 apply() 函数和 applymap() 函数的区别:
- apply() 函数操作的是行或列的运算,而不是元素的运算,比如在这里使用格式化操作就会报错。
- applymap() 函数操作的是元素,因此没有诸如 axis 这样的参数,它只接受函数传入
四、map() 函数详解
- 如果对 applymap() 函数搞清楚了,那么map() 函数就很简单,说白了 map() 函数是应用在 Series 中的,还是举上面的例子。
df['A'].map(lambda x: '%.2f'%x) #0 4.00 #1 4.00 #2 4.00 #Name: A, dtype: object
- 需要注意的是,Series 没有 applymap() 函数。
df[['A']].applymap(lambda x: '%.2f'%x) #--------------------------------------------------------------------------- #AttributeError Traceback (most recent call last) #<ipython-input-11-585649caf30e> in <module>() #----> 1 df[['A']].applymap(lambda x: '%.2f'%x) # 异常 # #E:\Anaconda\lib\site-packages\pandas\core\generic.py in __getattr__(self, name) # 5139 if self._info_axis._can_hold_identifiers_and_holds_name(name): # 5140 return self[name] #-> 5141 return object.__getattribute__(self, name) # 5142 # 5143 def __setattr__(self, name: str, value) -> None: # #AttributeError: 'Series' object has no attribute 'applymap'