利用Python進行資料分析
編輯推薦: |
來源csdn ,主要講解了GroupBy機制,groups中的迭代,Dicts與Series分組,應用函式進行分組,根據索引等級分組,資料聚合等結合案例詳細講解。 |
import numpy as np
import pandas as pd
GroupBy機制
上圖顯示了一個分組背後的具體操作,當操作一個數據集按照某個key進行分組時,資料集首先會按組進行分割,然後再對每一組應用函式,最後返回分組後的結果。
df=pd.DataFrame({ 'key1':['a','a','b','b','a'], 'key2':['one','two','one','two','one'], 'data1':np.random.randn(5), 'data2':np.random.randn(5) }) df.loc[:,'data1'].groupby(df.loc[:,'key1']).mean() #將data1列按照key1進行分組,再求均值
當需要按照多個key進行分組時,給groupby()傳遞一個列表即可,得到的結果是具有層級index的Series:
mean=df.loc[:,'data1'].groupby([df.loc[:,'key1'],df.loc[:,'key2']]).mean()
mean.unstack()
當對整個資料集進行分組時,可以直接給groupby()傳遞key的值,此時不可再用loc()與iloc()方法,因為groupby()生成的是一個groupby物件,而不是DataFrame:
另一個應用於groupby()之後的方法為size():
groups中的迭代
GroupBy物件是一個可迭代物件:
for key,data in df.groupby('key1'):
print(key)
print(data)
根據Dicts與Series分組
建立對映關係如dict或series,將列先進行對映再進行分組。
people=pd.DataFrame( np.random.randn(5,5), index=['Joe','Steve','Wes','Jim','Travis'], columns=['a','b','c','d','e'] ) people.iloc[2,[1,2]]=None mapping={ 'a':'red', 'b':'red', 'c':'blue', 'd':'blue', 'e':'red', 'f':'orange' } people.groupby(mapping,axis=1).mean()
map_series=pd.Series(mapping)
people.groupby(map_series,axis=1).mean()
應用函式進行分組
比如對上述資料集,如需要對名字長度進行分組,則可以給groupby()傳遞一個函式作為引數:
根據索引等級分組
對於帶層級索引的資料集,可以根據某一層級的索引名稱進行分組,指定引數level=即可:
hier_df=pd.DataFrame( np.random.randn(4,5), columns=[['US','US','US','JP','JP'], [1,3,5,1,3]] ) hier_df.columns.names=['city','tensor'] hier_df.groupby(level='city',axis=1).count()
資料聚合
tips=pd.read_csv('examples/tips.csv') tips.loc[:,'tip_pct']=tips.loc[:,'tip']/tips.loc[:,'total_bill'] tips.sample(3)
grouped=tips.groupby(['day','smoker'])
grouped['tip_pct'].mean()
可以對groupby物件的agg()方法傳遞一個函式名列表,會返回一個groupby物件應用函式後生成的DataFrame:
返回無行索引的聚合資料
使用引數as_index=引數來返回一個無行索引的資料:
可見行索引被轉換成了列值。
Apply
GroupBy()方法最普遍的目的就是在資料集上應用函式以篩選出想要的資料。比如使用者自己寫了一個top()函式,它會返回DataFrame指定列中值最大的n條記錄:
def top(df,n=5,column='tip_pct'):
return df.sort_values(by=column).iloc[-n:,:]
可以看到以’smoker’分組方法篩選出來的資料條目中還包含了由分組產生的’smoker’行索引,可以使用引數group_keys=來消除分組索引:
分位數與桶分析
frame=pd.DataFrame({ 'data1':np.random.randn(1000), 'data2':np.random.randn(1000) }) quartiles= pd.cut(frame.loc[:,'data1'],4) #以data1生成四個區間
def get_stats(group):
return {
'min':group.min(),
'max':group.max(),
'mean':group.mean()
}
grouped= frame.loc[:,'data2' ].groupby(quartiles) #以data1的區間來對data2進行分組
grouped.apply(get_stats).unstack()
示例
隨機取樣與改序
假設需要生成一組隨機取樣(有放回或無放回)來做蒙特卡洛分析,或者是用做機器學習專案中的資料子集,需要對原資料集進行隨機取樣或者改序。
#生成一副牌組Series suits=['H','S','C','D'] base_name=['A']+list(range(2,11))+['J','Q','K'] cards=[] for suit in suits: cards.extend(str(num)+suit for num in base_name) card_val=(list(range(1,14)))*4 deck=pd.Series(card_val,index=cards)
#抽牌函式
def draw(deck,n=5):
return deck.sample(n)
4H 4
6C 6
5C 5
AH 1
7C 7
dtype: int64
假設現在需要從每個花色中隨機抽出兩張牌,可以先按花色來對牌組進行分組再應用抽牌函式:
get_suit=lambda card:card[-1] #card的最後一位表示花色,這裡沒太懂
deck.groupby (get_suit,group_keys=False).apply (draw,n=2)
6C 6
10C 10
KD 13
QD 12
9H 9
JH 11
5S 5
6S 6
dtype: int64
分組的加權均值與相關係數
如果資料是帶權重的,使用apply()方法可以很方便的計算加權平均值:
frame=pd.DataFrame({ 'category':['a','a','b','b'], 'data':np.random.randn(4), 'weights':np.random.rand(4) }) frame
get_wavg=lambda grouped:np.average(grouped.loc[:,'data'],weights=grouped.loc[:,'weights'])
frame.groupby('category').apply(get_wavg)
在下一個例子前,先了解一下pct_change()方法:
obj=pd.Series(np.arange(1,5))
obj.pct_change()
接下來我們匯入一個真實資料集,進行相關性分析:
close_px=pd.read_csv ('examples/stock_px_2.csv', parse_dates=True,index_col=0)
close_px.info()
使用pct_change()來計算日回報率:
eturns=close_px.pct_change().dropna()
returns.head()
我們把資料按年進行聚合,再使用apply()方法顯示以SPX為參照的各公司收益相關性:
get_year=lambda timestamp:timestamp.year #此資料集的行索引為時間物件,無loc()方法
spx_cor=lambda x:x.corrwith(x.loc[:,'SPX'])
還可以得到指定兩家公司的年收益相關性:
AAPL_cor_MSFT=lambda x:x.loc[:,'AAPL'].corr(x.loc[:,'MSFT'])
returns.groupby(get_year).apply(AAPL_cor_MSFT)
2003 0.480868
2004 0.259024
2005 0.300093
2006 0.161735
2007 0.417738
2008 0.611901
2009 0.432738
2010 0.571946
2011 0.581987
dtype: float64
透視表與交叉表
pivot_table()方法與groupby()方法能得到相似的結果,不過pivot_table()方法能提供更強大的功能。
tips=pd.read_csv('examples/tips.csv')
tips.pivot_table(index=['day','smoker'])
以上結果同樣可以通過tips.groupby(['day','smoker'])得到。如果現在我們只想生成tip和size列的透視表,以time和day來分組:
交叉表
以兩個Series或list組成一個表