希望自己在兵荒馬亂中保持韌性,發(fā)現(xiàn)寶藏怠肋。
目錄
1.清除重復(fù)行或某個(gè)字段:drop_duplicates函數(shù)
2.apply函數(shù)
3.axis的理解
4.pd.read_csv()讀數(shù)據(jù)
5.stack()和unstack()函數(shù)
6.groupby函數(shù)的使用
7.數(shù)據(jù)索引
8.數(shù)據(jù)排序
9.計(jì)算某列有多少個(gè)不同的值,類似sql中count(distinct A)
10.數(shù)據(jù)篩選缎谷,類似sql中l(wèi)ike或where
11.將連續(xù)數(shù)據(jù)離散化操作或者類似sql中Case When
12.修改列名
13.map、apply灶似、applymap詳解
14.povit_table數(shù)據(jù)透視表的使用
15.數(shù)據(jù)表的合并和連接
16.全局替換dataframe.replace()
17.data.to_csv()
1.drop_duplicates
DataFrame.drop_duplicates(subset=None, keep='first', inplace=False)
subset: 列名列林,可選,默認(rèn)為None
keep: {‘first’, ‘last’, False}, 默認(rèn)值 ‘first’
first: 保留第一次出現(xiàn)的重復(fù)行酪惭,刪除后面的重復(fù)行希痴。
last: 刪除重復(fù)項(xiàng),除了最后一次出現(xiàn)春感。
False: 刪除所有重復(fù)項(xiàng)砌创。
inplace:布爾值,默認(rèn)為False鲫懒,是否直接在原數(shù)據(jù)上刪除重復(fù)項(xiàng)或刪除重復(fù)項(xiàng)后返回副本嫩实。(inplace=True表示直接在原來的DataFrame上刪除重復(fù)項(xiàng),而默認(rèn)值False表示生成一個(gè)副本窥岩。)
根據(jù)數(shù)據(jù)的不同情況及處理數(shù)據(jù)的不同需求甲献,通常會(huì)分為兩種情況,一種是去除完全重復(fù)的行數(shù)據(jù)颂翼,另一種是去除某幾列重復(fù)的行數(shù)據(jù)晃洒,就這兩種情況可用下面的代碼進(jìn)行處理。
#去除完全重復(fù)的行數(shù)據(jù)
DataFrame.drop_duplicates()
#去除某幾列重復(fù)的行數(shù)據(jù)
DataFrame.drop_duplicates(subset=['A','B'],keep='first')
#示例朦乏,刪除positionId重復(fù)的行
data_duplicates=data.drop_duplicates(subset=['positionId'],keep='first')
data_duplicates.head()
2.apply函數(shù)
在pandas中球及,有Series和DataFrame兩者數(shù)據(jù)類型。針對(duì)這兩者類型使用apply函數(shù)有略微區(qū)別呻疹。
2.1 Series.apply
series = pd.Series([20, 21, 12], index=['London','New York','Helsinki'])
series
def square(x):
x=x**2
return x
series.apply(square)
series.apply(lambda x:x**2)
def subtract_custom_value(x, custom_value):
return x-custom_value
series.apply(subtract_custom_value,custom_value=5)
def add_custom_values(x, **kwargs):
for month in kwargs:
x+=kwargs[month]
return x
series.apply(add_custom_values,june=30, july=20, august=25)
series.apply(lambda x:np.log(x+1))
2.2 DataFrame.apply
df = pd.DataFrame([[4, 9,3],[3,5,2],[1,6,7]], columns=['A', 'B','C'])
df
df.apply(lambda x:x['A']+x['C'],axis=1)
df.apply(lambda x:np.sum(x),axis=0)
4.axis理解
axis是apply中的參數(shù)吃引,axis=1為橫向,axis=0為縱向刽锤,而不是行和列镊尺。這里axis=1就表示DataFrame根據(jù)lambda函數(shù)做橫向計(jì)算。
4.pd.read_csv
使用pd.read_csv()讀取數(shù)據(jù)姑蓝,對(duì)于數(shù)據(jù)路徑有三種辦法鹅心。一是ipynb文件和使用的數(shù)據(jù)集在同一個(gè)文件中,此時(shí)可以直接讀取纺荧。另一種就是ipynb文件和使用的數(shù)據(jù)集不在同一個(gè)文件中,此時(shí)讀取數(shù)據(jù)需要使用相對(duì)路徑和絕對(duì)路徑。
#ipynb文件和使用的數(shù)據(jù)集在同一個(gè)文件中
data=pd.read_csv('DataAnalyst.csv',encoding='gbk')
#ipynb文件和使用的數(shù)據(jù)集不在同一個(gè)文件中宙暇,使用相對(duì)路徑
data = pd.read_csv('C:/Users/Administrator/Desktop/秦路數(shù)據(jù)分析學(xué)習(xí)/第三周 Excel/DataAnalyst.csv',encoding='gbk')
#ipynb文件和使用的數(shù)據(jù)集不在同一個(gè)文件中输枯,使用絕對(duì)路徑
data = pd.read_csv('C:\\Users\\Administrator\\Desktop\\秦路數(shù)據(jù)分析學(xué)習(xí)\\第三周 Excel\\DataAnalyst.csv',encoding='gbk')
另外,pd.read_csv()的常用參數(shù):
header:指定行數(shù)用來作為列名占贫,數(shù)據(jù)開始行數(shù)桃熄。如果文件中沒有列名,則默認(rèn)為0型奥,否則設(shè)置為None瞳收。
sep:默認(rèn)的為',',即認(rèn)為文件是以逗號(hào)分隔(一般csv文件都是這個(gè)格式)厢汹,若是空格分隔螟深,可以使用"\s+"。
names:用于結(jié)果的列名列表烫葬,對(duì)各列重命名界弧,即添加表頭。
如數(shù)據(jù)有表頭搭综,但想用新的表頭垢箕,可以設(shè)置header=0,names=['a','b']實(shí)現(xiàn)表頭定制。
encoding:一般默認(rèn)為"utf-8"兑巾,如果文件中有中文条获,一般需要使用"gbk"既们。
5.stack()和unstack()函數(shù)
對(duì)數(shù)據(jù)做處理時(shí)洋魂,經(jīng)常需要對(duì)數(shù)據(jù)進(jìn)行reshape。其中脓鹃,stack和unstack是我們經(jīng)常用到的操作之一奋姿。
stack和unstack是python進(jìn)行層次化索引的重要操作锄开。層次化索引就是對(duì)索引進(jìn)行層次化分類,便于使用称诗,這里的索引可以是行索引萍悴,也可以是列索引。
其實(shí),應(yīng)用stack和unstack只需要記住下面的知識(shí)點(diǎn)即可:
stack: 將數(shù)據(jù)從”表格結(jié)構(gòu)“變成”花括號(hào)結(jié)構(gòu)“蜈首,即將其列索引變成行索引实抡。
unstack: 數(shù)據(jù)從”花括號(hào)結(jié)構(gòu)“變成”表格結(jié)構(gòu)“欠母,即要將其中一層的行索引變成列索引。如果是多層索引吆寨,則以上函數(shù)是針對(duì)內(nèi)層索引(這里是store)赏淌。利用level可以選擇具體哪層索引。
import pandas as pd
import numpy as np
from pandas import Series,DataFrame
data=DataFrame(np.arange(12).reshape((3,4)),index=pd.Index(['street1','street2','street3']),
columns=pd.Index(['store1','store2','store3','store4']))
print('----------data--------')
print(data)
print('-------------data2----------------------------\n')
data2=data.stack()
data3=data2.unstack()
print(data2)
print('--------------data3---------------------------\n')
print(data3)
data4=data2.unstack(level=0)
print('-------data4----------')
print(data4)
data5=data2.unstack(level=-1) # 默認(rèn)的level=-1啄清,內(nèi)層的索引
print('------data5--------')
print(data5)
'''
----------data--------
store1 store2 store3 store4
street1 0 1 2 3
street2 4 5 6 7
street3 8 9 10 11
-------------data2----------------------------
street1 store1 0
store2 1
store3 2
store4 3
street2 store1 4
store2 5
store3 6
store4 7
street3 store1 8
store2 9
store3 10
store4 11
dtype: int64
--------------data3---------------------------
store1 store2 store3 store4
street1 0 1 2 3
street2 4 5 6 7
street3 8 9 10 11
-------data4----------
street1 street2 street3
store1 0 4 8
store2 1 5 9
store3 2 6 10
store4 3 7 11
------data5--------
store1 store2 store3 store4
street1 0 1 2 3
street2 4 5 6 7
street3 8 9 10 11
'''
可以看到:使用stack函數(shù)六水,將data的列索引['store1','store2','store3’,'store4']轉(zhuǎn)變成行索引(第二層),便得到了一個(gè)層次化的Series(data2)辣卒,使用unstack函數(shù)掷贾,將data2的第二層行索引轉(zhuǎn)變成列索引(默認(rèn)內(nèi)層索引,level=-1)荣茫,便又得到了DataFrame(data3)
下面的例子我們利用level選擇具體哪層索引想帅。
data4=data2.unstack(level=0)
print(data4)
'''
street1 street2 street3
store1 0 4 8
store2 1 5 9
store3 2 6 10
store4 3 7 11
'''
我們可以清晰看到,當(dāng)我們?nèi)evel=0時(shí)计露,即最外層索引時(shí)博脑,unstack把行索引['street1','street2','street3’]變?yōu)榱肆兴饕?br> 重塑
6.groupby函數(shù)
#按照city和education分組
data_duplicates.groupby(['city','education']).mean()
#按city和education分組并計(jì)算bottomSalary最小值,最大值和平均值
data_duplicates.groupby(['city','education'])['bottomSalary'].agg(['min','max','mean'])
data_duplicates.groupby(['city','education']).agg({'bottomSalary':['mean','min'],'topSalary':'max','salary':'count'})
在日常的數(shù)據(jù)分析中票罐,經(jīng)常需要將數(shù)據(jù)根據(jù)某個(gè)(多個(gè))字段劃分為不同的群體(group)進(jìn)行分析叉趣,如電商領(lǐng)域?qū)⑷珖目備N售額根據(jù)省份進(jìn)行劃分,分析各省銷售額的變化情況该押,社交領(lǐng)域?qū)⒂脩舾鶕?jù)畫像(性別疗杉、年齡)進(jìn)行細(xì)分,研究用戶的使用情況和偏好等蚕礼。在Pandas中烟具,上述的數(shù)據(jù)處理操作主要運(yùn)用groupby完成,在這里著重介紹一下groupby的基本原理及對(duì)應(yīng)的agg奠蹬、transform和apply操作朝聋。
為了后續(xù)圖解的方便,采用模擬生成的10個(gè)樣本數(shù)據(jù)囤躁,代碼和數(shù)據(jù)如下:
company=["A","B","C"]
business=['X','Y','Z']
data=pd.DataFrame({
"company":[company[x] for x in np.random.randint(0,len(company),10)],
"business":[business[x] for x in np.random.randint(0,len(business),10)],
"salary":np.random.randint(5,50,10),
"age":np.random.randint(15,50,10)
}
)
data
1.Groupby的基本原理
在pandas中冀痕,實(shí)現(xiàn)分組操作的代碼很簡單,僅需一行代碼狸演,在這里言蛇,將上面的數(shù)據(jù)集按照company字段進(jìn)行劃分:
company_group=data.groupby(['company'])
company_group
將上述代碼輸入ipython后,會(huì)得到一個(gè)DataFrameGroupBy對(duì)象那這個(gè)生成的DataFrameGroupBy是啥呢宵距?對(duì)data進(jìn)行了groupby后發(fā)生了什么腊尚?ipython所返回的結(jié)果是其內(nèi)存地址,并不利于直觀地理解满哪,為了看看group內(nèi)部究竟是什么婿斥,這里把group轉(zhuǎn)換成list的形式來看一看:
list(company_group)
[('A', company business salary age
0 A Z 37 21
1 A Y 5 44
3 A X 38 30
4 A Y 31 36
9 A X 28 17),
('B', company business salary age
7 B Y 15 37
8 B Y 15 18),
('C', company business salary age
2 C X 40 17
5 C Y 15 30
6 C Y 19 26)]
轉(zhuǎn)換成列表的形式后劝篷,可以看到,列表由三個(gè)元組組成受扳,每個(gè)元組中携龟,第一個(gè)元素是組別(這里是按照company進(jìn)行分組兔跌,所以最后分為了A,B,C)勘高,第二個(gè)元素的是對(duì)應(yīng)組別下的DataFrame,整個(gè)過程可以圖解如下:總結(jié)來說坟桅,groupby的過程就是將原有的DataFrame按照groupby的字段(這里是company)华望,劃分為若干個(gè)分組DataFrame,被分為多少個(gè)組就有多少個(gè)分組DataFrame仅乓。所以說赖舟,在groupby之后的一系列操作(如agg、apply等)夸楣,均是基于子DataFrame的操作宾抓。理解了這點(diǎn),也就基本摸清了Pandas中g(shù)roupby操作的主要原理豫喧。下面來講講groupby之后的常見操作石洗。
2.agg聚合操作
聚合操作是groupby后非常常見的操作,會(huì)寫SQL的朋友對(duì)此應(yīng)該是非常熟悉了紧显。聚合操作可以用來求和讲衫、均值、最大值孵班、最小值等涉兽,下面的表格列出了Pandas中常見的聚合操作。針對(duì)樣例數(shù)據(jù)集篙程,如果我想求不同公司員工的平均年齡和平均薪水枷畏,可以按照下方的代碼進(jìn)行:
data.groupby(['company']).mean()
如果想對(duì)針對(duì)不同的列求不同的值,比如要計(jì)算不同公司員工的平均年齡以及薪水的中位數(shù)虱饿,可以利用字典進(jìn)行聚合操作的指定:
data.groupby(['company']).agg({'salary':'median','age':'mean'})
3.transform
transform是一種什么數(shù)據(jù)操作拥诡?和agg有什么區(qū)別呢?為了更好地理解transform和agg的不同郭厌,下面從實(shí)際的應(yīng)用場景出發(fā)進(jìn)行對(duì)比袋倔。
在上面的agg中,我們學(xué)會(huì)了如何求不同公司員工的平均薪水折柠,如果現(xiàn)在需要在原數(shù)據(jù)集中新增一列avg_salary宾娜,代表員工所在的公司的平均薪水(相同公司的員工具有一樣的平均薪水),該怎么實(shí)現(xiàn)呢扇售?如果按照正常的步驟來計(jì)算前塔,需要先求得不同公司的平均薪水嚣艇,然后按照員工和公司的對(duì)應(yīng)關(guān)系填充到對(duì)應(yīng)的位置,不用transform的話华弓,實(shí)現(xiàn)代碼如下:
avg_salary=data.groupby(['company']).salary.mean().to_dict()
avg_salary
data['avgsalary'] = data['company'].map(avg_salary)
data
如果使用transform的話食零,僅需要一行代碼:
data['avg_salary']=data.groupby(['company']).salary.transform('mean')
data
圖中的大方框是transform和agg所不一樣的地方贰谣,對(duì)agg而言,會(huì)計(jì)算得到A迁霎,B吱抚,C公司對(duì)應(yīng)的均值并直接返回,但對(duì)transform而言考廉,則會(huì)對(duì)每一條數(shù)據(jù)求得相應(yīng)的結(jié)果秘豹,同一組內(nèi)的樣本會(huì)有相同的值,組內(nèi)求完均值后會(huì)按照原索引的順序返回結(jié)果昌粤,如果有不理解的可以拿這張圖和agg那張對(duì)比一下既绕。
4.apply
apply相比agg和transform而言更加靈活,能夠傳入任意自定義的函數(shù)涮坐,實(shí)現(xiàn)復(fù)雜的數(shù)據(jù)操作凄贩。但apply在groupby后使用apply有什么特別的呢?
對(duì)于groupby后的apply膊升,以分組后的子DataFrame作為參數(shù)傳入指定函數(shù)的怎炊,基本操作單位是DataFrame,而一般apply的基本操作單位是Series廓译。還是以一個(gè)案例來介紹groupby后的apply用法评肆。
假設(shè)我現(xiàn)在需要獲取各個(gè)公司年齡最大的員工的數(shù)據(jù),該怎么實(shí)現(xiàn)呢非区?可以用以下代碼實(shí)現(xiàn):
def get_oldest_staff(x):
df = x.sort_values(by='age',ascending=False)
return df.iloc[0,:]
data.groupby('company',as_index=False).apply(get_oldest_staff)
最后,關(guān)于apply的使用管怠,這里有個(gè)小建議淆衷,雖然說apply擁有更大的靈活性,但apply的運(yùn)行效率會(huì)比agg和transform更慢渤弛。所以祝拯,groupby之后能用agg和transform解決的問題還是優(yōu)先使用這兩個(gè)方法,實(shí)在解決不了了才考慮使用apply進(jìn)行操作。
知乎--Groupby函數(shù)
7.數(shù)據(jù)索引
#單獨(dú)取出某一列
data_duplicates['city']
#取出多列
data_duplicates[['city','education']]
# 取出某列的某一行
data_duplicates['city'][0]
# 取出某列的某幾行
data_duplicates['city'][:10]
#取出某幾列的某幾行
data_duplicates[['city','education','salary']][:1]
# loc方法索引
'''
DataFrame.loc[行名,列名]
'''
# 取出某幾列的某幾行
data_duplicates.loc[[0,1,5],['city','education','salary']]
# 取出 city ,education ,salary的0-20行所有索引名稱為偶數(shù)的數(shù)據(jù)
data_duplicates.loc[0:21:2,['city','education','salary']]
#iloc方法索引
'''
DataFrame.iloc[行位置佳头,列位置]
'''
#取出某幾列的某幾行
data_duplicates.iloc[[0,1,5],[0,1,2]]
# 取出前五列的奇數(shù)列的0-20行所有索引名稱為偶數(shù)的數(shù)據(jù)
data_duplicates.iloc[0:21:2,0:5:2]
#ix方法索引
'''
DataFrame.ix[行位置/行名,列位置/列名]
'''
#篩選出A條件或B條件的樣本鹰贵。這里是組為實(shí)驗(yàn)組,頁面為新頁面或者組為控制組康嘉,頁面為舊頁面的樣本
df1=df[((df['group']=='treatment')&(df['landing_page']=='new_page'))|((df['group']=='control')&(df['landing_page']=='old_page'))]
8.數(shù)據(jù)排序
#Series.sort_values(ascending=False)False降序碉输,True升序
data_duplicates['bottomSalary'].sort_values(ascending=False)
#df.sort_values(by=['A','B'],ascending=False)按by的字段進(jìn)行排序
data_duplicates.sort_values(by='bottomSalary',ascending=False)
data_duplicates.sort_values(by=['bottomSalary','topSalary'],ascending=False)
9.計(jì)算某列有多少個(gè)不同的值,類似sql中count(distinct A)
data_duplicates['education'].nunique()
10.數(shù)據(jù)篩選,類似sql中l(wèi)ike或where
#篩選教育背景要求本科及以上
data_duplicates[data_duplicates['education'].isin(['本科','碩士','博士'])]
#篩選受教育背景非大專的樣本
data_duplicates[data_duplicates['education']!='大專']
#篩選公司名字中帶直播的數(shù)據(jù)
data_duplicates[data_duplicates['companyShortName'].str.contains('直播')]
#篩選公司名字中帶直播或者騰訊的數(shù)據(jù)
data_duplicates[data_duplicates['companyShortName'].str.contains('直播|騰訊')]
#多個(gè)條件篩選--在北京月薪10k起的直播行業(yè)招聘
data_duplicates[(data_duplicates['city']=='北京')&(data_duplicates['companyShortName'].str.contains('直播'))&(data_duplicates['bottomSalary']>10)]
11.將連續(xù)數(shù)據(jù)離散化操作或者類似sql中Case When
#根據(jù)最低薪資水平創(chuàng)建新的列SalaryType
#方法一
data_duplicates.loc[data_duplicates['bottomSalary']<=10,'SalaryType']='低薪資'
data_duplicates.loc[(data_duplicates['bottomSalary']>10)&(data_duplicates['bottomSalary']<=30),'SalaryType']='中等薪資'
data_duplicates.loc[data_duplicates['bottomSalary']>30,'SalaryType']='高薪資'
#方法二 pd.cut() 左開右閉 (0,10],(10,20],(20,1000]
data_duplicates['SalaryType1'] = pd.cut(data_duplicates['bottomSalary'],[0,10,20,1000],labels=['低薪資','中等薪資','高薪資'])
12.修改列名
data_duplicates.rename(columns={'city':'城市','公司名稱':'companyname'},inplace=True)
13.map亭珍、apply敷钾、applymap詳解
在日常的數(shù)據(jù)處理中,經(jīng)常會(huì)對(duì)一個(gè)DataFrame進(jìn)行逐行块蚌、逐列和逐元素的操作闰非,對(duì)應(yīng)這些操作膘格,Pandas中的map峭范、apply和applymap可以解決絕大部分這樣的數(shù)據(jù)處理需求。
boolean=[True,False]
gender=["男","女"]
color=["white","black","yellow"]
data=pd.DataFrame({
"height":np.random.randint(150,190,100),
"weight":np.random.randint(40,90,100),
"smoker":[boolean[x] for x in np.random.randint(0,2,100)],
"gender":[gender[x] for x in np.random.randint(0,2,100)],
"age":np.random.randint(15,90,100),
"color":[color[x] for x in np.random.randint(0,len(color),100) ]
})
data.head()
Series處理
1.map用法
如果需要把數(shù)據(jù)集中g(shù)ender列的男替換為1瘪贱,女替換為0纱控,怎么做呢?絕對(duì)不是用for循環(huán)實(shí)現(xiàn)菜秦,使用Series.map()可以很容易做到甜害,最少僅需一行代碼。
#第一種方法
data['gender'] = data['gender'].map({'男':1,'女':0})
#第二種方法
#使用函數(shù)
def gender_map(x): #這里x表示的是Series的一個(gè)元素球昨,對(duì)Series元素依次處理
if x=='男':
gender=1
else:
gender=0
return gender
data['gender']=data['gender'].map(gender_map)
那map在實(shí)際過程中是怎么運(yùn)行的呢尔店?請(qǐng)看下面的圖解(為了方便展示,僅截取了前10條數(shù)據(jù))不論是利用字典還是函數(shù)進(jìn)行映射主慰,map方法都是把對(duì)應(yīng)的數(shù)據(jù)逐個(gè)當(dāng)作參數(shù)傳入到字典或函數(shù)中嚣州,得到映射后的值。
2.apply用法
同時(shí)Series對(duì)象還有apply方法共螺,apply方法的作用原理和map方法類似该肴,區(qū)別在于apply能夠傳入功能更為復(fù)雜的函數(shù)。怎么理解呢藐不?一起看看下面的例子匀哄。
假設(shè)在數(shù)據(jù)統(tǒng)計(jì)的過程中,年齡age列有較大誤差雏蛮,需要對(duì)其進(jìn)行調(diào)整(加上或減去一個(gè)值)涎嚼,由于這個(gè)加上或減去的值未知,故在定義函數(shù)時(shí)挑秉,需要加多一個(gè)參數(shù)bias法梯,此時(shí)用map方法是操作不了的(傳入map的函數(shù)只能接收一個(gè)參數(shù)),apply方法則可以解決這個(gè)問題衷模。
def apply_age(x,**kwargs):
for i in kwargs:
x+=kwargs[i]
return x
#以字典的形式傳遞參數(shù)
data['age'] = data['age'].apply(apply_age,list_1=6,list_2=3,list_3=1)
data.head()
總而言之鹊汛,對(duì)于Series而言蒲赂,map可以解決絕大多數(shù)的數(shù)據(jù)處理需求,但如果需要使用較為復(fù)雜的函數(shù)刁憋,則需要用到apply方法滥嘴。
DataFrame處理
對(duì)于DataFrame而言,基本沒有DataFrame.map()的使用至耻,map方法都是針對(duì)Series的處理若皱。
1.apply
對(duì)DataFrame而言,apply是非常重要的數(shù)據(jù)處理方法尘颓,它可以接收各種各樣的函數(shù)(Python內(nèi)置的或自定義的)走触,處理方式很靈活,下面通過幾個(gè)例子來看看apply的具體使用及其原理疤苹。
假設(shè)現(xiàn)在需要對(duì)data中的數(shù)值列分別進(jìn)行取對(duì)數(shù)和求和的操作晴音,這時(shí)可以用apply進(jìn)行相應(yīng)的操作,因?yàn)槭菍?duì)列進(jìn)行操作粹污,所以需要指定axis=0段多,使用下面的兩行代碼可以很輕松地解決我們的問題。
#沿著0軸求和
data[['height','weight','age']].apply(lambda x:sum(x),axis=0)
#沿著0軸求log
data[['height','weight','age']]=data[['height','weight','age']].apply(lambda x:np.log(x),axis=0)
data.head()
當(dāng)沿著軸0(axis=0)進(jìn)行操作時(shí)觉啊,會(huì)將各列(columns)默認(rèn)以Series的形式作為參數(shù),傳入到你指定的操作函數(shù)中沈贝,操作后合并并返回相應(yīng)的結(jié)果杠人。
那如果在實(shí)際使用中需要按行進(jìn)行操作(axis=1),那整個(gè)過程又是怎么實(shí)現(xiàn)的呢?
在數(shù)據(jù)集中,有身高和體重的數(shù)據(jù)嗡善,所以根據(jù)這個(gè)辑莫,我們可以計(jì)算每個(gè)人的BMI指數(shù)(體檢時(shí)常用的指標(biāo),衡量人體肥胖程度和是否健康的重要標(biāo)準(zhǔn))罩引,計(jì)算公式是:體重指數(shù)BMI=體重/身高的平方(國際單位kg/㎡),因?yàn)樾枰獙?duì)每個(gè)樣本進(jìn)行操作袁铐,這里使用axis=1的apply進(jìn)行操作揭蜒,代碼如下:
def BMI(x):
weight=x['weight']
height=x['height']/100
BMI = weight/height**2
return BMI
data['BMI'] = data.apply(BMI,axis=1)
data.head()
當(dāng)apply設(shè)置了axis=1對(duì)行進(jìn)行操作時(shí),會(huì)默認(rèn)將每一行數(shù)據(jù)以Series的形式(Series的索引為列名)傳入指定函數(shù)剔桨,返回相應(yīng)的結(jié)果屉更。
總結(jié)一下對(duì)DataFrame的apply操作:
1.當(dāng)axis=0時(shí),對(duì)每列columns執(zhí)行指定函數(shù)洒缀;當(dāng)axis=1時(shí)瑰谜,對(duì)每行row執(zhí)行指定函數(shù)。
2.無論axis=0還是axis=1帝洪,其傳入指定函數(shù)的默認(rèn)形式均為Series似舵,可以通過設(shè)置raw=True傳入numpy數(shù)組。
3.對(duì)每個(gè)Series執(zhí)行結(jié)果后葱峡,會(huì)將結(jié)果整合在一起返回(若想有返回值,定義函數(shù)時(shí)需要return相應(yīng)的值)
4.當(dāng)然龙助,DataFrame的apply和Series的apply一樣砰奕,也能接收更復(fù)雜的函數(shù),如傳入?yún)?shù)等提鸟,實(shí)現(xiàn)原理是一樣的军援,具體用法詳見官方文檔。
2.applymap
applymap的用法比較簡單称勋,會(huì)對(duì)DataFrame中的每個(gè)單元格執(zhí)行指定函數(shù)的操作胸哥,雖然用途不如apply廣泛,但在某些場合下還是比較有用的赡鲜,如下面這個(gè)例子空厌。
df = pd.DataFrame(
{
"A":np.random.randn(5),
"B":np.random.randn(5),
"C":np.random.randn(5),
"D":np.random.randn(5),
"E":np.random.randn(5),
}
)
df
現(xiàn)在想將DataFrame中所有的值保留兩位小數(shù)顯示,使用applymap可以很快達(dá)到你想要的目的银酬,代碼和圖解如下:
df.applymap(lambda x:'%.2f'%x)
14.pivot_table數(shù)據(jù)透視表
從功能上講嘲更,Pandas 中用透視表 (pivot table) 和 Excel 里面的透視表是一樣的。
Pivot 字面意思是支點(diǎn)揩瞪,即上圖中的 index 和 columns 指定的行和列標(biāo)簽赋朦,支點(diǎn)可想理解成數(shù)據(jù) (values) 在哪個(gè)維度上做整合 (aggfunc),再吧 NaN 值用 fill_value 替代,按行按列加總 (margin=True)宠哄。
boolean=[True,False]
gender=["男","女"]
color=["white","black","yellow"]
data=pd.DataFrame({
"height":np.random.randint(150,190,100),
"weight":np.random.randint(40,90,100),
"smoker":[boolean[x] for x in np.random.randint(0,2,100)],
"gender":[gender[x] for x in np.random.randint(0,2,100)],
"age":np.random.randint(15,90,100),
"color":[color[x] for x in np.random.randint(0,len(color),100) ]
})
data.head()
設(shè)置"單行"為pivot
創(chuàng)建透視表的 pivot_table() 函數(shù)里面的參數(shù)設(shè)置很多壹将,學(xué)習(xí)它最有效的方式是每一步設(shè)置一個(gè)參數(shù),檢查結(jié)果是否符合預(yù)期毛嫉。
先從最簡單的語法開始瞭恰,只設(shè)置 index='gender',通用語法如下:
data.pivot_table(index='gender')
從上表可以看到狱庇,年齡惊畏、身高、體重密任、甚至bool類型的是否吸煙都按某種聚合方式進(jìn)行了合并了⊙掌簦現(xiàn)在大概可以猜出 pivot_table() 函數(shù)中有個(gè)參數(shù)用來設(shè)置整合方式,而默認(rèn)值為平均浪讳。
設(shè)置"多行"為pivot
上例設(shè)置單個(gè) index缰盏,接下來看看設(shè)置多個(gè) index 的結(jié)果是什么樣的。這時(shí)用列表來存儲(chǔ)多個(gè) index淹遵。通用語法如下:
data.pivot_table(index=['gender','smoker'])
到目前為止口猜,我們只設(shè)置了 index,那為什么只在 age透揣、height和weight三列上做整合呢济炎?因?yàn)檫@兩列的值是數(shù)值型 (int, float),而其他列的值是非數(shù)值型 (object)辐真。
設(shè)定被整合的數(shù)據(jù)
如果只看 age列下的整合結(jié)果须尚,只需設(shè)置 values='age' 或者 values=['age'],通用語法如下:
pd.pivot_table(df, index=label_list, values=label_list)
data.pivot_table(index=['gender','smoker'],values='age')
設(shè)定整合函數(shù)
默認(rèn)整合函數(shù)是求平均侍咱,如果要用求和的函數(shù)需要設(shè)置 aggfunc=np.sum耐床,通用語法為
pd.pivot_table(df, index=label_list, values=label_list, aggfunc=func)
data.pivot_table(index=['gender','smoker'],values='age',aggfunc='sum')
aggfunc 參數(shù)可以被設(shè)置為多個(gè)函數(shù),用列表儲(chǔ)存楔脯,通用語法為
pd.pivot_table(df, index=label_list, values=label_list, aggfunc=func_list)
data.pivot_table(index=['gender','smoker'],values='age',aggfunc=['sum','mean'])
設(shè)定列為pivot
如果進(jìn)一步想看按吸煙劃分后的整合結(jié)果撩轰,可以設(shè)置 columns=[''smoker"]
data.pivot_table(index=['gender'],columns=['smoker'],values='age',aggfunc=['mean'])
若表結(jié)果中有 NaN ,可設(shè)置 fill_value=0 用零替代昧廷。
要看總計(jì)怎么辦堪嫂?設(shè)置 margins=True 就可以了。
aggfunc 參數(shù)還可以傳進(jìn)一個(gè)字典來實(shí)現(xiàn)不同列下應(yīng)用不同的整合函數(shù)麸粮,語法如下:
pd.pivot_table( df, index=["Counterparty","Trader","Category"],
values=["Value","Quantity"],
aggfunc={"Value":np.sum, "Quantity":len},
fill_value=0,
margins=True )
再進(jìn)一步溉苛,不同列還可以應(yīng)用多個(gè)函數(shù),只需把函數(shù)名稱變成函數(shù)列表就可以了弄诲。語法如下:
pd.pivot_table( df, index=["Counterparty","Trader","Category"],
values=["Value","Quantity"],
aggfunc={"Value":[np.sum, min, max],
"Quantity":len},
fill_value=0 )
15.數(shù)據(jù)表的合并與連接
數(shù)據(jù)表可以按「鍵」合并愚战,用 merge 函數(shù)娇唯;可以按「軸」來連接,用 concat 函數(shù)寂玲。
15.1合并
按鍵 (key) 合并可以分「單鍵合并」和「多鍵合并」塔插。
單鍵合并
單鍵合并用merge函數(shù),語法如下:
pd.merge(df1,df2,how=s,on=c)
c是df1和df2共有的一欄拓哟,合并方式(how=s)有四種:
1.左連接(left join):合并之后顯示df1的所有行
2.右連接(right join):合并之后顯示df2的所有行
3.外連接(outer join)合并df1和df2的所有行
4.內(nèi)連接(inner join):合并所有行(默認(rèn)情況)
首先創(chuàng)建兩個(gè) DataFrame:
df_price:4 天的價(jià)格 (2019-01-01 到 2019-01-04)
df_volume:5 天的交易量 (2019-01-02 到 2019-01-06)
df_price = pd.DataFrame( {'Date': pd.date_range('2019-1-1', periods=4),
'Adj Close': [24.42, 25.00, 25.25, 25.64]})
df_volume = pd.DataFrame( {'Date': pd.date_range('2019-1-2', periods=5),
'Volume' : [56081400, 99455500, 83028700, 100234000, 73829000]})
left join:
pd.merge(df_price,df_volume,how='left')
right join:
pd.merge(df_price,df_volume,how='right')
outer join:
pd.merge(df_price,df_volume,how='outer')
inner join:
pd.merge(df_price,df_volume,how='inner')
多鍵合并
多鍵合并用的語法和單鍵合并一樣,只不過 on=c 中的 c 是多欄断序。
pd.merge( df1, df2, how=s, on=c )
首先創(chuàng)建兩個(gè) DataFrame:
portfolio1:3 比產(chǎn)品 FX Option, FX Swap 和 IR Option 的數(shù)量
portfolio2:4 比產(chǎn)品 FX Option (重復(fù)名稱), FX Swap 和 IR Swap 的數(shù)量
porfolio1 = pd.DataFrame({'Asset': ['FX', 'FX', 'IR'],
'Instrument': ['Option', 'Swap', 'Option'],
'Number': [1, 2, 3]})
porfolio2 = pd.DataFrame({'Asset': ['FX', 'FX', 'FX', 'IR'],
'Instrument': ['Option', 'Option', 'Swap', 'Swap'],
'Number': [4, 5, 6, 7]})
pd.merge(porfolio1,porfolio2,on=['Asset','Instrument'],how='left')
15.2連接
Numpy 數(shù)組可相互連接流纹,用 np.concat;同理违诗,Series 也可相互連接漱凝,DataFrame 也可相互連接,用 pd.concat诸迟。
連接Series
在 concat 函數(shù)也可設(shè)定參數(shù) axis:
axis = 0 (默認(rèn))茸炒,沿著軸 0 (行) 連接,得到一個(gè)更長的 Series
axis = 1阵苇,沿著軸 1 (列) 連接壁公,得到一個(gè) DataFrame
被連接的 Series 它們的 index 可以重復(fù) (overlapping),也可以不同绅项。
s1 = pd.Series([0, 1], index=['a', 'b'])
s2 = pd.Series([2, 3, 4], index=['c', 'd', 'e'])
s3 = pd.Series([5, 6], index=['f', 'g'])
#沿著「軸 1」連接得到一個(gè) DataFrame紊册。
pd.concat([s1,s2,s3],axis=1)
將 s1 和 s3 沿「軸 0」連接來創(chuàng)建 s4,這樣 s4 和 s1 的 index 是有重復(fù)的趁怔。
s4 = pd.concat([s1,s3],axis=0)
pd.concat([s1,s4],axis=1)
#將 s1 和 s4 沿「軸 1」內(nèi)連接 (即只連接它們共有 index 對(duì)應(yīng)的值)
pd.concat([s1,s4],axis=1,join='inner')
連接DataFrame
連接 DataFrame 的邏輯和連接 Series 的一模一樣湿硝。
沿著行連接(axis=0):
先創(chuàng)建兩個(gè) DataFrame,df1 和 df2润努。
df1 = pd.DataFrame( np.arange(12).reshape(3,4),
columns=['a','b','c','d'])
df2 = pd.DataFrame( np.arange(6).reshape(2,3),
columns=['b','d','a'])
沿著行連接分兩步
1.先把 df1 和 df2 列標(biāo)簽補(bǔ)齊
2.再把 df1 和 df2 縱向連起來
pd.concat([df1,df2],axis=0,ignore_index=True)
沿著列連接(axis=1):
先創(chuàng)建兩個(gè) DataFrame,df1 和 df2示括。
df1 = pd.DataFrame( np.arange(6).reshape(3,2),
index=['a','b','c'],
columns=['one','two'] )
df2 = pd.DataFrame( 5 + np.arange(4).reshape(2,2),
index=['a','c'],
columns=['three','four'])
pd.concat([df1,df2],axis=1)
16.全局替換DataFrame.replace(to_replace, value)
http://www.reibang.com/p/2557a805211f
replace的基本結(jié)構(gòu)是:df.replace(to_replace, value) 前面是需要替換的值铺浇,后面是替換后的值。
例如我們要將南岸改為城區(qū):
這樣Python就會(huì)搜索整個(gè)DataFrame并將文檔中所有的南岸替換成了城區(qū)(要注意這樣的操作并沒有改變文檔的源數(shù)據(jù)垛膝,要改變?cè)磾?shù)據(jù)需要使用inplace = True)鳍侣。
17.data.to_csv()
不想要行索引。data.to_csv(index=False)