專做正品 網(wǎng)站青島網(wǎng)絡(luò)科技公司排名
今天我們看一下Pandas中的數(shù)據(jù)轉(zhuǎn)換,話不多說直接開始🎇
目錄
一、??apply函數(shù)應(yīng)用
apply是一個自由度很高的函數(shù)
對于Series,它可以迭代每一列的值操作:
二、??矢量化字符串
為什么要用str屬性
替換和分割
提取子串
提取第一個匹配的子串
測試是否包含子串
生成啞變量
??方法摘要?
函數(shù)應(yīng)用
import pandas as pd
import numpy as np
一、??apply函數(shù)應(yīng)用
apply是一個自由度很高的函數(shù)
對于Series,它可以迭代每一列的值操作:
df = pd.read_csv('data/table.csv')
df.head()
df['Math'].apply(lambda x:str(x)+'!').head() #可以使用lambda表達式,也可以使用函數(shù)
?
💥對于DataFrame,它在默認axis=0下可以迭代每一個列操作:?
# def test(x):
# print(x)
# return x
# df.apply(test)#axis=0
# df.apply(lambda x:x.apply(lambda x:str(x)+'!')).head() #這是一個稍顯復(fù)雜的例子,有利于理解apply的功能
temp_data = df[["Height", "Weight", "Math"]]
# temp_data# 生成一個表格,每列是原來列的最大值,最小值,以及均值
def transfor(x):# x是Seriesresult = pd.Series()result["max"] = x.max()result["min"] = x.min()result["avg"] = x.mean()return resulttemp_data.apply(transfor, axis=0)
# 按列來傳入,一列就是一個x
?
def transfor(x):# x -> seriesbmi = x["Weight"]/(x["Height"]/100)**2x["bmi"] = bmireturn xtemp_data.apply(transfor, axis=1)# BMI = # apply
Pandas中的axis參數(shù)=0時,永遠表示的是處理方向而不是聚合方向,當axis='index'或=0時,對列迭代對行聚合,行即為跨列,axis=1同理?💥
二、??矢量化字符串
為什么要用str屬性
文本數(shù)據(jù)也就是我們常說的字符串,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)# 將出生日期轉(zhuǎn)為時間戳
user_info["birth"] = pd.to_datetime(user_info.birth)
user_info
💯在對 Series 中每個元素處理時,我們可以使用apply
方法。
💯比如,我想要將每個城市都轉(zhuǎn)為小寫,可以使用如下的方式。
user_info.city.map(lambda x: x.lower())
AttributeError: 'float' object has no attribute 'lower'
💯錯誤原因是因為 float 類型的對象沒有 lower 屬性。這是因為缺失值(np.nan)屬于float 類型。這時候我們的str
屬性操作來了,來看看如何使用吧~
# 將文本轉(zhuǎn)為小寫
user_info.city.str.lower()
可以看到,通過 `str` 屬性來訪問之后用到的方法名與 Python 內(nèi)置的字符串的方法名一樣。并且能夠自動排除缺失值。我們再來試試其他一些方法。例如,統(tǒng)計每個字符串的長度。?
user_info.city.str.len()
替換和分割
使用 .srt
屬性也支持替換與分割操作。
先來看下替換操作,例如:將空字符串替換成下劃線。
user_info.city.str.replace(" ", "_")
🏹replace
方法還支持正則表達式,例如將所有開頭為 S
的城市替換為空字符串。
user_info.city.str.replace("^S.*", " ")
🏹再來看下分割操作,例如根據(jù)空字符串來分割某一列
user_info.city.str.split(" ")
🏹分割列表中的元素可以使用 get
或 []
符號進行訪問:
user_info.city.str.split(" ").str.get(1)
🏹設(shè)置參數(shù) expand=True
可以輕松擴展此項以返回 DataFrame。
user_info.city.str.split(" ", expand=True)
提取子串
既然是在操作字符串,很自然,你可能會想到是否可以從一個長的字符串中提取出子串。答案是可以的。
提取第一個匹配的子串
extract
方法接受一個正則表達式并至少包含一個捕獲組,指定參數(shù) expand=True
可以保證每次都返回 DataFrame。
例如,現(xiàn)在想要匹配空字符串前面的所有的字母,可以使用如下操作:
user_info.city.str.extract("(\w+)\s+", expand=True)
如果使用多個組提取正則表達式會返回一個 DataFrame,每個組只有一列。
例如,想要匹配出空字符串前面和后面的所有字母,操作如下:
user_info.city.str.extract("(\w+)\s+(\w+)", expand=True)
測試是否包含子串
除了可以匹配出子串外,我們還可以使用 contains
來測試是否包含子串。例如,想要測試城市是否包含子串 “Zh”。
user_info.city.str.contains("Zh")
當然了,正則表達式也是支持的。例如,想要測試是否是以字母 “S” 開頭。
user_info.city.str.contains("^S")
生成啞變量
這是一個神奇的功能,通過 get_dummies
方法可以將字符串轉(zhuǎn)為啞變量,sep
參數(shù)是指定啞變量之間的分隔符。來看看效果吧。
user_info.city.str.get_dummies(sep=" ")
這樣,它提取出了 Bei, Guang, Hai, Jing, Shang, Shen, Zhen, Zhou 這些啞變量,并對每個變量下使用 0 或 1 來表達。實際上與 One-Hot(狂熱編碼)是一回事。
??方法摘要?
這里列出了一些常用的方法摘要。
方法 | 描述 |
---|---|
cat() | 連接字符串 |
split() | 在分隔符上分割字符串 |
rsplit() | 從字符串末尾開始分隔字符串 |
get() | 索引到每個元素(檢索第i個元素) |
join() | 使用分隔符在系列的每個元素中加入字符串 |
get_dummies() | 在分隔符上分割字符串,返回虛擬變量的DataFrame |
contains() | 如果每個字符串都包含pattern / regex,則返回布爾數(shù)組 |
replace() | 用其他字符串替換pattern / regex的出現(xiàn) |
repeat() | 重復(fù)值(s.str.repeat(3)等同于x * 3 t2 >) |
pad() | 將空格添加到字符串的左側(cè),右側(cè)或兩側(cè) |
center() | 相當于str.center |
ljust() | 相當于str.ljust |
rjust() | 相當于str.rjust |
zfill() | 等同于str.zfill |
wrap() | 將長長的字符串拆分為長度小于給定寬度的行 |
slice() | 切分Series中的每個字符串 |
slice_replace() | 用傳遞的值替換每個字符串中的切片 |
count() | 計數(shù)模式的發(fā)生 |
startswith() | 相當于每個元素的str.startswith(pat) |
endswith() | 相當于每個元素的str.endswith(pat) |
findall() | 計算每個字符串的所有模式/正則表達式的列表 |
match() | 在每個元素上調(diào)用re.match,返回匹配的組作為列表 |
extract() | 在每個元素上調(diào)用re.search,為每個元素返回一行DataFrame,為每個正則表達式捕獲組返回一列 |
extractall() | 在每個元素上調(diào)用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 |
函數(shù)應(yīng)用
雖說 Pandas 為我們提供了非常豐富的函數(shù),有時候我們可能需要自己定制一些函數(shù),并將它應(yīng)用到 DataFrame 或 Series。常用到的函數(shù)有:map
、apply
、applymap
。
map
是 Series 中特有的方法,通過它可以對 Series 中的每個元素實現(xiàn)轉(zhuǎn)換。
如果我想通過年齡判斷用戶是否屬于中年人(30歲以上為中年),通過 map
可以輕松搞定它。
# 接收一個 lambda 函數(shù)
user_info.age.map(lambda x: "yes" if x >= 30 else "no")
又比如,我想要通過城市來判斷是南方還是北方,我可以這樣操作
user_info.citycity_map = {"BeiJing": "north","ShangHai": "south","GuangZhou": "south","ShenZhen": "south"
}# 傳入一個 map
user_info.city.str.replace(" ","").map(city_map)
apply 方法既支持 Series,也支持 DataFrame,在對 Series 操作時會作用到每個值上,在對 DataFrame 操作時會作用到所有行或所有列(通過 axis 參數(shù)控制)。
# 對 Series 來說,apply 方法 與 map 方法區(qū)別不大。
user_info.age.apply(lambda x: "yes" if x >= 30 else "no")
applymap 方法針對于 DataFrame,它作用于 DataFrame 中的每個元素,它對 DataFrame 的效果類似于 apply 對 Series 的效果。
大家如果感覺可以的話,可以去做一些小練習(xí)~~
【練習(xí)一】 現(xiàn)有一份關(guān)于字符串的數(shù)據(jù)集,請解決以下問題:
(a)現(xiàn)對字符串編碼存儲人員信息(在編號后添加ID列),使用如下格式:“×××(名字):×國人,性別×,生于×年×月×日”
(b)將(a)中的人員生日信息部分修改為用中文表示(如一九七四年十月二十三日),其余返回格式不變。
(c)將(b)中的ID列結(jié)果拆分為原列表相應(yīng)的5列,并使用equals檢驗是否一致。