https://github.com/datawhalechina/joyful-pandas
基于自己的日常工作,整理必備的一些知識點,覆蓋95%+的使用場景。
第一章 基礎(chǔ)
1.1 文件讀取與寫入
df = pd.read_csv('data/table.csv')
df_excel = pd.read_excel('data/table.xlsx')
df.to_csv('data/new_table.csv')
df.to_excel('data/new_table2.xlsx', sheet_name='Sheet1')
1.2 基本數(shù)據(jù)結(jié)構(gòu)
Series
-
查看Series自帶的額方法
image.png
Dataframe
- 新增列的方法
常規(guī)方法
df['B']=list('abc')
df.assign(B=pd.Series(list('abc)))
df.merge(pd.Dataframe({'B':['abc']}, how='left', left_index=True, right_index=True))
一般用的都是第一種和第三種方法,實際上第二種方法和第三種方法是等效的,都是講究索引對齊性(left_jone,index),在索引未嚴(yán)格對其的情況下就是缺失值。用第二種方法其實更簡便,但用三種方法更普遍。。
轉(zhuǎn)換
s.to_frame()
s.to_fame().T
1.3 常用基本函數(shù)
df.head()
df.tail()
df.unique()
df.nunique()
df.count() #各列的非空值個數(shù)
df.value_counts()
df.info()
df.describe()
df.describe(percentiles=[.05, .25, .75, .95]) # 可以自行選擇分位數(shù)
df['Math'].idxmax()
df['Math'].nlargest(3)
如果要返回最大幾個值的index,可以用nlargest再返回index,也可以sort_values再返回index。和numpy里面的np.argsort()可以起到一樣的效果
df['Math'].clip(33,80) #截斷,最小值和最大值進行限制
df.replace({'Address':{'street_1':'one','street_2':'two'}}) #字典替換,這里是限定支隊Address列進行替換
df.apply(lambda x : x.apply(lambda x:str(x)+'new')) #單列apply和全局apply的應(yīng)用,相當(dāng)于applymap
1.4 排序
df.sort_index()
df.sort_values()
第二章 索引
2.1 單級索引
- loc
包括單列/行,多列/行,行列聯(lián)合,函數(shù)索引和布爾索引(函數(shù)索引和布爾索引本質(zhì)上無區(qū)別)
df.loc[:,'Height':'Math'] #這樣的多列索引也是可以的
df.loc[[True if i[-1]=='4' or i[-1]=='7' else False for i in df['Address'].values]].head() #這樣的布爾索引可能略繞,不如直接把需要提取的index提取出來
- iloc
- []操作符
嚴(yán)格來說,[]索引只適合布爾索引和列索引,對行索引要用loc和iloc,不然很容易造成困擾。
df[df>80]
df['math']
- 布爾索引
廣泛使用的布爾符號:&, |, ~, isin
df[(df['Gender']=='F')&(df['Address']=='street_2')].head()
-
快速標(biāo)量索引
image.png
看需求使用吧,在數(shù)據(jù)量大的時候特別需要用到
區(qū)間索引
-
interval_range可以創(chuàng)造區(qū)間(注意調(diào)節(jié)左右開閉性)
image.png -
pd.cut可以將數(shù)值進行區(qū)間統(tǒng)計
image.png
當(dāng)然也而已利用interval_range確定區(qū)間,而不是自己輸入bins
df['bins'] = pd.cut(df['math'],pd.interval_range(start=0,end=100,freq=20,closed='left'))
- 區(qū)間索引
df.set_index('bins').loc[[30,50]] #只要區(qū)間和30、50有交叉就會被選中
區(qū)間索引雖然用得少,但是一旦需要用的時候如果掌握不好就很麻煩??偟膩碚f,pd.interval_range基本只在生成df的時候使用,對已有的數(shù)據(jù),一般采用pd.cut和loc的方法來進行索引??!
2.2 多級索引
- 創(chuàng)建多級索引的方式
tuple\array等等都可以,掌握兩種就可以了
from_tuples(雖然是from_tuples,但其實tuples,arrays都可以自動轉(zhuǎn)換)
arrays = [['A','a'],['A','b'],['B','a'],['B','b']]
mul_index = pd.MultiIndex.from_tuples(arrays, names=('Upper', 'Lower'))
pd.DataFrame({'Score':['perfect','good','fair','bad']},index=mul_index)
names不是必須的,看自己需要,我覺得沒啥實際意義。。
from_product(from_tuples是完全匹配,from_product是兩兩相乘的方式)

- 切片索引
display(df.loc[[('A','a'),('B','a')]])
display(df.loc[['A','B']])
df.loc[[('A'),('B','a')]] #會報錯,所以對mul_index必須統(tǒng)一level進行l(wèi)oc索引
差不多可以知道對mul_index進行l(wèi)oc索引很復(fù)雜,要不然就用布爾索引,要不然就轉(zhuǎn)換成單一index后進行索引。。
2.3 索引設(shè)定
- reindex\reset_index\set_index
reindex相當(dāng)于loc的功能,原始沒有的index可以選擇填充(默認(rèn)為空值填充)
reset_index會將當(dāng)前index生成為新的一列
set_index刪除當(dāng)前index并將另一列設(shè)置為index,利用append參數(shù)可以將當(dāng)前索引維持不變

set_index是最靈活的,可以覆蓋reindex的功能
- rename_axis和rename
rename_axis是修改index名和columns名,rename是修改里面的label。。。而且rename_axis有點繞,理論上index_name和columns_name都沒有存在的必要,所以這種情況下用rename來直接修改label就可以了。對于mul_index的情況
arrays = [['A','a'],['A','b'],['B','a'],['B','b']]
mul_index = pd.MultiIndex.from_tuples(arrays, names=('Upper', 'Lower'))
df = pd.DataFrame({'Score':['perfect','good','fair','bad']},index=mul_index)
df.rename_axis(index=['A','B']) #可以
df.rename_axis(index={'Upper':'A','Lower':'B'}) #可以
df.rename_axis({'Upper':'A','Lower':'B'},aixs=0) #不可以
df.rename_axis(['A','B'],axis=0) #可以
所以不是mul_index基本都不會用到
2.4 索引型函數(shù)
-
where和mask
where類似于布爾索引,但布爾索引是只顯示符合條件的行列,where是顯示全部行列,而不符合的行全部顯示為空值
image.png
mask則是符合的行全部顯示為空值
2.5 重復(fù)項處理
- duplicated和drop_duplicates
duplicated返回布爾Series,drop_duplicates保留經(jīng)過刪除重復(fù)項之后的行。
可以自行設(shè)置是以某一列去除重復(fù)行還是以全部列去除重復(fù)行。
2.5 抽樣
df.sample(n=5) #隨機抽樣5行
df.sample(n=5,axis=1) #隨機抽樣5列
df.sample(frac=0.5) #隨機比例抽樣
df.sample(n=5,inplace=True) #有放回抽樣
df.sample(n=5, weights = df['math']) #設(shè)置權(quán)重,這里是以某一列的數(shù)值為權(quán)重來決定該行被抽中的概率,自動歸一化
第三章 分組
3.2 groupby
- 分組
df_grouped = df.groupby('col') #以某列分組可以,每個組的Dataframe的index仍然是原始的index,而不是col
df_grouped = df.groupby(level=0) #以index進行分組,level都是針對index而言的,一個單索引的level只能等于0??!
df_grouped = df.set_index('col').groupby('col') #也是以index進行分組,不過這個時候不等同于df.groupby('col'),每個組的Dataframe的index是col

實際上分組的方式特別靈活,可以參見下面的連續(xù)性變量分組
- 組的容量和組數(shù)
df_grouped.size() #各個組的行數(shù)
df_grouped.ngroups #組的數(shù)目
df_grouped.groups #各個組的詳情
df_grouped.get_group('a') # 獲取特定組,dataframe格式
其實size是最方便的,相當(dāng)于value_counts的功能,能夠直接簡單的知道有多少分組
- 組的遍歷
for name,group in df_grouped:
print(name)
display(group)
-
連續(xù)型變量分組
image.png
也可以先加入一列interval_range后以該列進行分組
image.png
3.3 SAC
統(tǒng)一講一下agg,transform,apply的區(qū)別
- 在不做groupby的情況下,沒有agg的事。。。然后transform和apply本質(zhì)上無區(qū)別,都是對列進行運算,但是不是聚合運算
-
在做了groupby的情況下,agg內(nèi)置函數(shù)最快,transform針對非groupby列進行聚合運算,apply針對包括groupby列進行聚合運算。。當(dāng)然如果限定了對某列進行運算的話,transform和apply無本質(zhì)區(qū)別。。
image.png - 還有就是applymap是針對所有值進行運算。
總結(jié):在內(nèi)置函數(shù)聚合運算的時候用agg,其他時候用apply是基本完全可以替代transform的,transform和apply只有一點是否要對groupby列進行聚合運算的差異。
第四章 變形
4.1 透視表
- pivot_table
透視的核心四要素是:index(行)、columns(列)、value(值)和運算方式(aggfunc),如果不選aggfunc就是默認(rèn)mean
pd.pivot_table(df,index='School',columns='Gender',values='Height',aggfunc=['mean','sum'],margins=True).head()
margin可以匯總狀態(tài),相當(dāng)于不再細(xì)分value。。

如果是要計數(shù)的話,必須選定一列,然后進行count:
pd.pivot(df, index=A,columns=B,values=‘C’,aggfunc=['count'])
- crosstab
貌似屬于簡化版的pivot_table,不支持多級index和多級columns
4.3 stack 和 unstack
- stack
stack是把原來的列作為行進行展開
df.stack(0) #如果是mul_col,則將最外層列展開為行,
df.stack(1) #至少得是mul_col才能展開
- unstack
stack的逆函數(shù),把行變?yōu)榱?,實際上就是pivot_tabel
4.3 dummy
pd.get_dummies(df)
one-hot編碼
第五章 合并
5.1 append 和 assign
append
按序列添加行,和pd.concat axis=0功能一樣,但是這個要求是按序列進行拼接,pd.concat 并不會去檢查序列,好像是順序匹配assign
按序列添加列,和pd.concat axis=1功能一樣,同理也是要求按序列拼接
5.2 combine 和 update
combine是按條件用一個新的df去更新原df的列值,update是不管條件用新的df去覆蓋原df的列值。。但是兩者的應(yīng)用場景應(yīng)該是比較少,不如直接用apply的方式比較通用。
5.3 concat
最常用的拼接之一
5.4 merge和join
merge自然是最常用的拼接(之二),join和merge似乎沒有區(qū)別,只是默認(rèn)的連接方式不一致罷了。
第六章 缺失數(shù)據(jù)
6.1 缺失類型
- isnull 和 notnull來確定缺失值
df.isnull().sum()
df.isnull().all()
df.isnull().any()
all()是所有值都是True值(設(shè)定axis)才會返回True,any()是只要有一個是True就會返回True.
涉及到什么值是True,基本上,只有0、''、False才是False,其余都是True,包括np.nan值。。None值也是True。。所以為了避免誤區(qū),建議只針對bool值用any和all
- 其余缺失符號
np.nan None 和NaT(時間的nan)
基本上沒有太大必要去單獨掌握。。
- 所有類型
重點說一下,目前包括的類型為:
- float
- int
- bool
- datetime64[ns]
- datetime64[ns, tz]
- timedelta[ns]
- category
- object
默認(rèn)的數(shù)據(jù)類型是int64,float64,object和str也是等價,會自動轉(zhuǎn)換為object
6.2 缺失值的運算
基本上針對缺失值基本就是直接略過處理

6.3 填充與剔除
- 填充
df.fillna('value')
df.fillna(method='ffill')
df.fillna(method='backfill')
df.fillna(df.mean()) #自動對齊特性
- 剔除
df.dropna(axis=1) #默認(rèn)就是部分缺失則去除
df.dropna(axis=0) #默認(rèn)就是部分缺失則去除
df.dropna(axis=1,how='all') #全缺失去除
df.dropna(axis=1,how='any') #部分缺失去除
df.dropna(axis=0,subset=['B','C']) #對特定列進行缺失搜索
6.4 插值
- 線性插值
# s是series
s.interpolate() # 與index無關(guān)的插值,只考慮index的順序而不是值
s.interpolate(method='index') # 與index有關(guān)的插值,需要考慮idnex的值
s.interpolate(method='time') #與index有關(guān),并且index是時間格式
- 高級插值
多項式差值、樣條插值等等。。也是可以通過設(shè)定method實現(xiàn)
第七章 文本數(shù)據(jù)
7.2 拆分與拼接
- 拆分split
s = pd.Series(['a_b_c', 'c_d_e', np.nan, 'f_g_h'], dtype="str")
s.str.split('_') #拆分后成為list
s.str.split('_').str[0] # 列表的第0項
s.str[0] #str的第0項
s.str.split('_',expand=True,n=1) #expand控制是否需要展開為多列,n控制展開的列數(shù)
str的相關(guān)方法都是針對series(或者index的list)操作
- 拼接cat
s = pd.Series(['ab',None,'d'],dtype='string')
s.str.cat(sep=',',na_rep='*') #sep控制拼接符、na_rep控制對缺失值的替代處理
str.cat只能對series操作,拼接之后是一個str

s.str.cat(s2,sep=',',na_rep='*') #兩個series合并,則按序列進行拼接,默認(rèn)left_join
s.str.cat([s+'0',s*2]) #也可以進行series和df/多個series的拼接
s.str.cat(df) #也可以進行series和df/多個series的拼接
如果要對df的所有列進行拼接,可以采用以下方法
df.iloc[:,0].str.cat(df.iloc[:,1:]) #必須以series作為引導(dǎo)
4.3 替換
- replace
支持正則匹配替換,用r開頭
s.str.replace(r'^[AB]','***')
s.str.replace(r'([ABC])(\w+)',lambda x:x.group(2)[1:]+'*') #允許匿名進行g(shù)roup的操作,0返回字符本身,從1開始才是子組
s.str.replace(r'(?P<one>[ABC])(?P<two>\w+)',lambda x:x.group('two')[1:]+'*') #利用?P<....>表達(dá)式可以對子組命名調(diào)用
df的replace是全局替換(好像如果采用regex參數(shù)也可以實現(xiàn)正則匹配),str.replace是允許正則匹配的
4.4 子串匹配與提取
- str.extract
str.extract是綜合split和replace的功能,實現(xiàn)更加靈活的匹配
#下面兩種情況結(jié)果是一樣的
pd.Series(['10-87', '10-88', '10-89'],dtype="string").str.extract(r'([\d]{2})-([\d]{2})')
pd.Series(['10-87', '10-88', '10-89'],dtype="string").str.split('_', expand=True)
replace只能返回某一個group的值,extract能把所有符合要求的group都返回,以及實現(xiàn)拆分
str.extractall
會全匹配,如果可以匹配多個結(jié)果,則建立多級索引str.contains
同樣支持正則匹配
pd.Series(['1', None, '3a', '3b', '03c'], dtype="string").str.contains(r'[0-9][a-z]')
- str.match
str.match與其區(qū)別在于,match依賴于python的re.match,檢測內(nèi)容為是否從頭開始包含該正則模式
4.3 其他常用方法
- str.strip
- str.lower和str.upper
- str.swapcase和str.capitalize
分別表示交換字母大小寫和大寫首字母 - str.isnumeric()
判斷是否是數(shù)值
第八章
整體來說分類category應(yīng)該用到得很少
pd.Categorical(["a", "b", "c", "a"], categories=['a','b','c']) #這是類似于list的categrical數(shù)據(jù)
s = pd.Series(cat) #這是dtype為category的series

這個就是catgorical數(shù)據(jù),形似list
一些最基本的方法
s.cat.categories #查看分類情況
s.cat.ordered #查看是否排序,雖然一般用不到
還有一些修改categories的方法,一般用不到,如果需要用的時候,可以用pd.cut或者pd.Categorical來生成新列







