1. 程式人生 > >python資料分析系列教程——Pandas全解

python資料分析系列教程——Pandas全解

起步

Pandas最初被作為金融資料分析工具而開發出來,因此 pandas 為時間序列分析提供了很好的支援。 Pandas 的名稱來自於面板資料(panel data)和python資料分析 (data analysis) 。panel data是經濟學中關於多維資料集的一個術語,在Pandas中也提供了panel的資料型別。

在我看來,對於 Numpy 以及 Matplotlib ,Pandas可以幫助建立一個非常牢固的用於資料探勘與分析的基礎。而Scipy當然是另一個主要的也十分出色的科學計算庫。本文使用python3.6來編寫程式碼。

安裝與匯入

通過pip進行安裝: pip install pandas

匯入:

import pandas as pd  

Pandas的資料型別

Pandas基於兩種資料型別: series 與 dataframe 。

Series

一個series是一個一維的資料型別,其中每一個元素都有一個標籤。類似於Numpy中元素帶標籤的陣列。其中,標籤可以是數字或者字串。

import numpy as np  
import pandas as pd  

s = pd.Series([1, 2, 5, np.nan, 6, 8])  
print(s)  

輸出:

0    1.0  
1    2.0  
2    5.0  
3    NaN
4 6.0 5 8.0 dtype: float64

DataFrame

一個dataframe是一個二維的表結構。Pandas的dataframe可以儲存許多種不同的資料型別,並且每一個座標軸都有自己的標籤。你可以把它想象成一個series的字典項。

建立一個 DateFrame:

#建立日期索引序列  
dates =pd.date_range('20130101', periods=6)  
print(type(dates))  
#建立Dataframe,其中 index 決定索引序列,columns 決定列名  
df =pd.DataFrame(np.random.randn(6
,4), index=dates, columns=list('ABCD')) print(df)

輸出:

<class 'pandas.core.indexes.datetimes.DatetimeIndex'>  
                   A         B         C         D  
2013-01-01  0.406575 -1.356139  0.188997 -1.308049  
2013-01-02 -0.412154  0.123879  0.907458  0.201024  
2013-01-03  0.576566 -1.875753  1.967512 -1.044405  
2013-01-04  1.116106 -0.796381  0.432589  0.764339  
2013-01-05 -1.851676  0.378964 -0.282481  0.296629  
2013-01-06 -1.051984  0.960433 -1.313190 -0.093666  

字典建立 DataFrame

df2 =pd.DataFrame({'A' : 1.,  
   'B': pd.Timestamp('20130102'),  
   'C': pd.Series(1,index=list(range(4)),dtype='float32'),  
   'D': np.array([3]*4,dtype='int32'),  
   'E': pd.Categorical(["test","train","test","train"]),  
   'F':'foo' })  

print(df2)  

輸出:

     A          B    C  D      E    F  
0  1.0 2013-01-02  1.0  3   test  foo  
1  1.0 2013-01-02  1.0  3  train  foo  
2  1.0 2013-01-02  1.0  3   test  foo  
3  1.0 2013-01-02  1.0  3  train  foo  

將檔案資料匯入Pandas

df =pd.read_csv("Average_Daily_Traffic_Counts.csv", header=0)
df.head()

資料來源可以是 英國政府資料 或 美國政府資料 來獲取資料來源。當然, Kaggle 是另一個好用的資料來源。

選擇/切片

df[‘column_name’] ,df[row_start_index, row_end_index] 選取指定整列資料

df['name']   # 選取一列,成一個series   
df[['name']]  # 選取一列,成為一個dataframe     
df[['name','gender']] #選取多列,多列名字要放在list裡    
df[0:]  #第0行及之後的行,相當於df的全部資料,注意冒號是必須的    
df[:2]  #第2行之前的資料(不含第2行)    
df[0:1] #第0行    
df[1:3] #第1行到第2行(不含第3行)    
df[-1:] #最後一行    
df[-3:-1] #倒數第3行到倒數第1行(不包含最後1行即倒數第1行,這裡有點煩躁,因為從前數時從第0行開始,從後數就是-1行開始,畢竟沒有-0

loc,在知道列名字的情況下,df.loc[index,column] 選取指定行,列的資料

# df.loc[index, column_name],選取指定行和列的資料    
df.loc[0,'name'] # 'Snow'    
df.loc[0:2, ['name','age']]          #選取第0行到第2行,name列和age列的資料, 注意這裡的行選取是包含下標的。    
df.loc[[2,3],['name','age']]         #選取指定的第2行和第3行,name和age列的資料    
df.loc[df['gender']=='M','name']     #選取gender列是M,name列的資料    
df.loc[df['gender']=='M',['name','age']] #選取gender列是M,name和age列的資料    

iloc,在column name特別長或者index是時間序列等各種不方便輸入的情況下,可以用iloc (i = index), iloc完全用數字來定位 iloc[row_index, column_index]

df.iloc[0,0]        #第0行第0列的資料,'Snow'    
df.iloc[1,2]        #第1行第2列的資料,32    
df.iloc[[1,3],0:2]  #第1行和第3行,從第0列到第2列(不包含第2列)的資料    
df.iloc[1:3,[1,2]   #第1行到第3行(不包含第3行),第1列和第2列的資料  

索引彙總

# 選擇單獨的一列,返回 Serires,與 df.A 效果相當。
df['A']

# 位置切片
df[0:3]

# 索引切片
df['20130102':'20130104']

# 通過標籤選擇
df.loc[dates[0]]

# 對多個軸同時通過標籤進行選擇
df.loc[:,['A','B']]

# 獲得某一個單元的資料
df.loc[dates[0],'A']
# 或者
df.at[dates[0],'A']# 速度更快的做法

# 通過位置進行選擇
df.iloc[3]

# 切片
df.iloc[3:5,0:2]

# 列表選擇
df.iloc[[1,2,4],[0,2]]

# 獲得某一個單元的資料
df.iloc[1,1]
# 或者
df.iat[1,1]# 更快的做法

# 布林索引
df[df.A > 0]

# 獲得大於零的項的數值
df[df > 0]

# isin 過濾
df2[df2['E'].isin(['two','four'])]

賦值

# 新增一列,根據索引排列
s1 =pd.Series([1,2,3,4,5,6], index=pd.date_range('20130102', periods=6))
df['F']=s1

# 預設項
# 在 pandas 中使用 np.nan 作為預設項的值。
df1 =df.reindex(index=dates[0:4], columns=list(df.columns)+['E'])
df1.loc[dates[0]:dates[1],'E']=1

# 刪除所有帶有預設項的行
df1.dropna(how='any')

# 填充預設項
df1.fillna(value=5)

# 獲得預設項的布林掩碼
pd.isnull(df1)

算數運算

兩個dataframe 矩陣相加、相減、相乘、相除,會對兩個矩陣行索引(包括行索引名稱和行索引值)和列索引相同的兩個對應元素做運算。

觀察操作

# 觀察開頭的資料
df.head()

# 觀察末尾的資料
df.tail(3)

# 顯示索引
df.index

# 顯示列
df.columns

# 顯示底層 numpy 結構
df.values

# DataFrame 的基本統計學屬性預覽
df.describe()
"""
  A  B  C  D
count 6.000000 6.000000 6.000000 6.000000 #數量
mean 0.073711 -0.431125 -0.687758 -0.233103 #平均值
std 0.843157 0.922818 0.779887 0.973118 #標準差
min -0.861849 -2.104569 -1.509059 -1.135632 #最小值
25% -0.611510 -0.600794 -1.368714 -1.076610 #正態分佈 25%
50% 0.022070 -0.228039 -0.767252 -0.386188 #正態分佈 50%
75% 0.658444 0.041933 -0.034326 0.461706 #正態分佈 75%
max 1.212112 0.567020 0.276232 1.071804 #最大值
"""

# 轉置
df.T

# 根據某一軸的索引進行排序
df.sort_index(axis=1, ascending=False)

# 根據某一列的數值進行排序
df.sort(columns='B')

統計

count                      非NA值的數量
describe                  針對Series或各DataFrame列計算彙總統計
min,max                 計算最小值和最大值
argmin,argmax        計算能夠獲取到最小值和最大值的索引位置(整數)
idxmin,idxmax         計算能夠獲取到最小值和最大值的索引值
quantile                   計算樣本的分位數(01sum                        值的總和
mean                      值的平均數, a.mean() 預設對每一列的資料求平均值;若加上引數a.mean(1)則對每一行求平均值
media                      值的算術中位數(50%分位數)
mad                         根據平均值計算平均絕對離差
var                          樣本值的方差 
std                        樣本值的標準差
skew                     樣本值的偏度(三階矩)
kurt                       樣本值的峰度(四階矩)
cumsum                 樣本值的累計和
cummin,cummax    樣本值的累計最大值和累計最小
cumprod                樣本值的累計積
diff                        計算一階差分(對時間序列很有用) 
pct_change            計算百分數變化
# 求平均值
df.mean()
"""
A -0.004474
B -0.383981
C -0.687758
D 5.000000
F 3.000000
dtype: float64
"""

# 指定軸上的平均值
df.mean(1)

# 不同維度的 pandas 物件也可以做運算,它會自動進行對應,shift 用來做對齊操作。
s = pd.Series([1,3,5,np.nan,6,8], index=dates).shift(2)
"""
2013-01-01NaN
2013-01-02NaN
2013-01-031
2013-01-043
2013-01-055
2013-01-06NaN
Freq: D, dtype: float64
"""

# 對不同維度的 pandas 物件進行減法操作
df.sub(s, axis='index')
"""
   A B C D F
2013-01-01NaN NaN NaN NaN NaN
2013-01-02NaN NaN NaN NaN NaN
2013-01-03-1.861849-3.104569-1.49492941
2013-01-04-2.278445-3.706771-4.03957520
2013-01-05-5.424972-4.432980-4.7237680-1
2013-01-06NaN NaN NaN NaN NaN
"""

函式應用

# 累加
df.apply(np.cumsum)

直方圖

s =pd.Series(np.random.randint(0,7, size=10))
s.value_counts()
"""
4 5
6 2
2 2
1 1
dtype: int64
String Methods
"""

字元處理

s =pd.Series(['A','B','C','Aaba','Baca', np.nan,'CABA','dog','cat'])
s.str.lower()
"""
0 a
1 b
2 c
3 aaba
4 baca
5 NaN
6 caba
7 dog
8 cat
dtype: object
"""

合併

使用 concat() 連線 pandas 物件:

df =pd.DataFrame(np.random.randn(10,4))
"""
  0  1  2  3
0 -0.548702 1.467327 -1.015962 -0.483075
1 1.637550 -1.217659 -0.291519 -1.745505
2 -0.263952 0.991460 -0.919069 0.266046
3 -0.709661 1.669052 1.037882 -1.705775
4 -0.919854 -0.042379 1.247642 -0.009920
5 0.290213 0.495767 0.362949 1.548106
6 -1.131345 -0.089329 0.337863 -0.945867
7 -0.932132 1.956030 0.017587 -0.016692
8 -0.575247 0.254161 -1.143704 0.215897
9 1.193555 -0.077118 -0.408530 -0.862495
"""

pieces =[df[:3], df[3:7], df[7:]]
pd.concat(pieces)
"""
  0  1  2  3
0 -0.548702 1.467327 -1.015962 -0.483075
1 1.637550 -1.217659 -0.291519 -1.745505
2 -0.263952 0.991460 -0.919069 0.266046
3 -0.709661 1.669052 1.037882 -1.705775
4 -0.919854 -0.042379 1.247642 -0.009920
5 0.290213 0.495767 0.362949 1.548106
6 -1.131345 -0.089329 0.337863 -0.945867
7 -0.932132 1.956030 0.017587 -0.016692
8 -0.575247 0.254161 -1.143704 0.215897
9 1.193555 -0.077118 -0.408530 -0.862495
"""

join 合併:

left =pd.DataFrame({'key': ['foo','foo'],'lval': [1,2]})
right =pd.DataFrame({'key': ['foo','foo'],'rval': [4,5]})
pd.merge(left, right, on='key')
"""
 key lval rval
0 foo 1 4
1 foo 1 5
2 foo 2 4
3 foo 2 5
"""

追加

在 dataframe 資料後追加行

df =pd.DataFrame(np.random.randn(8,4), columns=['A','B','C','D'])
s =df.iloc[3]
df.append(s, ignore_index=True)

分組

分組常常意味著可能包含以下的幾種的操作中一個或多個

依據一些標準分離資料
對組單獨地應用函式
將結果合併到一個數據結構中

df =pd.DataFrame({'A': ['foo','bar','foo','bar','foo','bar','foo','foo'],  
                  'B': ['one','one','two','three','two','two','one','three'],  
                  'C': np.random.randn(8),  
                  'D': np.random.randn(8)})  
print('源資料集:\n',df)  

df1 = df.groupby('A').sum()  
print('A分組:\n',df1)  

df2 = df.groupby(['A','B']).sum()  
print('AB分組:\n',df2)  

輸出結果

源資料集:  
      A      B         C         D  
0  foo    one  0.423062 -0.813870  
1  bar    one -1.058636 -0.943536  
2  foo    two -0.843569 -0.611338  
3  bar  three  0.933234 -1.425916  
4  foo    two -1.145840  0.643593  
5  bar    two  1.057359 -1.049414  
6  foo    one -0.387183  1.056451  
7  foo  three  1.923139 -1.184541  
A分組:  
             C         D  
A                        
bar  0.931957 -3.418865  
foo -0.030391 -0.909705  
AB分組:  
                   C         D  
A   B                          
bar one   -1.058636 -0.943536  
    three  0.933234 -1.425916  
    two    1.057359 -1.049414  
foo one    0.035879  0.242581  
    three  1.923139 -1.184541  
    two   -1.989409  0.032255  

分組時,組內運算
代表運算的字串包括‘sum’、‘mean’、‘min’、‘max’、‘count’

pd3 = pd3.groupby('a').agg('sum').reset_index()  

或者自定義函式

# # 或自定義函式不需要引數,則x是serise,如果x有自定引數,則x為DataFrame  
def funname(x,name):  
    print(name)  
    print(type(x),'\n',x)  
    return 2  

pd3 = pd3.groupby('a').agg(funname,'aaa').reset_index()  

資料透視表

df =pd.DataFrame({'A': ['one','one','two','three']*3,
   'B': ['A','B','C']*4,
   'C': ['foo','foo','foo','bar','bar','bar']*2,
   'D': np.random.randn(12),
   'E': np.random.randn(12)})

# 生成資料透視表
pd.pivot_table(df, values='D', index=['A','B'], columns=['C'])
"""
C  bar foo
A B  
one A -0.773723 1.418757
 B -0.029716 -1.879024
 C -1.146178 0.314665
three A 1.006160 NaN
 B NaN -1.035018
 C 0.648740 NaN
two A NaN 0.100900
 B -1.170653 NaN
 C NaN 0.536826
"""

時間序列

pandas 擁有既簡單又強大的頻率變換重新取樣功能,下面的例子從 1次/秒 轉換到了 1次/5分鐘:

rng =pd.date_range('1/1/2012', periods=100, freq='S')
ts =pd.Series(np.random.randint(0,500,len(rng)), index=rng)
ts.resample('5Min', how='sum')
"""
2012-01-01 25083
Freq: 5T, dtype: int32
"""

# 本地化時區表示
rng =pd.date_range('3/6/2012 00:00', periods=5, freq='D')
ts =pd.Series(np.random.randn(len(rng)), rng)
"""
2012-03-06 0.464000
2012-03-07 0.227371
2012-03-08 -0.496922
2012-03-09 0.306389
2012-03-10 -2.290613
Freq: D, dtype: float64
"""

ts_utc =ts.tz_localize('UTC')
"""
2012-03-06 00:00:00+00:00 0.464000
2012-03-07 00:00:00+00:00 0.227371
2012-03-08 00:00:00+00:00 -0.496922
2012-03-09 00:00:00+00:00 0.306389
2012-03-10 00:00:00+00:00 -2.290613
Freq: D, dtype: float64
"""

# 轉換為週期
ps =ts.to_period()

# 轉換為時間戳
ps.to_timestamp()

分類

df =pd.DataFrame({"id":[1,2,3,4,5,6],"raw_grade":['a','b','b','a','a','e']})

# 將 raw_grades 轉換成 Categoricals 型別
df["grade"]=df["raw_grade"].astype("category")
df["grade"]
"""
0 a
1 b
2 b
3 a
4 a
5 e
Name: grade, dtype: category
Categories (3, object): [a, b, e]
"""

# 重新命名分類
df["grade"]=df["grade"].cat.set_categories(["very bad","bad","medium","good","very good"])

# 根據分類的順序對資料進行排序
df.sort("grade")
"""
 id raw_grade  grade
5 6   e very bad
1 2   b  good
2 3   b  good
0 1   a very good
3 4   a very good
4 5   a very good
"""

作圖

ts =pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))
ts =ts.cumsum()
ts.plot()

資料IO

# 從 csv 檔案讀取資料
pd.read_csv('foo.csv')

# 儲存到 csv 檔案
df.to_csv('foo.csv')

# 讀取 excel 檔案
pd.read_excel('foo.xlsx','Sheet1', index_col=None, na_values=['NA'])

# 儲存到 excel 檔案
df.to_excel('foo.xlsx', sheet_name='Sheet1')

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家學習或者使用python能帶來一定的幫助,如果有疑問大家可以留言交流。