最後一次更新日期: 2019/9/23
新增字串和時間處理的簡要介紹
缺失值填充、刪除、讀寫excel小節做了少許補充
第四章節補充了使用行列迭代器的方法
第五章節補充了設定索引、重置索引、重新命名索引的方法
第三章節補充了基本運算子及對應函式的參考列表、移位與差量計算
pandas
是基於numpy
的資料分析庫,提供一些更易用的資料模型和大量高效的統計方法。
使用前先匯入模組:
import pandas as pd
按需匯入以下模組:
import numpy as np
import matplotlib.pyplot as plt
點選下方連結可前往各小節
使用指南1 - 資料模型與屬性 (索引,資料序列,資料框,分類資料)
使用指南3 - 陣列與統計運算 (基本運算和標量值函式,統計方法,自定義函式,廣播)
使用指南5 - 增刪改 (更新,增加,刪除,變更索引,行列轉置,缺失值填充)
使用指南8 - 讀寫 (讀寫csv,讀寫excel,讀寫sql)
一. 資料模型與屬性
1. 索引Index
numpy中只有位置索引,而pandas還增加了標籤索引,依賴於一個專用的Index
型別。
常規索引
pd.Index([1,2,3])
Out[64]: Int64Index([1, 2, 3], dtype='int64')
pd.Index([1.,2.,3.])
Out[65]: Float64Index([1.0, 2.0, 3.0], dtype='float64')
pd.Index(['a','b','c'])
Out[66]: Index(['a', 'b', 'c'], dtype='object')
pd.Index(range(10))
Out[67]: RangeIndex(start=0, stop=10, step=1)
pd.Index(range(10)).values
Out[68]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int64)
import datetime as dt
dt1=dt.datetime.now()
dt2=dt1+dt.timedelta(days=1)
pd.Index([dt1,dt2])
Out[81]: DatetimeIndex(['2019-03-09 20:56:14.644159', '2019-03-10 20:56:14.644159'], dtype='datetime64[ns]', freq=None)
複製程式碼
Index
在建立時會根據傳入資料(一維序列)自動生成具體的索引型別,也可通過dtype
引數指定型別,但無法正常轉換時會報錯;copy
引數指定建立索引時是否複製源資料,預設false
。
具體的索引型別也可通過各自的方法建立。
Index.values
可以檢視作為資料基礎的一維陣列,Index.dtype
可以檢視資料型別。
多級索引
pandas提供了多級索引以便於分組資料,可用於構造高維資料集,groupby
計算也會自動產生多級索引。
midx=pd.MultiIndex(levels=[['a','b'],['c','d']],labels=[[1,1,0,0],[0,1,0,1]],name=['idx1','idx2'])
midx
Out[6]:
MultiIndex(levels=[['a', 'b'], ['c', 'd']],
labels=[[1, 1, 0, 0], [0, 1, 0, 1]],
names=['idx1', 'idx2'])
midx.set_labels([1,0,1,0],level=1)
Out[9]:
MultiIndex(levels=[['a', 'b'], ['c', 'd']],
labels=[[1, 1, 0, 0], [1, 0, 1, 0]],
names=['idx1', 'idx2'])
midx.swaplevel(0,1)
Out[11]:
MultiIndex(levels=[['c', 'd'], ['a', 'b']],
labels=[[0, 1, 0, 1], [1, 1, 0, 0]],
names=['idx2', 'idx1'])
pd.MultiIndex.from_arrays([['a','a','b','b'],['c','d','c','d']],names=['idx1','idx2'])
Out[12]:
MultiIndex(levels=[['a', 'b'], ['c', 'd']],
labels=[[0, 0, 1, 1], [0, 1, 0, 1]],
names=['idx1', 'idx2'])
複製程式碼
MultiIndex
的第一個引數levels
是每個級別的唯一標籤列表,是一個兩層巢狀的序列,外層對應級別,內層對應唯一標籤;
第二個引數labels
是所有記錄在每個級別上選取的標籤序號,也是一個兩層巢狀的序列,外層對應級別,內層對應記錄,新版本中已被codes
引數取代;
第四個引數names
是每個級別的名稱。
MultiIndex
提供了一些輔助方法,set_levels
、set_labels
、set_names
可以設定整體或是某一級別的索引屬性,通過level
引數指定級別,預設設定整體;
swaplevel
可以交換級別,droplevel
可以刪除級別,sortlevel
可以對指定級別排序;
from_array
、from_tuples
、from_product
、from_frame
方法可從其他結構的資料中建立索引。
2. 資料序列Series
s=pd.Series([1,2,3,4],name='s1')
s
Out[100]:
0 1
1 2
2 3
3 4
Name: s1, dtype: int64
pd.Series([[1,2],[3,4]],index=['row1','row2'])
Out[101]:
row1 [1, 2]
row2 [3, 4]
dtype: object
s.dtype
Out[102]: dtype('int64')
s.name
Out[103]: 's1'
s.values
Out[104]: array([1, 2, 3, 4], dtype=int64)
s.index
Out[105]: RangeIndex(start=0, stop=4, step=1)
s.shape
Out[106]: (4,)
複製程式碼
核心資料模型其一,由序列名name
、標籤索引index
、值陣列(一維)values
組成。用於存放一維資料,只有一個軸方向:0,shape
屬性可以檢視資料集的形狀。
建立時只能接收一維序列資料(list,tuple,ndarray),超過一維的將後面的維度看作元素的維度,會根據傳入的資料自動判斷型別,也可通過dtype
引數顯示指定。
預設情況下會生成範圍索引,可通過index
引數指定一個一維序列作為索引,也可在建立後直接為index
屬性賦值。
3. 資料框DataFrame
df=pd.DataFrame([[1,'a'],[2,'b']],columns=['col1','col2'])
df
Out[108]:
col1 col2
0 1 a
1 2 b
df.dtypes
Out[113]:
col1 int64
col2 object
dtype: object
df.index
Out[114]: Int64Index([1, 2], dtype='int64', name='col1')
df.columns
Out[116]: Index(['col1', 'col2'], dtype='object')
df.values
Out[117]:
array([[1, 'a'],
[2, 'b']], dtype=object)
df.col2
Out[125]:
col1
1 a
2 b
Name: col2, dtype: object
pd.DataFrame({'col1':[1,3],'col2':['a','b']})
Out[126]:
col1 col2
0 1 a
1 3 b
df.shape
Out[127]: (2, 2)
複製程式碼
核心資料模型其二,也就是資料表,由列標籤索引columns
、行標籤索引index
、值陣列(二維)values
組成。用於存放二維資料,有兩個軸方向:0和1,對應行座標和列座標,shape
屬性可以檢視資料集的形狀。列資料的訪問可以通過與列名相同的屬性名訪問,僅在定義了字串列名時可用,一個單列即是一個Series
。
建立時只能接收二維序列資料(list,tuple,ndarray),超過二維的將後面的維度看作元素的維度,會根據傳入的資料自動判斷型別,也可通過dtype
引數顯示指定,與numpy不太一樣的是,DataFrame
的列可以定義不同的資料型別,通過建立時的自動判斷,或是篩選出列後轉換型別,DataFrame.dtypes
屬性可檢視所有列的資料型別。相比numpy,pandas的DataFrame
建立還增加了對dict
資料來源的支援,key
對應列名,value
對應列資料。
預設情況下會生成範圍索引,可通過index
引數指定一個一維序列作為索引,也可在建立後直接為index
屬性賦值,DataFrame.set_index
方法可以返回替換了索引的資料框副本而不影響原資料。
DataFrame
相當於Series
的堆疊,沿DataFrame
的行或列方向進行寬度為1的切片,得到的就是一個Series
。
原本pandas還提供了三維的資料模型Panel
,但新版中已經廢棄,可嘗試使用多級索引MultiIndex
來構造更高維度的資料集。
4. 分類資料Categorical
pandas提供了分類資料型別用於約束此類資料,該型別會限制分類標籤的取值,並可為分類標籤提供排序依據。
pd.Categorical(['a','b','b','c'],categories=['a','b'],ordered=True)
Out[14]:
[a, b, b, NaN]
Categories (2, object): [a < b]
pd.Categorical(['a','b','b','c'])
Out[15]:
[a, b, b, c]
Categories (3, object): [a, b, c]
複製程式碼
第一個引數values
為所有分類標籤的序列;
第二個引數categories
為唯一分類標籤的序列,當指定該引數後,values
中不屬於categories
的標籤會被替換為NaN
,不指定時會根據values
自動生成;
第三個引數ordered
宣告唯一分類標籤是否指示排序方式,為True
時會按categories
中的順序對標籤標定大小關係,預設False
。
二. 資料型別與轉換
1. 資料型別
pandas支援的資料型別就是numpy的資料型別,在建立資料模型時同樣可通過dtype
引數指定。
常用的資料型別有:np.bool_
(bool),np.int64
(int),np.float64
(float),np.datetime64
(datetime),object
(str等),pd.Categorical
(category)。
更詳細的型別說明可檢視numpy的使用指南。
和numpy不太一樣的是,numpy中int
型別預設為np.int32
,而pandas中預設np.int64
;numpy中儲存字串優先採用定長的np.str_
,而pandas中統一使用object
。
pandas資料模型使用單個ndarray
作為基礎資料,所以當pandas的每列採用不同資料型別時,作為資料來源的ndarray
整體被設定為object
資料型別。
2. 型別轉換
df=pd.DataFrame([[1,'2'],[3,'a']],columns=['col1','col2'])
df.dtypes
Out[49]:
col1 int64
col2 object
dtype: object
df.col1.astype('float')
Out[50]:
0 1.0
1 3.0
Name: col1, dtype: float64
pd.to_numeric(df.col2,errors='ignore')
Out[52]:
0 2
1 a
Name: col2, dtype: object
pd.to_numeric(df.col2,errors='coerce')
Out[53]:
0 2.0
1 NaN
Name: col2, dtype: float64
複製程式碼
pandas和numpy一樣主要使用astype
進行型別轉換,該方法返回轉換後資料,需要在原資料上更改時可以用返回值去覆蓋原資料。
當需要進行一些可能會失敗的轉換時,可以考慮使用專用的方法,例如pd.to_numeric
用於將一個Series
轉換為數字型別,errors
引數可以指定對錯誤的處理方式:'coerce'
表示強制轉換,不能轉換的元素會替換為NaN
;'ignore'
表示存在無法轉換的元素時會放棄轉換。
當需要對DataFrame
整體應用轉換時,可使用apply
方法。
三. 陣列與統計運算
1. 基本運算和標量值函式
pandas過載了python的大部分運算子,可以直接進行陣列計算,numpy的標量值函式也可直接使用,這些運算都是將原本作用於單個元素的運算擴充到整個陣列。
df=pd.DataFrame([[1,'2'],[3,'a']],columns=['col1','col2'])
df+df
Out[57]:
col1 col2
0 2 22
1 6 aa
np.sqrt(df.col1)
Out[201]:
0 1.000000
1 1.732051
Name: col1, dtype: float64
複製程式碼
使用的運算子和函式必須對參與運算的所有資料型別都是有意義的,否則會報錯。
匹配方式
s1=pd.Series([1,2,3,4],index=[0,1,2,3])
s2=pd.Series([5,6,7,8],index=[1,2,3,4])
s1+s2
Out[156]:
0 NaN
1 7.0
2 9.0
3 11.0
4 NaN
dtype: float64
複製程式碼
此處需要注意pandas和numpy的區別,pandas的陣列運算在元素匹配上是基於標籤索引的,未能匹配到的位置會被替換為NaN,numpy則是基於位置索引。
基本運算子與對應的函式
運算子 | 對應函式 | 說明 |
---|---|---|
+ | add | 相加 |
- | sub | 相減 |
* | mul | 相乘 |
/ | div | 相除 |
// | floordiv | 整除 |
% | mod | 取餘 |
** | pow | 指數冪 |
== | eq | 相等 |
!= | ne | 不等 |
>= | ge | 大於等於 |
<= | le | 小於等於 |
> | gt | 大於 |
< | lt | 小於 |
~ | - | 按位取反 |
& | - | 按位與 |
| | - | 按位或 |
^ | - | 按位異或 |
pandas資料模型的邏輯運算不能使用not、and、or,應當使用~、&、|;
位移運算子<<、>>也不可用於pandas資料模型。
2. 統計方法
聚合函式
pandas繼承了numpy的聚合函式:sum
、mean
、max
、min
等。
可通過Series
和DataFrame
的方法呼叫,或是呼叫numpy下的靜態方法。
df.sum()
Out[58]:
col1 4
col2 2a
dtype: object
np.max(df)
Out[60]:
col1 3
col2 a
dtype: object
df.agg({'col1':'max','col2':'sum'})
Out[114]:
col1 3
col2 2a
dtype: object
df.agg(['max','sum'])
Out[115]:
col1 col2
max 3 a
sum 4 2a
複製程式碼
通過pandas資料模型的方法呼叫時,
第一個引數axis
可以指定統計的軸,Series
指定該引數沒有意義,DataFrame
預設沿軸0統計,即按列統計。pandas無法指定對所有軸展開統計,如有需要可以使用numpy的方法;
第二個引數skipna
可以指示是否跳過NaN
值;
第三個引數level
用於在存在多級索引的情況下指定某一級索引進行統計;
第四個引數numeric_only
用於指定是否只對數字應用計算。
當對DataFrame
沿行方向統計時,由於不同列的資料型別可能不一樣,需保證對應運算是有意義的,否則無法得到期望的結果。
agg
方法是aggregate
方法的簡寫,用於對不同列應用不同聚合函式或是多種聚合函式,可以傳入list
或是dict
宣告統計方式。
分組統計
pandas提供了類似於sql的groupby
方法用於分組統計。
df=pd.DataFrame([['a','c',1],['a','d',2],['b','d',3]],columns=['col1','col2','col3'])
In [89]: df
Out[89]:
col1 col2 col3
0 a c 1
1 a d 2
2 b d 3
result=df.groupby(by=['col1','col2']).agg(['max','min'])
result
Out[94]:
col3
max min
col1 col2
a c 1 1
d 2 2
b d 3 3
result.sum(level=0)
Out[95]:
col3
max min
col1
a 3 3
b 3 3
gb=df.groupby(by=['col1','col2'])
gb.groups
Out[141]:
{('a', 'c'): Int64Index([0], dtype='int64'),
('a', 'd'): Int64Index([1], dtype='int64'),
('b', 'd'): Int64Index([2], dtype='int64')}
gb.get_group(('a','c'))
Out[142]:
col1 col2 col3
0 a c 1
複製程式碼
只呼叫groupby
方法會得到一個DataFrameGroupBy
物件,通過其groups
方法可檢視所有分組資訊,get_group
方法可獲取指定分組。
該物件可呼叫各種聚合函式,或呼叫agg
方法進行復合的聚合統計,返回包含多級索引的DataFrame
統計結果表,對於結果表,可以繼續應用統計函式並通過level
引數指定索引級別進行二次統計。
移位與差異計算
在分析資料時會有需要計算相鄰記錄之間變化量的情況,可通過shift方法實現記錄的移位再相減或直接使用diff方法。
s=pd.Series([1,2,3,4])
s
Out[28]:
0 1
1 2
2 3
3 4
dtype: int64
s.shift()
Out[29]:
0 NaN
1 1.0
2 2.0
3 3.0
dtype: float64
s.shift(periods=2)
Out[32]:
0 NaN
1 NaN
2 1.0
3 2.0
dtype: float64
s-s.shift()
Out[30]:
0 NaN
1 1.0
2 1.0
3 1.0
dtype: float64
s.diff()
Out[33]:
0 NaN
1 1.0
2 1.0
3 1.0
dtype: float64
s.pct_change()
Out[34]:
0 NaN
1 1.000000
2 0.500000
3 0.333333
dtype: float64
複製程式碼
shift方法用於指定方向上的資料移位,diff方法用於指定位移下的變化量計算,pct_change方法用於指定位移下的變化率計算。periods引數指定位移量,預設1,axis指定軸方向,預設0。
3. 應用自定義函式
除pandas和numpy提供的函式外,還可以自定義函式並使用apply
、applymap
、map
方法快速應用於整個資料集。
df.apply(lambda x: x.col1+x.col2, axis=1)
Out[119]:
0 3
1 7
dtype: int64
def add(row):
return row.col1+row.col2
df.apply(add, axis=1)
Out[121]:
0 3
1 7
dtype: int64
df.applymap(lambda x: x*2)
Out[122]:
col1 col2
0 2 4
1 6 8
def double(item):
return item*2
df.applymap(double)
Out[124]:
col1 col2
0 2 4
1 6 8
s=pd.Series(['a','b','b'])
s.map(lambda x: x*2)
Out[129]:
0 aa
1 bb
2 bb
dtype: object
s.map({'a':'c','b':'d'})
Out[130]:
0 c
1 d
2 d
dtype: object
複製程式碼
DataFrame
有apply
和applymap
兩個方法:
apply
將函式應用於每行或者每列,axis
引數指定應用函式的軸方向,值為0表示按列應用,即逐列作為函式的引數進行計算,值為1表示按行應用,預設為0;
applymap
將函式應用於每個元素。
Series
只有一個map
方法,用於將函式應用於元素,除此以外,還提供值對映的功能,輸入dict
型別時會根據key-value對映將相應的值替換。
支援lambda匿名函式。
4. 廣播
l2=[1,2]
a2=np.array(l2)
s2=pd.Series(l2)
df21=pd.DataFrame([1,2])
df12=pd.DataFrame([[1,2]])
l22=[[1,2],[3,4]]
a22=np.array(l22)
df22=pd.DataFrame(l22)
df23=pd.DataFrame([[3,4,5],[6,7,8]])
df22+l2
Out[99]:
0 1
0 2 4
1 4 6
df22+a2
Out[100]:
0 1
0 2 4
1 4 6
df22+s2
Out[101]:
0 1
0 2 4
1 4 6
df22+df21
Out[102]:
0 1
0 2 NaN
1 5 NaN
df22+df12
Out[103]:
0 1
0 2.0 4.0
1 NaN NaN
df23+s2
Out[104]:
0 1 2
0 4.0 6.0 NaN
1 7.0 9.0 NaN
df21+df12
Out[130]:
0 1
0 2.0 NaN
1 NaN NaN
複製程式碼
pandas的廣播機制繼承自numpy但有不一樣的地方:
標量值會與DataFrame
或Series
中每個元素進行同樣的計算;
Series
或一維list
或一維ndarray
會與DataFrame
的每一行進行運算,Series
在長度不足以匹配DataFrame
的行時不足部分會替換為NaN
,其他兩種長度不足會報錯;
DataFrame
與DataFrame
進行運算會按元素匹配,無論行列,長度不足的部分都會替換為NaN
;
二維ndarray
與DataFrame
的運算遵循numpy的廣播規則,長度不足且為1的軸會被廣播至同等大小; 二維list
與DataFrame
的運算不被支援。
四. 查詢和關聯
1. 索引查詢
(1). 索引器格式
單值選取:[value,...]
多值選取:[[value1,value2],...]
範圍選取:[start:end:step,...]
start
表示區間的開始,預設值0,end
表示區間的結束(不包含),預設值等於軸長度,step
表示選取的步長,預設值1,採用預設值的引數可以省略,[:,...]
表示對應軸方向上全部選取。
pandas中索引器的格式與numpy差不多,但用法有區別。pandas除了numpy的位置索引,還增加了標籤索引,雖然可以對Series
和DataFrame
直接使用索引器,但用法被嚴格限制,建議改用iloc
和loc
方法進行索引。
(2). 直接索引
df=pd.DataFrame(np.arange(1,10).reshape((3,3)),columns=['col1','col2','col3'],index=['row1','row2','row3'])
df[0:3:2]
Out[158]:
col1 col2 col3
row1 1 2 3
row3 7 8 9
df['row1':'row3':2]
Out[161]:
col1 col2 col3
row1 1 2 3
row3 7 8 9
df['col2']
Out[162]:
row1 2
row2 5
row3 8
Name: col2, dtype: int32
df[['col1','col3']]
Out[163]:
col1 col3
row1 1 3
row2 4 6
row3 7 9
df['col2'][1:3]
Out[168]:
row2 5
row3 8
Name: col2, dtype: int32
複製程式碼
直接索引提供了有限的幾種使用方式:按行位置進行索引切片、按行標籤進行索引切片、按列標籤取列、按列標籤列表取多列、布林索引篩選行、索爾索引篩選元素等。 一次索引器只能使用一種方式,不能行列同時操作,如有需要,可進行連續索引。
(3). loc和iloc索引
df.loc['row1','col1']
Out[169]: 1
df.loc['row1':'row3':2,'col1':'col3':2]
Out[170]:
col1 col3
row1 1 3
row3 7 9
df.iloc[0,0]
Out[185]: 1
df.iloc[0:3:2,0:3:2]
Out[186]:
col1 col3
row1 1 3
row3 7 9
複製程式碼
loc
專用於標籤索引,iloc
專用於位置索引,索引器可接收單值、列表、範圍、布林索引,可同時索引行和列。
(4). 布林索引
df>5
Out[190]:
col1 col2 col3
row1 False False False
row2 False False True
row3 True True True
df[df>5]
Out[191]:
col1 col2 col3
row1 NaN NaN NaN
row2 NaN NaN 6.0
row3 7.0 8.0 9.0
df['col1']>2
Out[192]:
row1 False
row2 True
row3 True
Name: col1, dtype: bool
df.loc[df['col1']>2]
Out[193]:
col1 col2 col3
row2 4 5 6
row3 7 8 9
df.loc[df['col1']>2,df.iloc[1]>5]
Out[196]:
col3
row2 6
row3 9
df.iloc[df['col1'].values>2]
Out[208]:
col1 col2 col3
row2 4 5 6
row3 7 8 9
複製程式碼
布林索引是一種比較特殊的索引,通過對pandas或numpy的資料模型進行比較運算可以得到,本質上就是資料型別為bool
的Serie
或DataFrame
或ndarray
,與源資料形狀相同,用於標識每個元素是否符合篩選條件。在索引器中使用布林索引可以篩選出符合條件的資料。
在直接索引時,二維布林索引可以用於篩選DataFrame
的元素,形狀不變,不符合條件的元素會被替換為NaN
,這一點和numpy不一樣,numpy進行同樣形式的篩選時會將符合條件的元素構造為新的一維陣列返回;一維布林索引只可以用於篩選行資料;
在使用loc
索引時,不能使用二維布林索引,只能針對每個軸使用一維布林索引,並且必須是由Series
運算得到的帶有標籤索引的布林索引;
在使用iloc
索引時,同樣不能使用二維布林索引,只能針對每個軸使用一維布林索引,並且必須是由一維ndarray
運算得到的不含標籤索引的布林索引(Series.values
可得到對應的ndarray
)。
(5). 指定值查詢
df=pd.DataFrame({'a':[np.nan,1,2],'b':[3,np.nan,4]})
df
Out[142]:
a b
0 NaN 3.0
1 1.0 NaN
2 2.0 4.0
df.isin([2,3])
Out[143]:
a b
0 False True
1 False False
2 True False
df.isna()
Out[144]:
a b
0 True False
1 False True
2 False False
複製程式碼
isin
方法用於查詢存在於指定列表中的值,isna
方法用於查詢NaN值,兩方法都會返回布林索引,通常結合索引器使用。
2. 行列迭代
pandas提供了迭代器用於遍歷行或者列。
(1). 行迭代
df=pd.DataFrame([{'a':1,'b':2,'c':3},{'a':4,'b':5,'c':6}])
for i,row in df.iterrows():
print("\nrow(%s):\n%s"%(i,row))
row(0):
a 1
b 2
c 3
Name: 0, dtype: int64
row(1):
a 4
b 5
c 6
Name: 1, dtype: int64
複製程式碼
(2). 列迭代
for j,col in df.iteritems():
print("\ncol(%s):\n%s"%(j,col))
col(a):
0 1
1 4
Name: a, dtype: int64
col(b):
0 2
1 5
Name: b, dtype: int64
col(c):
0 3
1 6
Name: c, dtype: int64
複製程式碼
3. 表連線
pandas提供了類似於sql的join
、merge
、concat
方法進行表連線。
(1). 索引連線
df1=pd.DataFrame([[1,2],[3,4]],columns=['col1','col2'],index=[1,0])
df2=pd.DataFrame([[5,6],[7,8]],columns=['col3','col4'],index=[0,1])
df1.join(df2,how='inner')
Out[229]:
col1 col2 col3 col4
1 1 2 7 8
0 3 4 5 6
複製程式碼
join
方法根據索引進行表連線,how
引數指定連線方式,有inner
內連線、outer
外連線、left
左連線、right
右連線 這幾種,預設為left
。
此處的join
和sql中的join並不一樣。
(2). 鍵連線
df1=pd.DataFrame({'col1':[1,2,3],'col2':[4,5,6]})
df2=pd.DataFrame({'col2':[4,5,7],'col3':[1,2,2]})
df1.merge(df2)
Out[235]:
col1 col2 col3
0 1 4 1
1 2 5 2
df1.merge(df2,how='left',left_on='col1',right_on='col3')
Out[237]:
col1 col2_x col2_y col3
0 1 4 4.0 1.0
1 2 5 5.0 2.0
2 2 5 7.0 2.0
3 3 6 NaN NaN
複製程式碼
merge
方法根據指定鍵(列)進行表連線,通過on
引數(相同鍵)或left_on
和right_on
引數(不同鍵)指定,預設會將兩表中都存在的鍵作為連線鍵;how
引數指定連線方式,有inner
內連線、outer
外連線、left
左連線、right
右連線 這幾種,預設為inner
。
該方法才是sql中join的等效方法。
(3). 拼接
df1=pd.DataFrame({'col1':[1,2,3],'col2':[4,5,6]})
df2=pd.DataFrame({'col2':[4,5,7],'col3':[1,2,2]})
pd.concat([df1,df2])
Out[241]:
col1 col2 col3
0 1.0 4 NaN
1 2.0 5 NaN
2 3.0 6 NaN
0 NaN 4 1.0
1 NaN 5 2.0
2 NaN 7 2.0
pd.concat([df1,df2],join='inner')
Out[242]:
col2
0 4
1 5
2 6
0 4
1 5
2 7
pd.concat([df1,df2],axis=1)
Out[243]:
col1 col2 col2 col3
0 1 4 4 1
1 2 5 5 2
2 3 6 7 2
複製程式碼
用於拼接表,等效於sql中的union all。
axis
引數指定用於拼接的軸,預設0;join
引數指定其他軸的處理方式,inner
表示只返回都存在的項,outer
表示全部返回,預設outer
。
拼接後的結果表中可能會有行索引或列索引上的重複,可以視需要重整索引。
五. 增刪改
1. 更新
df=pd.DataFrame({'a':[1,2],'b':[3,4]})
df.iloc[0,0]=0
df[df>2]+=1
df
Out[262]:
a b
0 0 4
1 2 5
df['a']=[2,1]
df
Out[266]:
a b
0 2 4
1 1 5
df[:]=[1,2]
df
Out[269]:
a b
0 1 2
1 1 2
複製程式碼
更新資料的方式與numpy一樣,索引篩選資料後直接賦值就行了,可以對所有元素賦值同一個標量,也可賦值同樣形狀的資料集,或是對DataFrame
每行賦值同樣的資料序列。
2. 增加
df=pd.DataFrame({'a':[1,2],'b':[3,4]})
df['c']=[5,6]
df
Out[248]:
a b c
0 1 3 5
1 2 4 6
df.loc[2]=-1
df
Out[253]:
a b c
0 1 3 5
1 2 4 6
2 -1 -1 -1
df.insert(0,'new',[0,0,0])
df
Out[255]:
new a b c
0 0 1 3 5
1 0 2 4 6
2 0 -1 -1 -1
複製程式碼
藉助索引器可直接為新行或是新列賦值。
insert
方法可以在指定位置插入新列,loc
引數指定位置索引,column
引數指定列名,value
指定新列的資料。
3. 刪除
df=pd.DataFrame({'a':[1,2,3],'b':[4,5,6]})
df[df['a']>2]
Out[277]:
a b
2 3 6
df.drop([0,2])
Out[281]:
a b
1 2 5
df.drop('a',axis=1)
Out[282]:
b
0 4
1 5
2 6
複製程式碼
刪除資料最靈活的方法就是通過索引篩去不需要的資料。
也可通過drop
刪除指定索引標籤的資料,labels
指定要刪除的標籤,可以是標量或是列表,axis
引數指定查詢索引標籤的軸,預設為0。該方法是根據索引標籤而不是位置去刪除的,所以如果指定標籤存在重複,這些資料會一起被刪除。
若想留存被刪除的列(比如想將該列插入另一個位置),可使用pop
方法彈出列。
4. 變更索引
(1).設定索引
df=pd.DataFrame({'a':[1,2],'b':[3,4]})
df.set_index('a')
Out[46]:
b
a
1 3
2 4
df.set_index(keys=['a','b'],drop=False)
Out[47]:
a b
a b
1 3 1 3
2 4 2 4
複製程式碼
set_index
方法可以將指定列設定為索引:
第一個引數keys
指定列名;
第二個引數drop
設定是否要刪除被設定為索引的列,預設True
;
第三個引數append
設定是否追加到現有索引上,預設False
;
第四個引數replace
設定是否在當前物件上修改,預設False
。
(2).重置索引
在有些情況下,比如進行過一系列的表關聯和分組計算後,DataFrame
的索引會變得雜亂,這時候需要一個方法來快速重置索引。
df=pd.DataFrame([['a','c',1],['a','d',2],['b','d',3],['b','d',4]],
columns=['col1','col2','col3'])
r=df.groupby(['col1','col2']).sum()
r
Out[34]:
col3
col1 col2
a c 1
d 2
b d 7
r.reset_index(drop=True)
Out[37]:
col3
0 1
1 2
2 7
r.reset_index(level=1)
Out[38]:
col2 col3
col1
a c 1
a d 2
b d 7
複製程式碼
reset_index
方法可以將行索引重置,並將捨棄的索引資訊作為列插入DataFrame
:
第一個引數level
可以指定多級索引需要捨棄的級別,預設全部捨棄,索引會被還原為RangeIndex
;
第二個引數drop
可以設定是否丟棄被重置的索引資訊,該項設定為True後索引資訊不會被插入DataFrame
,預設False
;
第三個引數replace
設定是否在當前物件上修改,預設False
。
(3).重構索引
df=pd.DataFrame({'a':[1,2],'b':[3,4]})
df.reindex(columns=['a','b','c','d'],fill_value=0)
Out[256]:
a b c d
0 1 3 0 0
1 2 4 0 0
複製程式碼
reindex
方法用於重構索引,可以實現複雜的結構變更,包括行列的增加、刪除、移位:
第二個引數index
設定新的行索引;
第三個引數columns
設定新的列索引,已存在的索引會和資料一起被移至新的位置,不存在的將被建立;
第八個引數fill_value
可以指定新增行列的填充值。
(4).重新命名索引
df=pd.DataFrame([{'a':1,'b':2,'c':3},{'a':4,'b':5,'c':6}])
df
Out[52]:
a b c
0 1 2 3
1 4 5 6
df.rename({'a':'e','b':'f','c':'g'},axis=1)
Out[50]:
e f g
0 1 2 3
1 4 5 6
複製程式碼
rename
方法可以對現有索引標籤重新命名:
第一個引數mapper
用來指定對映關係,可以是dict或是function,輸入原名稱,輸出新名稱;
第四個引數axis
指定重新命名的軸,行索引對應0,列索引對應1,預設0;
第六個引數replace
設定是否在當前物件上修改,預設False
。
5. 行列轉置
df=pd.DataFrame({'a':[1,2],'b':[3,4]})
df
Out[134]:
a b
0 1 3
1 2 4
df.T
Out[135]:
0 1
a 1 2
b 3 4
複製程式碼
DataFrame.T
用於實現行列轉置,整個資料集將沿左上至右下的對角線翻轉。
Series
呼叫轉置方法是無效的,如果需要轉置,先呼叫to_frame
方法轉為DataFrame
。
6. 缺失值填充
df=pd.DataFrame({'a':[np.nan,1,3],'b':[2,np.nan,6]})
df
Out[96]:
a b
0 NaN 2.0
1 1.0 NaN
2 3.0 6.0
df.fillna(0)
Out[97]:
a b
0 0.0 2.0
1 1.0 0.0
2 3.0 6.0
df.fillna(df.mean())
Out[98]:
a b
0 2.0 2.0
1 1.0 4.0
2 3.0 6.0
df.dropna()
Out[120]:
a b
2 3.0 6.0
df[df.isna()]=0
df
Out[122]:
a b
0 0.0 2.0
1 1.0 0.0
2 3.0 6.0
複製程式碼
fillna
方法用於填充缺失值,第一個引數value
設定用於填充的值,可傳入標量,對所有列填充同樣的值,也可傳入字典或系列,對不同列填充不同的值;另一種用法是給第二個引數method
賦值,'ffill'
和'bfill'
分別表示用前一個和後一個有效值填充。
dropna
方法用於直接刪除帶卻缺失值的行或列:axis
引數指定刪除行(0)或列(1);how
引數指定刪除的條件,'all'
表示全部值為NaN時刪除,'any'
表示有一個為NaN時刪除;thresh
引數設定在出現幾個NaN時執行刪除。
isna
方法配合索引器也能對缺失值進行更新,可通過賦值標量對所有列填充同樣的值,或是賦值序列對不同列填充不同的值。
六. 排序與去重
1. 直接與間接排序
df=pd.DataFrame([[2,'a'],[1,'c'],[3,'b']],columns=['col1','col2'],index=[3,2,1])
df
Out[6]:
col1 col2
3 2 a
2 1 c
1 3 b
df.sort_index()
Out[7]:
col1 col2
1 3 b
2 1 c
3 2 a
df.sort_values('col1')
Out[8]:
col1 col2
2 1 c
3 2 a
1 3 b
df.loc[df['col2'].sort_values().index]
Out[21]:
col1 col2
3 2 a
1 3 b
2 1 c
複製程式碼
sort_index
方法可以按索引排序,axis
引數指定排序的軸,預設0,level
引數指定用於排序的多級索引的級別,預設None,ascending
引數指定是否升序,預設True。
sort_values
方法可以按指定鍵排序,by
引數指定用於排序的鍵,axis
引數指定排序的軸,預設0,ascending
引數指定是否升序,預設True。
間接排序可通過loc
方法傳入排序後的標籤索引實現,排序前兩個資料模型的索引必須一致;iloc
方法類似,需要傳入經過numpy的argsort
方法排序後的位置索引。
2. 去重
df=pd.DataFrame({'a':[1,2,2,2],'b':[3,3,4,4]})
df
Out[10]:
a b
0 1 3
1 2 3
2 2 4
3 2 4
df.duplicated()
Out[11]:
0 False
1 False
2 False
3 True
dtype: bool
df.drop_duplicates()
Out[12]:
a b
0 1 3
1 2 3
2 2 4
df.drop_duplicates('a',keep='last')
Out[14]:
a b
0 1 3
3 2 4
複製程式碼
duplicated
方法用於返回標識去重結果的一維布林陣列,保留的項為True。subset
引數指定參與去重的行或列標籤,預設使用所有列;keep
引數指定保留方式,'first'
表示保留第一項,'last'
表示保留最後一項,None
表示不保留。
drop_duplicates
方法用於返回去重結果。subset
和keep
引數的作用和duplicated
一樣。
七. 亂序和抽樣
1. 隨機排序
df=pd.DataFrame({'a':[1,2,3],'b':[4,5,6]})
df.iloc[np.random.permutation(df.shape[0])]
Out[25]:
a b
1 2 5
0 1 4
2 3 6
df.sample(frac=1.)
Out[27]:
a b
0 1 4
2 3 6
1 2 5
複製程式碼
隨機排序,用於打亂資料集。一種方法是通過numpy生成亂序索引,然後應用在pandas的iloc
索引方法上;另一種方法是使用pandas的抽樣方法sample
,設定抽樣比例frac
引數為1.,採用預設的不放回抽樣的方式,也可以達到同樣的效果。
2. 抽樣
df.sample(n=2)
Out[34]:
a b
1 2 5
2 3 6
df.sample(frac=0.8,replace=True)
Out[36]:
a b
1 2 5
1 2 5
複製程式碼
sample
方法用於抽樣,第一個引數n
設定抽樣數量,第二個引數frac
設定抽樣比例,第三個引數replace
設定是否放回,預設False
,第四個引數weight
可設定樣本權重,第五個引數random_state
設定隨機數種子。
八. 讀寫
1. 讀寫csv
df=pd.DataFrame({'a':[1,2],'b':[3,4]},index=['r1','r2'])
df.to_csv()
Out[14]: ',a,b\nr1,1,3\nr2,2,4\n'
df.to_csv(index=False)
Out[15]: 'a,b\n1,3\n2,4\n'
df.to_csv("d:\\test.csv",index=False)
df2=pd.read_csv("d:\\test.csv")
df2
Out[18]:
a b
0 1 3
1 2 4
複製程式碼
to_csv
方法用於寫入csv檔案:
引數path_or_buf
設定檔案路徑或物件,預設為None
,表示直接返回完整的內容字串;
引數sep
設定分隔符,長度為1的字串,預設為','
;
引數na_rep
設定缺失值填充,預設''
;
引數float_format
設定浮點數的格式字串,如'%.2f'
表示保留兩位小數;
引數columns
設定要寫的列,預設None
,表示全部;
引數header
設定是否寫入列名,預設True
,如果給出字串列表,則作為列別名;
引數index
設定是否寫入行索引標籤,預設True
;
引數index_label
設定行索引列的列名,預設None
,會直接使用索引的名稱,不寫入列名需要設定為False
;
引數encoding
設定編碼格式,python3預設utf-8
;
引數chunksize
設定每次批量寫入的塊大小,預設一次寫入全部資料。
read_csv
方法用於讀取csv檔案:
引數filepath_or_buffer
設定檔案路徑或類檔案物件,必須賦值;
引數sep
設定分隔符,長度為1的字串,預設為','
;
引數header
設定作為列名的行號,可傳入列表,會讀取為多級索引,預設是第一行作為列名,當通過names
顯示傳遞列名時,該設定無效,另外,該引數會跳過註釋行和空行;
引數names
設定列名列表,預設為None
,如果檔案不含列名,header
也應設定為None
,該引數不能有重複項,會報錯;
引數index_col
設定作為行標籤的列號,可傳入列表,會讀取為多級索引,預設不設定;
引數usecols
設定要讀取的列列表,可以是列位置(int)或是列名(str)的列表,也可以傳入對列名進行邏輯判斷的函式,結果為True
的列將被返回;
引數prefix
設定預設列名字首,在沒有設定列名時會將該字首組合列號作為列名;
引數dtype
設定資料型別,dict
型別,鍵為列名,值為numpy資料型別,預設None
;
引數skiprows
設定開頭要跳過的行數,需要傳入int
,也可以設定要跳過的行號,傳入list of int
或對行號進行邏輯判斷的函式;
引數skipfooter
設定尾部要跳過的行數,需要傳入int
;
引數nrows
設定要讀取的行數,用於分批讀取大檔案;
引數na_filter
設定是否檢測缺失值,預設True
,在確定沒有缺失值的情況下可以關閉以提升讀取效能;
引數skip_blank_lines
設定是否跳過空行,預設True
;
引數encoding
設定編碼格式,python3預設utf-8
;
引數error_bad_lines
設定列數異常的壞行是否報錯,預設True
,False
時會直接剔除壞行;
引數chunksize
設定分塊的大小,如果設定,會按該大小分塊讀取並以迭代器返回。
2. 讀寫excel
df=pd.DataFrame({'a':[1,2],'b':[3,4]},index=['r1','r2'])
df.to_excel('d:\\test.xlsx',sheet_name='test1',index=False)
df2=pd.read_excel('d:\\test.xlsx',sheet_name=0)
df2
Out[9]:
a b
0 1 3
1 2 4
複製程式碼
to_excel
方法用於寫入xls或xlsx檔案:
引數excel_writer
設定檔案路徑或ExcelWriter,必須賦值;
引數sheet_name
設定要讀取的工作表名稱,預設'Sheet1'
;
引數na_rep
設定缺失值填充,預設''
;
引數float_format
設定浮點數的格式字串,如'%.2f'
表示保留兩位小數;
引數columns
設定要寫入的列,為列名的序列;
引數header
設定是否寫入列名,預設True
,當輸入字串列表時會當作列的別名;
引數index
設定是否寫入行索引標籤,預設True
;
引數index_label
設定行索引列的列名,當存在多級索引時應當輸入字串列表,預設None
,會直接使用索引的名稱;
引數startrow
設定寫入的起始行,預設0
;
引數startcol
設定寫入的起始列,預設0
;
引數merge_cells
設定單元格是否合併,預設True
。
read_excel
方法用於讀取xls或xlsx檔案:
引數io
設定檔案路徑或Excel檔案物件,必須賦值;
引數sheet_name
設定要讀取的工作表,可以傳入序號(int)或工作表名(str)或是包含前兩種的列表,傳入None
表示全部,預設0
;
引數header
設定解析為列名的行號,傳入行號的列表時會解析為多級索引,如果沒有列名,需要設定為None
;
引數names
設定列名,與header
配合使用,預設None
;
引數index_col
設定解析為行標籤的列號,傳入列號的列表時會解析為多級索引,預設None
;
引數usecols
設定需要返回的列,可傳入列號的列表list of int
、列名的列表list of str
、用逗號分隔的列名序列(例如 'A,B,C')或用冒號標識的列名範圍(例如 'A:E')str
,也可傳入對列名進行邏輯判斷的函式,結果為True
的列將被返回;
引數dtype
設定資料型別,dict
型別,鍵為列名,值為numpy資料型別,預設None
;
引數skiprows
設定開頭要跳過的行數,需要傳入int
,也可以設定要跳過的行號,傳入list of int
或對行號進行邏輯判斷的函式;
引數skipfooter
設定尾部要跳過的行數,需要傳入int
。
當sheetname不明確,需要獲取全部sheetname時,可用以下方法
excel=pd.ExcelFile(file_path)
excel.sheetname
複製程式碼
3. 讀寫sql
import sqlalchemy as sqla
username='sa'
password='123456'
server='127.0.0.1'
database='Test'
charset='utf8'
engine = sqla.create_engine('mssql+pymssql://{}:{}@{}/{}?charset={}'.format(username,password,server,database,charset))
df=pd.DataFrame({'a':[1,2],'b':[3,4]},index=['r1','r2'])
df.to_sql('test1',engine,if_exists='append',index=False)
df.to_sql('test1',engine,if_exists='append',index=False)
df2=pd.read_sql('select * from test1',engine)
df2
Out[28]:
a b
0 1.0 3.0
1 2.0 4.0
2 1.0 3.0
3 2.0 4.0
複製程式碼
to_sql
方法用於寫入資料庫:
引數name
設定要寫入的表名,str
型別;
引數conn
設定資料庫連線,sqlalchemy.engine.Engine
型別,需要配合sqlalchemy庫使用,通過create_engine
方法建立,連線字串格式形如'{資料庫型別}+{驅動名}://{使用者名稱}:{密碼}@{伺服器地址}:{埠號}/{資料庫名}?charset={字符集}'
;
引數if_exists
設定表存在時的處理方式,'fail'
表示丟擲異常,'replace'
表示替換現有表,'append'
表示作為新資料插入現有表,預設'fail'
;
引數index
設定行索引標籤是否作為一列寫入,預設True
;
引數index_label
設定行索引標籤列的列名,當存在多級索引時應當輸入字串列表,預設None
,會直接使用索引的名稱;
引數chunksize
設定每次批量寫入的塊大小,預設一次寫入全部資料;
引數dtype
設定寫入的資料型別,dict
型別,鍵為列名,值為sqlalchemy資料型別。
read_sql
方法用於讀取資料庫:
引數sql
設定要執行的sql查詢或表名;
引數conn
設定資料庫連線,sqlalchemy.engine.Engine
型別;
引數index_col
設定作為行標籤索引的列名,傳入列名的列表時會生成多級索引;
引數coerce_float
設定是否嘗試將一些非字串非數字物件(如decimal.Decimal)的值轉換為浮點數,預設True
;
引數params
設定傳遞給執行sql的引數列表,具體格式由使用的驅動決定;
引數parse_dates
設定要解析為時間的列名列表,預設None
;
引數columns
設定要讀取的列,僅在sql
引數傳入表名時有效,預設None
讀取全部列;
引數chunksize
設定分塊的大小,如果設定,會按該大小分塊讀取並以迭代器返回。
九. 快速繪圖
準備好pandas資料物件就可以呼叫方法直接繪圖,pandas提供的快速繪圖只適用於單次繪圖,不便於構建複雜的圖表,如有需要,使用matplotlib的方法建立影像和子圖。
1. 曲線圖
df=pd.DataFrame({'a':[1,1.5,2.5,4],'b':[3,2.1,3.2,1],'c':[1,2,3,4]})
fig=plt.figure(figsize=(12,4))
ax1=fig.add_subplot(1,2,1)
df.plot.line(ax=ax1)
ax2=fig.add_subplot(1,2,2)
df.plot.line(x='c',y=['a','b'],ax=ax2)
#plt.show()
Out[53]: <matplotlib.axes._subplots.AxesSubplot at 0x2aefe00ddd8>
複製程式碼
引數x
設定作為x軸資料的列名(只能一個),引數y
設定作為y軸資料的列名/列名列表,引數ax
設定子圖物件,預設None
單獨繪製。
plt.figure
用於建立影像,figsize
用於設定影像大小,tuple型別,格式為(weight,height)
;
Figure.add_subplot
用於建立子圖,第一個引數設定縱向分割槽個數,第二個引數設定橫向分割槽個數,第三個引數設定是第幾個子圖,是按分割槽先橫後縱排列的;
plt.plot
用於顯示繪製好的影像,在當前場景下可以省略,ipython呼叫完pandas的繪圖方法後會直接顯示。
繪製曲線圖也可以使用plot(kind='line')
,引數kind
也可以省略,因為預設值就是'line'
。
2. 條形圖
df=pd.DataFrame({'a':[1,1.5,2.5,4],'b':[3,2.1,3.2,1],'c':[1,2,3,4]})
fig=plt.figure(figsize=(12,4))
ax1=fig.add_subplot(1,2,1)
df.plot.bar(ax=ax1)
ax2=fig.add_subplot(1,2,2)
df.plot.bar(stacked=True,ax=ax2)
Out[147]: <matplotlib.axes._subplots.AxesSubplot at 0x2aeff4f17b8>
複製程式碼
引數stacked
設定條形圖是否堆疊。
水平條形圖需要改用DataFrame.plot.barh
方法。
3. 直方圖
df=pd.DataFrame({'a':[1,2,2,3],'b':[3,3,3,4],'c':[1,2,3,4]})
fig=plt.figure(figsize=(12,4))
ax1=fig.add_subplot(1,2,1)
df.plot.hist(alpha=0.5,ax=ax1)
ax2=fig.add_subplot(1,2,2)
df.plot.hist(stacked=True,bins=4,ax=ax2)
Out[210]: <matplotlib.axes._subplots.AxesSubplot at 0x2aefff32080>
複製程式碼
引數alpha
設定透明度,引數stacked
設定是否堆疊,引數bins
設定分箱數。
配合diff
可以繪製按列拆分為子圖的直方圖:
df.diff().hist(bins=4)
Out[165]:
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x000002AE805A4748>,
<matplotlib.axes._subplots.AxesSubplot object at 0x000002AE805E3D68>],
[<matplotlib.axes._subplots.AxesSubplot object at 0x000002AE80615390>,
<matplotlib.axes._subplots.AxesSubplot object at 0x000002AE8063DA20>]],
dtype=object)
複製程式碼
4. 箱線圖
df = pd.DataFrame(np.random.rand(10, 4),columns=['A','B','C','D'])
df.plot.box()
Out[167]: <matplotlib.axes._subplots.AxesSubplot at 0x2aeff644080>
複製程式碼
5. 散點圖
df=pd.DataFrame(np.random.rand(50,3),columns=['a','b','c'])
fig=plt.figure(figsize=(12,4))
ax1=fig.add_subplot(1,2,1)
df.plot.scatter(x='a',y='b',s=df['c']*200,ax=ax1)
ax2=fig.add_subplot(1,2,2)
df[df['c']>=0.5].plot.scatter(x='a',y='b',color='b',label='c1',ax=ax2)
df[df['c']<0.5].plot.scatter(x='a',y='b',color='g',label='c2',ax=ax2)
Out[186]: <matplotlib.axes._subplots.AxesSubplot at 0x2ae81a82e48>
複製程式碼
引數x
設定作為x軸資料的列名(只能一個),引數y
設定作為y軸資料的列名(只能一個),引數s
設定點的大小,引數color
設定點的顏色,引數label
設定標籤,需要為每個類別繪製不同顏色的點時,篩選出每個類別的資料分別繪製到同一個子圖上,並指定顏色和標籤。
6. 餅圖
df=pd.DataFrame(2*np.random.rand(3,2),index=['a','b','c'],columns=['p1','p2'])
df.plot.pie(y='p1',figsize=(4,4))
Out[204]: <matplotlib.axes._subplots.AxesSubplot at 0x2ae81f66cf8>
複製程式碼
df.plot.pie(subplots=True,figsize=(8.5,4))
Out[206]:
array([<matplotlib.axes._subplots.AxesSubplot object at 0x000002AE8171BEB8>,
<matplotlib.axes._subplots.AxesSubplot object at 0x000002AEFFFD78D0>],
dtype=object)
複製程式碼
有兩種繪製方式,一是引數y
指定一個列作為取值繪製餅圖,二是設定引數subplots
為True
,會用每個列的資料繪製子圖。
figsize
是繪圖的通用引數,用於設定影像大小。
十. 特殊型別處理
1. 字串處理
(1). 運算子
df=pd.DataFrame([['a','head',1],['b','Body',2],['c','FOOT',3]],
columns=['col1','col2','col3'])
df['col1']+df['col2']
Out[54]:
0 ahead
1 bBody
2 cFOOT
dtype: object
df['col1']*df['col3']
Out[55]:
0 a
1 bb
2 ccc
dtype: object
複製程式碼
字串型別支援兩種運算子操作:拼接(str + str)和重複(str * int)
(2). 字串方法
Series.str
下封裝了用於字串處理的方法,python中str類的大部分方法都被繼承了。
下面演示一些常用的方法:
索引器
df['col2'].str[:2]
Out[60]:
0 he
1 Bo
2 FO
Name: col2, dtype: object
複製程式碼
字串長度
df['col2'].str.len()
Out[73]:
0 4
1 4
2 4
Name: col2, dtype: int64
複製程式碼
大小寫轉換
#轉大寫
#isupper方法判斷是否大寫
df['col2'].str.upper()
Out[56]:
0 HEAD
1 BODY
2 FOOT
Name: col2, dtype: object
#轉小寫
#islower方法判斷是否大寫
df['col2'].str.lower()
Out[57]:
0 head
1 body
2 foot
Name: col2, dtype: object
#首字母大寫
df['col2'].str.capitalize()
Out[58]:
0 Head
1 Body
2 Foot
Name: col2, dtype: object
#大小寫互轉
df['col2'].str.swapcase()
Out[59]:
0 HEAD
1 bODY
2 foot
Name: col2, dtype: object
複製程式碼
填充
#填充至width長度
#side可設定'left'/'right'/'both'
df['col2'].str.pad(width=10, side='right', fillchar='-')
Out[63]:
0 head------
1 Body------
2 FOOT------
Name: col2, dtype: object
#居中填充
#等效於pad(side='both')
df['col2'].str.center(width=11, fillchar='*')
Out[66]:
0 ****head***
1 ****Body***
2 ****FOOT***
Name: col2, dtype: object
複製程式碼
拼接
#將一列字串拼接成一個字串
#sep設定分隔符
df['col2'].str.cat(sep=',')
Out[67]: 'head,Body,FOOT'
#將兩列字串拼接成一列字串
#na_rep設定空值填充
df['col2'].str.cat(['d','e',np.nan],sep=',',na_rep='?')
Out[68]:
0 head,d
1 Body,e
2 FOOT,?
Name: col2, dtype: object
#將兩列字串拼接成一列字串
#join設定連線方式
ss=pd.Series(['d','e','f'],index=[0,3,5])
df['col2'].str.cat(ss,sep=',',na_rep='?',join='left')
Out[69]:
0 head,d
1 Body,?
2 FOOT,?
Name: col2, dtype: object
#將每個元素上的字串列表拼接
ss=pd.Series([['a','b'],['c','d']])
ss.str.join(',')
Out[72]:
0 a,b
1 c,d
dtype: object
複製程式碼
拆分
#拆分字串並以列表作為元素返回
#pat分隔符預設為' ',可設定正規表示式用於分割
ss=pd.Series(['a,b,c','d,e'])
ss.str.split(pat=',')
Out[74]:
0 [a, b, c]
1 [d, e]
dtype: object
#n限制分割的次數,expand設定是否將拆分後的字串展開至列
ss.str.split(pat=',',n=1,expand=True)
Out[76]:
0 1
0 a b,c
1 d e
複製程式碼
查詢與替換
#是否包含
#pat可設定一般字串或正規表示式
df['col2'].str.contains('a')
Out[89]:
0 True
1 False
2 False
Name: col2, dtype: bool
#正則匹配
#pat只能設定正規表示式
#另有startswith,endswith方法可用於匹配開頭和結尾
#另有extract,extractall方法可用於抽取匹配的組
df['col2'].str.match('[a-z]*')
Out[90]:
0 True
1 True
2 True
Name: col2, dtype: bool
#查詢匹配並返回索引
#另有findall方法可查詢全部匹配並以列表元素返回
#另有index方法可通過start,end設定查詢範圍
df['col2'].str.find('d')
Out[91]:
0 3
1 2
2 -1
Name: col2, dtype: int64
#統計指定模式出現次數
df['col2'].str.count('O')
Out[92]:
0 0
1 0
2 2
Name: col2, dtype: int64
#替換
#第一個引數pat設定匹配模式,第二個引數repl設定用於替換的字串
#引數n設定替換次數
#另有translate方法用於批量對映字元
df['col2'].str.replace('d','e')
Out[93]:
0 heae
1 Boey
2 FOOT
Name: col2, dtype: object
複製程式碼
刪除首尾字元
#另有lstrip,rstrip方法分別用於刪除首和尾的字元
df['col2'].str.strip('d')
Out[96]:
0 hea
1 Body
2 FOOT
Name: col2, dtype: object
#可設定正規表示式
df['col2'].str.strip('[FT]')
Out[98]:
0 head
1 Body
2 OO
Name: col2, dtype: object
複製程式碼
2. 時間處理
(1). 時間型別
pd.Timestamp('2017-01-01 20:30:00',freq='D')
Out[80]: Timestamp('2017-01-01 20:30:00', freq='D')
pd.Period('2017-01-01 20:30')
Out[81]: Period('2017-01-01 20:30', 'T')
pd.Timedelta('2 days 1 hours')
Out[82]: Timedelta('2 days 01:00:00')
pd.Timedelta(1,unit='Y')
Out[83]: Timedelta('365 days 05:49:12')
from datetime import datetime
pd.Timestamp(datetime.now())
Out[84]: Timestamp('2019-05-18 16:14:26.691659')
複製程式碼
pandas有兩種時間型別:Timestamp
和Period
,Timestamp
的dtype
為datetime64
,Period
的dtype
為object
。Timestamp
建立時可以不指定時間頻率freq
引數,但會導致無法參與運算;Period
則會根據輸入的值自動設定freq
。可轉換datetime庫的時間型別。
Timedelta
是時間變化量型別,第一個引數value
指定變化量,輸入型別為int
時需要配合第二個引數unit
(單位)使用,和時間型別中的freq
是一個意思,預設'ns'
;也可輸入字串型別,對應所有的擴充命名引數(days, seconds, microseconds,milliseconds, minutes, hours, weeks),可通過引數指定,或是以字串形式宣告。
支援的freq
取值有(按從大到小排列):‘Y’, ‘M’, ‘W’, ‘D’, ‘days’, ‘day’, ‘hours’, hour’, ‘hr’, ‘h’, ‘m’, ‘minute’, ‘min’, ‘minutes’, ‘T’, ‘S’, ‘seconds’, ‘sec’, ‘second’, ‘ms’, ‘milliseconds’, ‘millisecond’, ‘milli’, ‘millis’, ‘L’, ‘us’, ‘microseconds’, ‘microsecond’, ‘micro’, ‘micros’, ‘U’, ‘ns’, ‘nanoseconds’, ‘nano’, ‘nanos’, ‘nanosecond’, ‘N’。
(2). 時間範圍
生成
#時間範圍
tr=pd.date_range(start='2017-01-01',periods=5,freq='2H')
tr
Out[7]:
DatetimeIndex(['2017-01-01 00:00:00', '2017-01-01 02:00:00',
'2017-01-01 04:00:00', '2017-01-01 06:00:00',
'2017-01-01 08:00:00'],
dtype='datetime64[ns]', freq='2H')
#另一種時間範圍
pr=pd.period_range(start='2017-01-01',periods=5,freq='D')
pr
Out[9]:
PeriodIndex(['2017-01-01', '2017-01-02', '2017-01-03', '2017-01-04',
'2017-01-05'],
dtype='period[D]', freq='D')
#時間差範圍
tdr=pd.timedelta_range(start='1 day', end='2 days', freq='6H')
tdr
Out[11]:
TimedeltaIndex(['1 days 00:00:00', '1 days 06:00:00', '1 days 12:00:00',
'1 days 18:00:00', '2 days 00:00:00'],
dtype='timedelta64[ns]', freq='6H')
#時間間隔範圍
ir=pd.interval_range(start=pd.Timestamp('2017-01-01'),periods=3, freq='MS')
ir
Out[31]:
IntervalIndex([(2017-01-01, 2017-02-01], (2017-02-01, 2017-03-01], (2017-03-01, 2017-04-01]]
closed='right',
dtype='interval[datetime64[ns]]')
複製程式碼
pd.date_range
和pd.period_range
用於時間範圍的生成,pd.timedelta_range
用於時間變化量範圍的生成,pd.interval_range
用於時間間隔範圍的生成。
以上方法有幾個相同功能的引數:
start
引數指定範圍的開始;end
引數指定範圍的結束;
periods
引數指定生成的週期數(即數量);freq
引數指定生成的頻率(即間隔);
name
引數指定生成的索引名稱;closed
引數指定區間閉合方式,支援的取值有'left'
、'right'
、 None
(即兩邊都閉合),預設None
。
start
、end
、periods
、freq
這四個引數至少指定其中三個。
這些方法生成的都是索引型別,可通過.to_series()
或.to_frame()
轉換為Seris
或DataFrame
。
變更
tr=pd.date_range(start='2017-01-01',periods=5,freq='2H')
#移動範圍
tr.shift(-1,freq='D')
Out[172]:
DatetimeIndex(['2016-12-31 00:00:00', '2016-12-31 02:00:00',
'2016-12-31 04:00:00', '2016-12-31 06:00:00',
'2016-12-31 08:00:00'],
dtype='datetime64[ns]', freq='2H')
ts=pd.Series(np.arange(len(tr)),index=tr)
#按指定頻率重取樣
ts.asfreq(freq='4H')
Out[175]:
2017-01-01 00:00:00 0
2017-01-01 04:00:00 2
2017-01-01 08:00:00 4
Freq: 4H, dtype: int32
複製程式碼
shift
方法用於時間範圍的移動,第一個引數n
指定移動量,第二個引數freq
指定頻率。
asfreq
方法用於按指定頻率重取樣,只能用於使用時間索引的Series
或DataFrame
,第一個引數freq
指定頻率,第二個引數method
指定填充NaN
的方式,當新取樣頻率不能被舊頻率整除時,會出現值為NaN
的無效取樣,可選'ffill'
(前一個有效值)和'bfill'
(後一個有效值),預設None
(不填充)。
(3). 獲取時間部分
時間型別
t=pd.Timestamp('2017-01-02 20:30:40.50')
t.date()
Out[101]: datetime.date(2017, 1, 2)
t.year
Out[102]: 2017
t.month
Out[103]: 1
t.day
Out[104]: 2
t.time()
Out[105]: datetime.time(20, 30, 40, 500000)
t.hour
Out[106]: 20
t.minute
Out[107]: 30
t.second
Out[108]: 40
t.microsecond
Out[109]: 500000
t.quarter
Out[110]: 1
t.weekday()
Out[118]: 0
t.day_name()
Out[119]: 'Monday'
t.week
Out[120]: 1
複製程式碼
時間型別的Series
可呼叫.dt
下的同名屬性,date
、time
、weekday
方法都變為以屬性形式訪問,day_name
方法可通過weekday_name
屬性訪問。
時間變化量型別
td=pd.Timedelta(weeks=0,days=1,hours=2,minutes=3,seconds=4,
milliseconds=5,microseconds=6)
td.days
Out[141]: 1
td.seconds
Out[142]: 7384
td.microseconds
Out[143]: 5006
td.total_seconds()
Out[145]: 93784.005006
複製程式碼
Timedelta
的total_seconds
方法獲取總秒數;days
、seconds
、microseconds
獲取各個部分,只分這三個,years
、months
、hours
、minutes
等是沒有的。
時間變化量型別的Series
可呼叫.dt
下的同名屬性或方法。
(4). 型別轉換
其他型別轉時間
from datetime import datetime
t=pd.Timestamp(datetime.now())
p=pd.Period(t,freq='D')
複製程式碼
建立單個時間型別時可以直接傳入支援轉換的型別完成轉換。
Period
必須指定freq
。
ss=pd.Series(['2017-01-01','2017-01-02'])
ss.astype('datetime64')
Out[183]:
0 2017-01-01
1 2017-01-02
dtype: datetime64[ns]
pd.to_datetime(ss)
Out[184]:
0 2017-01-01
1 2017-01-02
dtype: datetime64[ns]
複製程式碼
Series
和DataFrame
的astype
方法指定型別datetime64
可以轉換型別為時間,靜態pd.to_datetime
可以完成等效轉換。
Series
和DataFrame
的to_period
和to_timestamp
方法是作用於索引而不是資料的,呼叫的是索引的同名方法,其中DatetimeIndex
和PeriodIndex
是可通過這兩個方法相互轉換的。
時間轉字串
tr=pd.date_range(start='2017-01-01',periods=5,freq='D')
tr.strftime('%Y-%m-%d,%a')
Out[231]:
Index(['2017-01-01,Sun', '2017-01-02,Mon', '2017-01-03,Tue', '2017-01-04,Wed',
'2017-01-05,Thu'],
dtype='object')
複製程式碼
Series
型別可通過.dt
下的同名方法呼叫轉換方法。
支援的轉換格式定義如下:
%y
年(兩位)
%Y
年(四位)
%m
月
%d
日
%H
時(24小時制)
%I
時(12小時制)
%M
分
%S
秒
%j
年內第幾天
%p
上午或下午,AM或PM
%U
年內第幾周,週日為一週的開始
%w
周,週日為一週的開始
%W
年內第幾周,週一為一週的開始
%
%Y-%m-%d %H:%M:%S
的簡寫形式
%F
%Y-%m-%d
的簡寫形式
%D
%m/%d/%y
的簡寫形式
%a
本地的周簡稱
%A
本地的周名稱
%b
本地的月簡稱
%B
本地的月名稱
%c
本地的日期表示和時間表示
%x
本地的日期表示
%X
本地的時間表示
%Z
當前時區的名稱
%%
%號本身
(5). 時間運算
#標量值時間
pd.Period('2017-01-01 20:30:00',freq='D')+1
Out[253]: Period('2017-01-02', 'D')
ss1=pd.Series(['2017-01-01','2017-02-02'])
ss1=ss1.astype('datetime64')
ss2=pd.Series(['2017-01-05','2017-02-04'])
ss2=ss2.astype('datetime64')
#時間-時間
ss2-ss1
Out[255]:
0 4 days
1 2 days
dtype: timedelta64[ns]
#獲取時間變化量的屬性
(ss2-ss1).dt.days
Out[256]:
0 4
1 2
dtype: int64
#時間變化量縮放
(ss2-ss1)*2
Out[257]:
0 8 days
1 4 days
dtype: timedelta64[ns]
#時間+時間變化量
ss1+pd.Timedelta(days=1)
Out[258]:
0 2017-01-02
1 2017-02-03
dtype: datetime64[ns]
複製程式碼
支援以下幾種運算:
時間 - 時間 = 時間變化量
時間變化量 + 時間變化量 = 時間變化量
時間變化量 * 整數 = 時間變化量
時間 + 時間變化量 = 時間
(時間:period
或datetime
,時間變化量:timedelta
,整數:int
)
標量值的Timestamp
和Period
在設定了freq
的情況下可以直接加減整數。