[python][科學計算][pandas]使用指南

jiedawang發表於2019-04-20

最後一次更新日期: 2019/4/20

pandas是基於numpy的資料分析庫,提供一些更易用的資料模型和大量高效的統計方法。

使用前先匯入模組:

import pandas as pd

按需匯入以下模組:

import numpy as np

import matplotlib.pyplot as plt

點選下方連結可前往各小節

簡要使用教程1 - 資料模型與屬性 (索引,資料序列,資料框,分類資料)

簡要使用教程2 - 資料型別與轉換 (資料型別,型別轉換)

簡要使用教程3 - 陣列與統計運算 (運算子和標量值函式,統計方法,自定義函式,廣播)

簡要使用教程4 - 查詢與關聯 (索引查詢,表連線)

簡要使用教程5 - 增刪改 (更新,增加,刪除,重構索引,行列轉置,缺失值填充)

簡要使用教程6 - 排序與去重 (直接與間接排序,去重)

簡要使用教程7 - 亂序與抽樣 (隨機排序,抽樣)

簡要使用教程8 - 讀寫 (讀寫csv,讀寫excel,讀寫sql)

簡要使用教程9 - 快速繪圖 (曲線圖,條形圖,直方圖,箱線圖,散點圖,餅圖)

一. 資料模型與屬性

返回目錄

1. 索引Index

numpy中只有位置索引,而pandas還增加了標籤索引,依賴於一個專用的Index型別。

常規索引

In [64]: pd.Index([1,2,3])
Out[64]: Int64Index([1, 2, 3], dtype='int64')

In [65]: pd.Index([1.,2.,3.])
Out[65]: Float64Index([1.0, 2.0, 3.0], dtype='float64')

In [66]: pd.Index(['a','b','c'])
Out[66]: Index(['a', 'b', 'c'], dtype='object')

In [67]: pd.Index(range(10))
Out[67]: RangeIndex(start=0, stop=10, step=1)

In [68]: pd.Index(range(10)).values
Out[68]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int64)

In [80]: import datetime as dt
    ...: dt1=dt.datetime.now()
    ...: dt2=dt1+dt.timedelta(days=1)

In [81]: 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計算也會自動產生多級索引。

In [5]: midx=pd.MultiIndex(levels=[['a','b'],['c','d']],labels=[[1,1,0,0],[0,1,0,1]],name=['idx1','idx2'])

In [6]: midx
Out[6]: 
MultiIndex(levels=[['a', 'b'], ['c', 'd']],
           labels=[[1, 1, 0, 0], [0, 1, 0, 1]],
           names=['idx1', 'idx2'])

In [9]: 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'])

In [11]: midx.swaplevel(0,1)
Out[11]: 
MultiIndex(levels=[['c', 'd'], ['a', 'b']],
           labels=[[0, 1, 0, 1], [1, 1, 0, 0]],
           names=['idx2', 'idx1'])

In [12]: 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_levelsset_labelsset_names可以設定整體或是某一級別的索引屬性,通過level引數指定級別,預設設定整體; swaplevel可以交換級別,droplevel可以刪除級別,sortlevel可以對指定級別排序; from_arrayfrom_tuplesfrom_productfrom_frame方法可從其他結構的資料中建立索引。

2. 資料序列Series

In [99]: s=pd.Series([1,2,3,4],name='s1')

In [100]: s
Out[100]: 
0    1
1    2
2    3
3    4
Name: s1, dtype: int64

In [101]: pd.Series([[1,2],[3,4]],index=['row1','row2'])
Out[101]: 
row1    [1, 2]
row2    [3, 4]
dtype: object

In [102]: s.dtype
Out[102]: dtype('int64')

In [103]: s.name
Out[103]: 's1'

In [104]: s.values
Out[104]: array([1, 2, 3, 4], dtype=int64)

In [105]: s.index
Out[105]: RangeIndex(start=0, stop=4, step=1)

In [106]: s.shape
Out[106]: (4,)
複製程式碼

核心資料模型其一,由序列名name、標籤索引index、值陣列(一維)values組成。用於存放一維資料,只有一個軸方向:0,shape屬性可以檢視資料集的形狀。

建立時只能接收一維序列資料(list,tuple,ndarray),超過一維的將後面的維度看作元素的維度,會根據傳入的資料自動判斷型別,也可通過dtype引數顯示指定。

預設情況下會生成範圍索引,可通過index引數指定一個一維序列作為索引,也可在建立後直接為index屬性賦值。

3. 資料框DataFrame

In [107]: df=pd.DataFrame([[1,'a'],[2,'b']],columns=['col1','col2'])

In [108]: df
Out[108]: 
   col1 col2
0     1    a
1     2    b

In [113]: df.dtypes
Out[113]: 
col1     int64
col2    object
dtype: object

In [114]: df.index
Out[114]: Int64Index([1, 2], dtype='int64', name='col1')

In [116]: df.columns
Out[116]: Index(['col1', 'col2'], dtype='object')

In [117]: df.values
Out[117]: 
array([[1, 'a'],
       [2, 'b']], dtype=object)

In [125]: df.col2
Out[125]: 
col1
1    a
2    b
Name: col2, dtype: object

In [126]: pd.DataFrame({'col1':[1,3],'col2':['a','b']})
Out[126]: 
   col1 col2
0     1    a
1     3    b

In [127]: 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提供了分類資料型別用於約束此類資料,該型別會限制分類標籤的取值,並可為分類標籤提供排序依據。

In[14]: pd.Categorical(['a','b','b','c'],categories=['a','b'],ordered=True)
Out[14]: 
[a, b, b, NaN]
Categories (2, object): [a < b]

In[15]: 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. 型別轉換

In [48]: df=pd.DataFrame([[1,'2'],[3,'a']],columns=['col1','col2'])

In [49]: df.dtypes
Out[49]: 
col1     int64
col2    object
dtype: object

In [50]: df.col1.astype('float')
Out[50]: 
0    1.0
1    3.0
Name: col1, dtype: float64

In [52]: pd.to_numeric(df.col2,errors='ignore')
Out[52]: 
0    2
1    a
Name: col2, dtype: object

In [53]: 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的標量值函式也可直接使用,這些運算都是將原本作用於單個元素的運算擴充到整個陣列。

In [56]: df=pd.DataFrame([[1,'2'],[3,'a']],columns=['col1','col2'])

In [57]: df+df
Out[57]: 
   col1 col2
0     2   22
1     6   aa

In [201]: np.sqrt(df.col1)
Out[201]: 
0    1.000000
1    1.732051
Name: col1, dtype: float64
複製程式碼

使用的運算子和函式必須對參與運算的所有資料型別都是有意義的,否則會報錯。

匹配方式

In [154]: s1=pd.Series([1,2,3,4],index=[0,1,2,3])

In [155]: s2=pd.Series([5,6,7,8],index=[1,2,3,4])

In [156]: s1+s2
Out[156]: 
0     NaN
1     7.0
2     9.0
3    11.0
4     NaN
dtype: float64
複製程式碼

此處需要注意pandas和numpy的區別,pandas的陣列運算在元素匹配上是基於標籤索引的,未能匹配到的位置會被替換為NaN,numpy則是基於位置索引。

2. 統計方法

聚合函式

pandas繼承了numpy的聚合函式:summeanmaxmin等。 可通過SeriesDataFrame的方法呼叫,或是呼叫numpy下的靜態方法。

In [58]: df.sum()
Out[58]: 
col1     4
col2    2a
dtype: object

In [60]: np.max(df)
Out[60]: 
col1    3
col2    a
dtype: object

In [114]: df.agg({'col1':'max','col2':'sum'})
Out[114]: 
col1     3
col2    2a
dtype: object

In [115]: 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方法用於分組統計。

In [88]: 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

In [93]: result=df.groupby(by=['col1','col2']).agg(['max','min'])

In [94]: result
Out[94]: 
          col3    
           max min
col1 col2         
a    c       1   1
     d       2   2
b    d       3   3

In [95]: result.sum(level=0)
Out[95]: 
     col3    
      max min
col1         
a       3   3
b       3   3

In [140]: gb=df.groupby(by=['col1','col2'])

In [141]: gb.groups
Out[141]: 
{('a', 'c'): Int64Index([0], dtype='int64'),
 ('a', 'd'): Int64Index([1], dtype='int64'),
 ('b', 'd'): Int64Index([2], dtype='int64')}

In [142]: gb.get_group(('a','c'))
Out[142]: 
  col1 col2  col3
0    a    c     1
複製程式碼

只呼叫groupby方法會得到一個DataFrameGroupBy物件,通過其groups方法可檢視所有分組資訊,get_group方法可獲取指定分組。 該物件可呼叫各種聚合函式,或呼叫agg方法進行復合的聚合統計,返回包含多級索引的DataFrame統計結果表,對於結果表,可以繼續應用統計函式並通過level引數指定索引級別進行二次統計。

3. 應用自定義函式

除pandas和numpy提供的函式外,還可以自定義函式並使用applyapplymapmap方法快速應用於整個資料集。

In [119]: df.apply(lambda x: x.col1+x.col2, axis=1)
Out[119]: 
0    3
1    7
dtype: int64

In [120]: def add(row):
     ...:     return row.col1+row.col2

In [121]: df.apply(add, axis=1)
Out[121]: 
0    3
1    7
dtype: int64

In [122]: df.applymap(lambda x: x*2)
Out[122]: 
   col1  col2
0     2     4
1     6     8

In [123]: def double(item):
     ...:     return item*2

In [124]: df.applymap(double)
Out[124]: 
   col1  col2
0     2     4
1     6     8

In [128]: s=pd.Series(['a','b','b'])

In [129]: s.map(lambda x: x*2)
Out[129]: 
0    aa
1    bb
2    bb
dtype: object

In [130]: s.map({'a':'c','b':'d'})
Out[130]: 
0    c
1    d
2    d
dtype: object
複製程式碼

DataFrameapplyapplymap兩個方法: apply將函式應用於每行或者每列,axis引數指定應用函式的軸方向,值為0表示按列應用,即逐列作為函式的引數進行計算,值為1表示按行應用,預設為0; applymap將函式應用於每個元素。

Series只有一個map方法,用於將函式應用於元素,除此以外,還提供值對映的功能,輸入dict型別時會根據key-value對映將相應的值替換。

支援lambda匿名函式。

4. 廣播

In [80]: 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]])

In [99]: df22+l2
Out[99]: 
   0  1
0  2  4
1  4  6

In [100]: df22+a2
Out[100]: 
   0  1
0  2  4
1  4  6

In [101]: df22+s2
Out[101]: 
   0  1
0  2  4
1  4  6

In [102]: df22+df21
Out[102]: 
   0   1
0  2 NaN
1  5 NaN

In [103]: df22+df12
Out[103]: 
     0    1
0  2.0  4.0
1  NaN  NaN

In [104]: df23+s2
Out[104]: 
     0    1   2
0  4.0  6.0 NaN
1  7.0  9.0 NaN

In [130]: df21+df12
Out[130]: 
     0   1
0  2.0 NaN
1  NaN NaN
複製程式碼

pandas的廣播機制繼承自numpy但有不一樣的地方: 標量值會與DataFrameSeries中每個元素進行同樣的計算; Series或一維list或一維ndarray會與DataFrame的每一行進行運算,Series在長度不足以匹配DataFrame的行時不足部分會替換為NaN,其他兩種長度不足會報錯; DataFrameDataFrame進行運算會按元素匹配,無論行列,長度不足的部分都會替換為NaN; 二維ndarrayDataFrame的運算遵循numpy的廣播規則,長度不足且為1的軸會被廣播至同等大小; 二維listDataFrame的運算不被支援。

四. 查詢和關聯

返回目錄

1. 索引查詢

(1). 索引器格式

單值選取:[value,...] 多值選取:[[value1,value2],...] 範圍選取:[start:end:step,...]

start表示區間的開始,預設值0,end表示區間的結束(不包含),預設值等於軸長度,step表示選取的步長,預設值1,採用預設值的引數可以省略,[:,...]表示對應軸方向上全部選取。

pandas中索引器的格式與numpy差不多,但用法有區別。pandas除了numpy的位置索引,還增加了標籤索引,雖然可以對SeriesDataFrame直接使用索引器,但用法被嚴格限制,建議改用ilocloc方法進行索引。

(2). 直接索引

In [157]: df=pd.DataFrame(np.arange(1,10).reshape((3,3)),columns=['col1','col2','col3'],index=['row1','row2','row3'])

In [158]: df[0:3:2]
Out[158]: 
      col1  col2  col3
row1     1     2     3
row3     7     8     9

In [161]: df['row1':'row3':2]
Out[161]: 
      col1  col2  col3
row1     1     2     3
row3     7     8     9

In [162]: df['col2']
Out[162]: 
row1    2
row2    5
row3    8
Name: col2, dtype: int32

In [163]: df[['col1','col3']]
Out[163]: 
      col1  col3
row1     1     3
row2     4     6
row3     7     9

In [168]: df['col2'][1:3]
Out[168]: 
row2    5
row3    8
Name: col2, dtype: int32
複製程式碼

直接索引提供了有限的幾種使用方式:按行位置進行索引切片、按行標籤進行索引切片、按列標籤取列、按列標籤列表取多列、布林索引篩選行、索爾索引篩選元素等。 一次索引器只能使用一種方式,不能行列同時操作,如有需要,可進行連續索引。

(3). loc和iloc索引

In [169]: df.loc['row1','col1']
Out[169]: 1

In [170]: df.loc['row1':'row3':2,'col1':'col3':2]
Out[170]: 
      col1  col3
row1     1     3
row3     7     9

In [185]: df.iloc[0,0]
Out[185]: 1

In [186]: df.iloc[0:3:2,0:3:2]
Out[186]: 
      col1  col3
row1     1     3
row3     7     9
複製程式碼

loc專用於標籤索引,iloc專用於位置索引,索引器可接收單值、列表、範圍、布林索引,可同時索引行和列。

(4). 布林索引

In [190]: df>5
Out[190]: 
       col1   col2   col3
row1  False  False  False
row2  False  False   True
row3   True   True   True

In [191]: df[df>5]
Out[191]: 
      col1  col2  col3
row1   NaN   NaN   NaN
row2   NaN   NaN   6.0
row3   7.0   8.0   9.0

In [192]: df['col1']>2
Out[192]: 
row1    False
row2     True
row3     True
Name: col1, dtype: bool

In [193]: df.loc[df['col1']>2]
Out[193]: 
      col1  col2  col3
row2     4     5     6
row3     7     8     9

In [196]: df.loc[df['col1']>2,df.iloc[1]>5]
Out[196]: 
      col3
row2     6
row3     9

In [208]: df.iloc[df['col1'].values>2]
Out[208]: 
      col1  col2  col3
row2     4     5     6
row3     7     8     9
複製程式碼

布林索引是一種比較特殊的索引,通過對pandas或numpy的資料模型進行邏輯運算得到,與源資料結構相同,資料型別為bool,用於標識每個元素是否符合邏輯運算的條件。在索引器中使用布林索引可以篩選出符合條件的資料。

在直接索引時,二維布林索引可以用於篩選DataFrame的元素,形狀不變,不符合條件的元素會被替換為NaN,這一點和numpy不一樣,numpy進行同樣形式的篩選時會將符合條件的元素構造為新的一維陣列返回;一維布林索引只可以用於篩選行資料;

在使用loc索引時,不能使用二維布林索引,只能針對每個軸使用一維布林索引,並且必須是由Series運算得到的帶有標籤索引的布林索引; 在使用iloc索引時,同樣不能使用二維布林索引,只能針對每個軸使用一維布林索引,並且必須是由一維ndarray運算得到的不含標籤索引的布林索引(Series.values可得到對應的ndarray)。

(5). 指定值查詢

In [141]: df=pd.DataFrame({'a':[np.nan,1,2],'b':[3,np.nan,4]})

In [142]: df
Out[142]: 
     a    b
0  NaN  3.0
1  1.0  NaN
2  2.0  4.0

In [143]: df.isin([2,3])
Out[143]: 
       a      b
0  False   True
1  False  False
2   True  False

In [144]: df.isna()
Out[144]: 
       a      b
0   True  False
1  False   True
2  False  False
複製程式碼

isin方法用於查詢存在於指定列表中的值,isna方法用於查詢NaN值,兩方法都會返回布林索引,通常結合索引器使用。

2. 表連線

pandas提供了類似於sql的joinmergeconcat方法進行表連線。

(1). 索引連線

In [227]: df1=pd.DataFrame([[1,2],[3,4]],columns=['col1','col2'],index=[1,0])

In [228]: df2=pd.DataFrame([[5,6],[7,8]],columns=['col3','col4'],index=[0,1])

In [229]: 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). 鍵連線

In [233]: df1=pd.DataFrame({'col1':[1,2,3],'col2':[4,5,6]})

In [234]: df2=pd.DataFrame({'col2':[4,5,7],'col3':[1,2,2]})

In [235]: df1.merge(df2)
Out[235]: 
   col1  col2  col3
0     1     4     1
1     2     5     2

In [237]: 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_onright_on引數(不同鍵)指定,預設會將兩表中都存在的鍵作為連線鍵;how引數指定連線方式,有inner內連線、outer外連線、left左連線、right右連線 這幾種,預設為inner

該方法才是sql中join的等效方法。

(3). 拼接

In [239]: df1=pd.DataFrame({'col1':[1,2,3],'col2':[4,5,6]})

In [240]: df2=pd.DataFrame({'col2':[4,5,7],'col3':[1,2,2]})

In [241]: 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

In [242]: pd.concat([df1,df2],join='inner')
Out[242]: 
   col2
0     4
1     5
2     6
0     4
1     5
2     7

In [243]: 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. 更新

In [259]: df=pd.DataFrame({'a':[1,2],'b':[3,4]})

In [260]: df.iloc[0,0]=0

In [261]: df[df>2]+=1

In [262]: df
Out[262]: 
   a  b
0  0  4
1  2  5

In [265]: df['a']=[2,1]

In [266]: df
Out[266]: 
   a  b
0  2  4
1  1  5

In [268]: df[:]=[1,2]

In [269]: df
Out[269]: 
   a  b
0  1  2
1  1  2
複製程式碼

更新資料的方式與numpy一樣,索引篩選資料後直接賦值就行了,可以對所有元素賦值同一個標量,也可賦值同樣形狀的資料集,或是對DataFrame每行賦值同樣的資料序列。

2. 增加

In [246]: df=pd.DataFrame({'a':[1,2],'b':[3,4]})

In [247]: df['c']=[5,6]

In [248]: df
Out[248]: 
   a  b  c
0  1  3  5
1  2  4  6

In [252]: df.loc[2]=-1

In [253]: df
Out[253]: 
   a  b  c
0  1  3  5
1  2  4  6
2 -1 -1 -1

In [254]: df.insert(0,'new',[0,0,0])

In [255]: 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. 刪除

In [276]: df=pd.DataFrame({'a':[1,2,3],'b':[4,5,6]})

In [277]: df[df['a']>2]
Out[277]: 
   a  b
2  3  6

In [281]: df.drop([0,2])
Out[281]: 
   a  b
1  2  5

In [282]: df.drop('a',axis=1)
Out[282]: 
   b
0  4
1  5
2  6
複製程式碼

刪除資料最靈活的方法就是通過索引篩去不需要的資料。 也可通過drop刪除指定索引標籤的資料,labels指定要刪除的標籤,可以是標量或是列表,axis引數指定查詢索引標籤的軸,預設為0。該方法是根據索引標籤而不是位置去刪除的,所以如果指定標籤存在重複,這些資料會一起被刪除。

4. 重構索引

In [246]: df=pd.DataFrame({'a':[1,2],'b':[3,4]})

In [256]: 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引數可以指定新增行列的填充值。

5. 行列轉置

In [133]: df=pd.DataFrame({'a':[1,2],'b':[3,4]})

In [134]: df
Out[134]: 
   a  b
0  1  3
1  2  4

In [135]: df.T
Out[135]: 
   0  1
a  1  2
b  3  4
複製程式碼

DataFrame.T用於實現行列轉置,整個資料集將沿左上至右下的對角線翻轉。 Series呼叫轉置方法是無效的,如果需要轉置,先呼叫to_frame方法轉為DataFrame

6. 缺失值填充

In [95]: df=pd.DataFrame({'a':[np.nan,1,3],'b':[2,np.nan,6]})

In [96]: df
Out[96]: 
     a    b
0  NaN  2.0
1  1.0  NaN
2  3.0  6.0

In [97]: df.fillna(0)
Out[97]: 
     a    b
0  0.0  2.0
1  1.0  0.0
2  3.0  6.0

In [98]: df.fillna(df.mean())
Out[98]: 
     a    b
0  2.0  2.0
1  1.0  4.0
2  3.0  6.0

In [120]: df.dropna()
Out[120]: 
     a    b
2  3.0  6.0

In [121]: df[df.isna()]=0

In [122]: df
Out[122]: 
     a    b
0  0.0  2.0
1  1.0  0.0
2  3.0  6.0
複製程式碼

fillna方法用於直接填充缺失值,可傳入標量,對所有列填充同樣的值,也可傳入字典或系列,對不同列填充不同的值。

dropna方法用於直接刪除帶卻缺失值的行或列:axis引數指定刪除行(0)或列(1);how引數指定刪除的條件,'all'表示全部值為NaN時刪除,'any'表示有一個為NaN時刪除;thresh引數設定在出現幾個NaN時執行刪除。

isna方法配合索引器也能對缺失值進行更新,可通過賦值標量對所有列填充同樣的值,或是賦值序列對不同列填充不同的值。

六. 排序與去重

返回目錄

1. 直接與間接排序

In[5]: df=pd.DataFrame([[2,'a'],[1,'c'],[3,'b']],columns=['col1','col2'],index=[3,2,1])

In[6]: df
Out[6]: 
   col1 col2
3     2    a
2     1    c
1     3    b

In[7]: df.sort_index()
Out[7]: 
   col1 col2
1     3    b
2     1    c
3     2    a

In[8]: df.sort_values('col1')
Out[8]: 
   col1 col2
2     1    c
3     2    a
1     3    b

In [21]: 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. 去重

In[8]: df=pd.DataFrame({'a':[1,2,2,2],'b':[3,3,4,4]})

In[10]: df
Out[10]: 
   a  b
0  1  3
1  2  3
2  2  4
3  2  4

In[11]: df.duplicated()
Out[11]: 
0    False
1    False
2    False
3     True
dtype: bool

In[12]: df.drop_duplicates()
Out[12]: 
   a  b
0  1  3
1  2  3
2  2  4

In[14]: 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方法用於返回去重結果。subsetkeep引數的作用和duplicated一樣。

七. 亂序和抽樣

返回目錄

1. 隨機排序

In [24]: df=pd.DataFrame({'a':[1,2,3],'b':[4,5,6]})

In [25]: df.iloc[np.random.permutation(df.shape[0])]
Out[25]: 
   a  b
1  2  5
0  1  4
2  3  6

In [27]: 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. 抽樣

In [34]: df.sample(n=2)
Out[34]: 
   a  b
1  2  5
2  3  6

In [36]: 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

In [13]: df=pd.DataFrame({'a':[1,2],'b':[3,4]},index=['r1','r2'])

In [14]: df.to_csv()
Out[14]: ',a,b\nr1,1,3\nr2,2,4\n'

In [15]: df.to_csv(index=False)
Out[15]: 'a,b\n1,3\n2,4\n'

In [16]: df.to_csv("d:\\test.csv",index=False)

In [17]: df2=pd.read_csv("d:\\test.csv")

In [18]: 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設定列數異常的壞行是否報錯,預設TrueFalse時會直接剔除壞行; 引數chunksize設定分塊的大小,如果設定,會按該大小分塊讀取並以迭代器返回。

2. 讀寫excel

In [5]: df=pd.DataFrame({'a':[1,2],'b':[3,4]},index=['r1','r2'])

In [7]: df.to_excel('d:\\test.xlsx',sheet_name='test1',index=False)

In [8]: df2=pd.read_excel('d:\\test.xlsx',sheet_name=0)

In [9]: 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

3. 讀寫sql

In [21]: 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))

In [23]: df=pd.DataFrame({'a':[1,2],'b':[3,4]},index=['r1','r2'])

In [24]: df.to_sql('test1',engine,if_exists='append',index=False)

In [25]: df.to_sql('test1',engine,if_exists='append',index=False)


In [27]: df2=pd.read_sql('select * from test1',engine)

In [28]: 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. 曲線圖

In [30]: df=pd.DataFrame({'a':[1,1.5,2.5,4],'b':[3,2.1,3.2,1],'c':[1,2,3,4]})

In [53]: 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>
複製程式碼

[python][科學計算][pandas]使用指南

引數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. 條形圖

In [30]: df=pd.DataFrame({'a':[1,1.5,2.5,4],'b':[3,2.1,3.2,1],'c':[1,2,3,4]})

In [147]: 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>
複製程式碼

[python][科學計算][pandas]使用指南

引數stacked設定條形圖是否堆疊。 水平條形圖需要改用DataFrame.plot.barh方法。

3. 直方圖

In [205]: df=pd.DataFrame({'a':[1,2,2,3],'b':[3,3,3,4],'c':[1,2,3,4]})

In [210]: 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>
複製程式碼

[python][科學計算][pandas]使用指南

引數alpha設定透明度,引數stacked設定是否堆疊,引數bins設定分箱數。

配合diff可以繪製按列拆分為子圖的直方圖:

In [165]: 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)
複製程式碼

[python][科學計算][pandas]使用指南

4. 箱線圖

In [166]: df = pd.DataFrame(np.random.rand(10, 4),columns=['A','B','C','D'])

In [167]: df.plot.box()
Out[167]: <matplotlib.axes._subplots.AxesSubplot at 0x2aeff644080>
複製程式碼

[python][科學計算][pandas]使用指南

5. 散點圖

In[185]: df=pd.DataFrame(np.random.rand(50,3),columns=['a','b','c'])

In[186]: 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>
複製程式碼

[python][科學計算][pandas]使用指南
引數x設定作為x軸資料的列名(只能一個),引數y設定作為y軸資料的列名(只能一個),引數s設定點的大小,引數color設定點的顏色,引數label設定標籤,需要為每個類別繪製不同顏色的點時,篩選出每個類別的資料分別繪製到同一個子圖上,並指定顏色和標籤。

6. 餅圖

In [203]: df=pd.DataFrame(2*np.random.rand(3,2),index=['a','b','c'],columns=['p1','p2'])

In [204]: df.plot.pie(y='p1',figsize=(4,4))
Out[204]: <matplotlib.axes._subplots.AxesSubplot at 0x2ae81f66cf8>
複製程式碼

[python][科學計算][pandas]使用指南

In [206]: 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)
複製程式碼

[python][科學計算][pandas]使用指南

有兩種繪製方式,一是引數y指定一個列作為取值繪製餅圖,二是設定引數subplotsTrue,會用每個列的資料繪製子圖。 figsize是繪圖的通用引數,用於設定影像大小。

相關文章