pandas基礎
流處理
流處理,聽起來很高大上啊,其實就是分塊讀取。有這麼一些情況,有一個很大的幾個G的檔案,沒辦法一次處理,那麼就分批次處理,一次處理1百萬行,接著處理下1百萬行,慢慢地總是能處理完的。
# 使用類似迭代器的方式data=pd.read_csv(file, chunksize=1000000)for sub_df in data: print('do something in sub_df here')
索引
Series和DataFrame都是有索引的,索引的好處是快速定位,在涉及到兩個Series或DataFrame時可以根據索引自動對齊,比如日期自動對齊,這樣可以省去很多事。 缺失值
pd.isnull(obj)obj.isnull()
將字典轉成資料框,並賦予列名,索引
DataFrame(data, columns=['col1','col2','col3'...], index = ['i1','i2','i3'...])
查看列名
DataFrame.columns 查看索引
DataFrame.index 重建索引
obj.reindex(['a','b','c','d','e'...], fill_value=0]#按給出的索引順序重新排序,而不是替換索引。如果索引沒有值,就用0填充#就地修改索引data.index=data.index.map(str.upper)
列順序重排(也是重建索引)
DataFrame.reindex[columns=['col1','col2','col3'...])`#也可以同時重建index和columnsDataFrame.reindex[index=['a','b','c'...],columns=['col1','col2','col3'...])
重建索引的快速鍵
DataFrame.ix[['a','b','c'...],['col1','col2','col3'...]]
重新命名軸索引
data.rename(index=str.title,columns=str.upper)#修改某個索引和列名,可以通過傳入字典data.rename(index={'old_index':'new_index'}, columns={'old_col':'new_col'})
查看某一列
DataFrame['state'] 或 DataFrame.state
查看某一行
需要用到索引
DataFrame.ix['index_name']
添加或刪除一列
DataFrame['new_col_name'] = 'char_or_number'#刪除行DataFrame.drop(['index1','index2'...])#刪除列DataFrame.drop(['col1','col2'...],axis=1)#或del DataFrame['col1']
DataFrame選擇子集
| 類型 |
說明 |
| obj[val] |
選擇一列或多列 |
| obj.ix[val] |
選擇一行或多行 |
| obj.ix[:,val] |
選擇一列或多列 |
| obj.ix[val1,val2] |
同時選擇行和列 |
| reindx |
對行和列重新索引 |
| icol,irow |
根據整數位置選取單列或單行 |
| get_value,set_value |
根據列標籤和欄標籤選擇單個值 |
針對series
obj[['a','b','c'...]]obj['b':'e']=5
針對dataframe
#選擇多列dataframe[['col1','col2'...]]#選擇多行dataframe[m:n]#條件式篩選dataframe[dataframe['col3'>5]]#選擇子集dataframe.ix[0:3,0:5]
dataframe和series的運算
會根據 index 和 columns 自動對齊然後進行運算,很方便啊
| 方法 |
說明 |
| add |
加法 |
| sub |
減法 |
| div |
除法 |
| mul |
乘法 |
#沒有資料的地方用0填充空值df1.add(df2,fill_value=0)# dataframe 與 series 的運算dataframe - series規則是:-------- -------- || | | | || | -------- || | || | v--------#指定軸方向dataframe.sub(series,axis=0)規則是:-------- --- | | | | ----->| | | | | | | | | | | | -------- ---
apply函數
f=lambda x:x.max()-x.min()#預設對每一列應用dataframe.apply(f)#如果需要對每一行分組應用dataframe.apply(f,axis=1)
排序和排名
#預設根據index排序,axis = 1 則根據columns排序dataframe.sort_index(axis=0, ascending=False)# 根據值排序dataframe.sort_index(by=['col1','col2'...])#排名,給出的是rank值series.rank(ascending=False)#如果出現重複值,則取平均秩次#在行或列上面的排名dataframe.rank(axis=0)
描述性統計
| 方法 |
說明 |
| count |
計數 |
| describe |
給出各列的常用統計量 |
| min,max |
最大最小值 |
| argmin,argmax |
最大最小值的索引位置(整數) |
| idxmin,idxmax |
最大最小值的索引值 |
| quantile |
計算樣本分位元 |
| sum,mean |
對列求和,均值 |
| mediam |
中位元 |
| mad |
根據平均值計算平均絕對離差 |
| var,std |
方差,標準差 |
| skew |
偏度(三階矩) |
| Kurt |
峰度(四階矩) |
| cumsum |
累積和 |
| Cummins,cummax |
累計組大致和累計最小值 |
| cumprod |
累計積 |
| diff |
一階差分 |
| pct_change |
計算百分數變化 |
唯一值,值計數,成員資格
obj.unique()obj.value_count()obj.isin(['b','c'])
處理缺失值
# 過濾缺失值# 只要有缺失值就丟棄這一行dataframe.dropna()#要求全部為缺失才丟棄這一行dataframe.dropna(how='all')# 根據列來判斷dataframe.dropna(how='all',axis=1)# 填充缺失值#1.用0填充df.fillna(0)#2.不同的列用不同的值填充df.fillna({1:0.5, 3:-1})#3.用均值填充df.fillna(df.mean())# 此時axis參數同前面,
將列轉成行索引
df.set_index(['col1','col2'...])
資料清洗,重塑
合并資料集
# 取 df1,df2 都有的部分,丟棄沒有的# 預設是inner的串連方式pd.merge(df1,df2, how='inner')#如果df1,df2的串連欄位名不同,則需要特別指定pd.merge(df1,df2,left_on='l_key',right_on='r_key')#其他的串連方式有 left,right, outer等。# 如果dataframe是多重索引,根據多個鍵進行合并pd.merge(left, right, on=['key1','key2'],how = 'outer')#合并後如果有重複的列名,需要添加尾碼pd.merge(left, right, on='key1', suffixes=('_left','_right'))
索引上的合并
#針對dataframe中的串連鍵不是列名,而是索引名的情況。pd.merge(left, right, left_on = 'col_key', right_index=True)#即左邊的key是列名,右邊的key是index。#多重索引pd.merge(left, right, left_on=['key1','key2'], right_index=True)
dataframe的join方法
#實現按索引合并。#其實這個join方法和資料庫的join函數是以一樣的理解left.join(right, how='outer')#一次合并多個資料框left.join([right1,right2],how='outer')
軸向串連(更常用)
串連:concatenation
綁定:binding
堆疊:stacking 列上的串連
np.concatenation([df1,df2],axis=1) #np包pd.concat([df1,df2], axis=1) #pd包#和R語言中的 cbind 是一樣的#如果axis=0,則和 rbind 是一樣的#索引對齊,沒有的就為空白# join='inner' 得到交集pd.concat([df1,df2], axis=1, join='innner')# keys 參數,還沒看明白# ignore_index=True,如果只是簡單的合并拼接而不考慮索引問題。pd.concat([df1,df2],ignore_index=True)
合并重複資料
針對可能有索引全部或者部分重疊的兩個資料集
填充因為合并時索引趙成的缺失值
where函數
#where即if-else函數np.where(isnull(a),b,a)
combine_first方法
#如果a中值為空白,就用b中的值填補a[:-2].combine_first(b[2:])#combine_first函數即對資料打補丁,用df2的資料填充df1中的缺失值df1.combine_first(df2)
重塑層次化索引
stact:將資料轉為長格式,即列旋轉為行
unstack:轉為寬格式,即將行旋轉為列
result=data.stack()result.unstack()
長格式轉為寬格式
pivoted = data.pivot('date','item','value')#前兩個參數分別是行和列的索引名,最後一個參數則是用來填充dataframe的資料列的列名。如果忽略最後一個參數,得到的dataframe會帶有層次化的列。
透視表
table = df.pivot_table(values=["Price","Quantity"], index=["Manager","Rep"], aggfunc=[np.sum,np.mean], margins=True))#values:需要對哪些欄位應用函數#index:透視表的行索引(row)#columns:透視表的列索引(column)#aggfunc:應用什麼函數#fill_value:空值填充#margins:添加匯總項#然後可以對透視表進行篩選table.query('Manager == ["Debra Henley"]')table.query('Status == ["pending","won"]')
移除重複資料
# 判斷是否重複data.duplicated()`#移除重複資料data.drop_duplicated()#對指定列判斷是否存在重複值,然後重複資料刪除資料data.drop_duplicated(['key1'])
交叉表
是一種用於計算分組頻率的特殊透視表.
注意,只對離散型的,分類型的,字元型的有用,連續型資料是不能計算頻率這種東西的。
pd.crosstab(df.col1, df.col2, margins=True)
類似vlookup函數
利用函數或映射進行資料轉換
#1.首先定義一個字典meat_to_animal={ 'bacon':'pig', 'pulled pork':'pig', 'honey ham':'cow'}#2.對某一列應用一個函數,或者字典,順便根據這一列的結果建立新列data['new_col']=data['food'].map(str.lower).map(meat_to_animal)
替換值
data.replace(-999,np.na)#多個值的替換data.replace([-999,-1000],np.na)#對應替換data.replace([-999,-1000],[np.na,0])#對應替換也可以傳入一個字典data.replace({-999:np.na,-1000:0})
離散化
# 定義分割點# 簡單分割(等寬分箱)s=pd.Series(range(100))pd.cut(s, bins=10, labels=range(10))bins=[20,40,60,80,100]#切割cats = pd.cut(series,bins)#查看標籤cats.labels#查看水平(因子)cats.levels#區間計數pd.value_count(cats)#自訂分區的標籤group_names=['youth','youngAdult','MiddleAge','Senior']pd.cut(ages,bins,labels=group_names)
分位元分割
data=np.random.randn(1000)pd.qcut(data,4) #四分位元#自訂分位元,包含端點pd.qcut(data,[0,0.3,0.5,0.9,1])
異常值
#查看各個統計量data.describe()#對某一列col=data[3]col[np.abs(col)>3]#選出全部含有“超過3或-3的值的行data[(np.abs(data)>3).any(1)]#異常值替換data[np.abs(data)>3]=np.sign(data)*3
抽樣
#隨機抽取k行df.take(np.random.permutation(len(df))[:k])#隨機抽取k行,但是k可能大於df的行數#可以理解為過抽樣了df.take(np.random.randint(0,len(df),size=k))
資料攤平處理
相當於將類別屬性轉成因子類型,比如是否有車,這個欄位有3個不同的值,有,沒有,過段時間買,那麼將會被編碼成3個欄位,有車,沒車,過段時間買車,每個欄位用0-1二值填充變成數值型。
#對攤平的資料列增加首碼dummies = pd.get_dummies(df['key'],prefix='key')#將攤平產生的資料列拼接回去df[['data1']].join(dummies)
字串操作
# 拆分strings.split(',')#根據Regex切分re.split('\s+',strings)# 串連'a'+'b'+'c'...或者'+'.join(series)# 判斷是否存在's' in strings`strings.find('s')# 計數strings.count(',')# 替換strings.replace('old','new')# 去除空白字元s.strip()
Regex
Regex需要先編譯匹配模式,然後才去匹配尋找,這樣能節省大量的CPU時間。
re.complie:編譯
findall:匹配所有
search:只返回第一個匹配項的起始和結束位址
match:值匹配字串的首部
sub:匹配替換,如果找到就替換
#原始字串strings = 'sdf@153.com,dste@qq.com,sor@gmail.com'#編譯匹配模式,IGNORECASE可以在使用的時候對大小寫不敏感pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}'regex = re.compile(pattern,flags=re.IGNORECASE)#匹配所有regex.findall(strings)#使用searchm = regex.search(strings) #擷取匹配的地址strings[m.start():m.end()]#匹配替換regex.sub('new_string', strings)
根據模式再切分
將模式切分,也就是將匹配到的進一步切分,通過pattern中的括弧實現.
pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\\.([A-Z]{2,4})'regex = re.compile(pattern)regex.findall(strings)#如果使用matchm=regex.match(string)m.groups()#效果是這樣的suzyu123@163.com --> [(suzyu123, 163, com)]#擷取 list-tuple 其中的某一列matches.get(i)
分組彙總,計算
group_by技術
# 根據多個索引分組,然後計算均值means = df['data1'].groupby([df['index1'],df['index2']).mean()# 展開成透視表格式means.unstack()
分組後價將片段做成一個字典
pieces = dict(list(df.groupby('index1')))pieces['b']
groupby預設是對列(axis=0)分組,也可以在行(axis=1)上分組 文法糖,groupby的快捷函數
df.groupby('index1')['col_names']df.groupby('index1')[['col_names']]#是下面代碼的文法糖df['col_names'].groupby(df['index1'])df.groupby(['index1','index2'])['col_names'].mean()
通過字典或series進行分組
people = DataFrame(np.random.randn(5, 5), columns=['a', 'b', 'c', 'd', 'e'], index=['Joe', 'Steve', 'Wes', 'Jim','Travis'])# 選擇部分設為napeople.ix[2:3,['b','c']]=np.namapping = {'a': 'red', 'b': 'red', 'c': 'blue', 'd': 'blue', 'e': 'red', 'f' : 'orange'}people.groupby(mapping,axis=1).sum()
通過函數進行分組
#根據索引的長度進行分組people.groupby(len).sum()
資料彙總
使用自訂函數
## 對所有的資料列使用自訂函數df.groupby('index1').agg(myfunc)#使用系統函數df.groupby('index1')['data1']describe()
根據列分組應用多個函數
#分組grouped = df.groupby(['col1','col2'])#選擇多列,對每一列應用多個函數grouped['data1','data2'...].agg(['mean','std','myfunc'])
對不同列使用不同的函數
grouped = df.groupby(['col1','col2'])#傳入一個字典,對不同的列使用不同的函數#不同的列可以應用不同數量的函數grouped.agg({'data1':['min','max','mean','std'], 'data2':'sum'})
分組計算後重新命名列名
grouped = df.groupby(['col1','col2'])grouped.agg({'data1':[('min','max','mean','std'),('d_min','d_max','d_mean','d_std')], 'data2':'sum'})
返回的彙總資料不要索引
df.groupby(['sex','smoker'], as_index=False).mean()
分組計算結果添加首碼
#對計算後的列名添加首碼df.groupby('index1').mean().add_prefix('mean_')
將分組計算後的值替換到原資料框
#將函數應用到各分組,再將分組計算的結果代換原資料框的值#也可以使用自訂函數df.groupby(['index1','index2'...]).transform(np.mean)
更一般化的apply函數
df.groupby(['col1','col2'...]).apply(myfunc)df.groupby(['col1','col2'...]).apply(['min','max','mean','std'])
禁用分組鍵
分組鍵會跟原始對象的索引共同構成結果對象中的層次化索引
df.groupby('smoker', group_keys=False).apply(mean)
分組索引轉成df的列
某些情況下,groupby的as_index=False參數並沒有什麼用,得到的還是一個series,這種情況一般是儘管分組了,但是計算需要涉及幾列,最後得到的還是series,series的index是層次化索引。這裡將series轉成dataframe,series的層次化索引轉成dataframe的列。
def fmean(df): """需要用兩列才能計算最後的結果""" skus=len(df['sku'].unique()) sums=df['salecount'].sum() return sums/skus#儘管禁用分組鍵,得到的還是seriessalemean=data.groupby(by=['season','syear','smonth'],as_index=False).apply(fmean)# 將series轉成dataframe,順便設定索引sub_df = pd.DataFrame(salemean.index.tolist(),columns=salemean.index.names,index=salemean.index)# 將groupby的結果和sub_df合并sub_df['salemean']=salemean
桶分析與分位元
對資料切分段,然後對每一分段應用函數
frame = DataFrame({'col1':np.random.randn(1000), 'col2':np.random.randn(1000)})#資料分段,建立分段用的因子#返回每一元素是屬於哪一分割區間factor = pd.cut(frame.col1, 4)#分組計算,然後轉成資料框形式grouped = frame.col2.groupby(factor)grouped.apply(myfunc).unstack()
用分組的均值填充缺失值
#自訂函數fill_mean= lambda x:x.fillna(x.mean())#分組填充df.groupby(group_key).apply(fill_mean)