pandas的拼接操作
pandas的拼接分為兩種:
- 級聯:pd.concat, pd.append
- 合並:pd.merge, pd.join
0. 回顧numpy的級聯
============================================
練習12:
- 生成2個3*3的矩陣,對其分別進行兩個維度上的級聯
============================================
import numpy as np import pandas as pd from pandas import Series,DataFrame
nd = np.random.randint(0,10,size=(3,3)) nd
np.concatenate((nd,nd),axis=0)#0代表行間操作
np.concatenate([nd,nd],axis=1)#1代表列間操作,()huo[]效果一樣
為方便講解,我們首先定義一個生成DataFrame的函數:
def make_df(inds,cols): #字典的key作為列名進行展示 data = {key:[key+str(i) for i in inds]for key in cols} return DataFrame(data,index=inds,columns=cols)
make_df([1,2],list('AB'))
1. 使用pd.concat()級聯
pandas使用pd.concat函數,與np.concatenate函數類似,只是多了一些參數:
pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False,
keys=None, levels=None, names=None, verify_integrity=False,
copy=True)
1) 簡單級聯
和np.concatenate一樣,優先增加行數(默認axis=0)
df1 = make_df([0,1],list('AB')) df2 = make_df([2,3],list('AB'))
display(df1,df2)
可以通過設置axis來改變級聯方向
pd.concat([df1,df2])
pd.concat((df1,df2),axis = 1)
注意index在級聯時可以重復
也可以選擇忽略ignore_index,重新索引
pd.concat((df1,df2),axis=1,ignore_index=True)
或者使用多層索引 keys
concat([x,y],keys=['x','y'])
pd.concat([df1,df2],keys=['x','y'])
#pd 模塊 import pandas as pd
#df1,df2 具體的實例 #級聯的方法,屬於上一級,DataFrame來自pandas
============================================
練習13:
-
想一想級聯的應用場景?
-
使用昨天的知識,建立一個期中考試張三、李四的成績表ddd
-
假設新增考試學科"計算機",如何實現?
-
新增王老五同學的成績,如何實現?
============================================
2) 不匹配級聯
不匹配指的是級聯的維度的索引不一致。例如縱向級聯時列索引不一致,橫向級聯時行索引不一致
df1 = make_df([1,2],list('AB')) df2 = make_df([2,4],list('BC')) display(df1,df2)
有3種連接方式:
- 外連接:補NaN(默認模式)
pd.concat([df1,df2])
- 內連接:只連接匹配的項
#合並顯示共有數據
pd.concat((df1,df2),join = 'inner',axis = 1)
- 連接指定軸 join_axes
df2.columns
#join_axex以某個DataFrame的列索引為新的列索引值
pd.concat([df1,df2],join_axes=[df2.columns])
============================================
練習14:
假設【期末】考試ddd2的成績沒有張三的,只有李四、王老五、趙小六的,使用多種方法級聯
============================================
3) 使用append()函數添加
由於在后面級聯的使用非常普遍,因此有一個函數append專門用於在后面添加
display(df1,df2)
#append函數屬於DataFrame,concat這函數屬於pandas模塊
#pd.concat((df1,df2)) df1.append(df2)
============================================
練習15:
新建一個只有張三李四王老五的期末考試成績單ddd3,使用append()與期中考試成績表ddd級聯
============================================
2. 使用pd.merge()合並
merge與concat的區別在於,merge需要依據某一共同的行或列來進行合並
使用pd.merge()合並時,會自動根據兩者相同column名稱的那一列,作為key來進行合並。
注意每一列元素的順序不要求一致
1) 一對一合並
#merge根據相同的元素進行合並的
df1 = DataFrame({'employee':['Po','Sara','Danis'], 'group':['sail','couting','marketing']}) df2 = DataFrame({'employee':['Po','Sara','Bush'], 'work_time':[2,3,1]}) display(df1,df2)
pd.merge(df1,df2)
df1.merge(df2)
2) 多對一合並
df1 = DataFrame({'employee':['Po','Sara','Danis'], 'group':['sail','couting','marketing']}) df2 = DataFrame({'employee':['Po','Po','Bush'], 'work_time':[2,3,1]}) display(df1,df2)
pd.merge(df1,df2)
3) 多對多合並
df1 = DataFrame({'employee':['Po','Po','Danis'], 'group':['sail','couting','marketing']}) df2 = DataFrame({'employee':['Po','Po','Bush'], 'work_time':[2,3,1]}) display(df1,df2)
pd.merge(df1,df2)
4) key的規范化
- 使用on=顯式指定哪一列為key,當有多個key相同時使用
df3 = DataFrame({'employee':['Po','Summer','Flower'], 'group':['sail','marketing','serch'], 'salary':[12000,10000,8000]}) df4 = DataFrame({'employee':['Po','Winter','Flower'], 'group':['marketing','marketing','serch'], 'work_time':[2,1,5]}) display(df3,df4)
pd.merge(df3,df4)
pd.merge(df3,df4,on='employee')
pd.merge(df3,df4,on='group',suffixes=['_A','_B'])
- 使用left_on和right_on指定左右兩邊的列作為key,當左右兩邊的key都不想等時使用
- 參數1為左,參數2為右
df3 = DataFrame({'employer':['Po','Summer','Flower'], 'Team':['sail','marketing','serch'], 'salary':[12000,10000,8000]}) df4 = DataFrame({'employee':['Po','Winter','Flower'], 'group':['marketing','marketing','serch'], 'work_time':[2,1,5]}) display(df3,df4)
pd.merge(df3,df4,left_on='employer',right_on='employee')
pd.merge(df3,df4,left_on='Team',right_on='group')
============================================
練習16:
-
假設有兩份成績單,除了ddd是張三李四王老五之外,還有ddd4是張三和趙小六的成績單,如何合並?
-
如果ddd4中張三的名字被打錯了,成為了張十三,怎么辦?
-
自行練習多對一,多對多的情況
-
自學left_index,right_index
============================================
5) 內合並與外合並
- 內合並:只保留兩者都有的key(默認模式)
df1 = DataFrame({'age':[18,22,33],'height':[175,169,180]}) df2 = DataFrame({'age':[18,23,31],'weight':[65,70,80]})
pd.merge(df1,df2)
df1.merge(df2,how='inner')
- 外合並 how='outer':補NaN
df1.merge(df2,how = 'outer')
- 左合並、右合並:how='left',how='right',
df1.merge(df2,how = 'left')#保留左側
pd.merge(df1,df2,how='right')#保留右側
============================================
練習17:
-
如果只有張三趙小六語數英三個科目的成績,如何合並?
-
考慮應用情景,使用多種方式合並ddd與ddd4
============================================
6) 列沖突的解決
當列沖突時,即有多個列名稱相同時,需要使用on=來指定哪一個列作為key,配合suffixes指定沖突列名
可以使用suffixes=自己指定后綴
display(df3,df4)
df3.columns = ['employee','group','salary'] display(df3)
pd.merge(df3,df4,on='employee',suffixes=['_李','_王'])
============================================
練習18:
假設有兩個同學都叫李四,ddd5、ddd6都是張三和李四的成績表,如何合並?
============================================
作業
3. 案例分析:美國各州人口數據分析
首先導入文件,並查看數據樣本
import numpy as np import pandas as pd from pandas import Series,DataFrame
#使用pandas讀取數據
pop = pd.read_csv('../../data/state-population.csv') areas = pd.read_csv('../../data/state-areas.csv') abb = pd.read_csv('../../data/state-abbrevs.csv')
pop.shape
pop.head()
areas.shape
abb.shape
合並pop與abbrevs兩個DataFrame,分別依據state/region列和abbreviation列來合並。
為了保留所有信息,使用外合並。
pop.head()
abb.head()
display(pop.shape,abb.shape)
#此時的場景 left == outer left數據大於abb
#left效果比outer差一些 #abb 河北 pop_m = pop.merge(abb,left_on='state/region',right_on='abbreviation',how = 'outer') pop_m.shape
去除abbreviation的那一列(axis=1)
pop_m.head()
pop_m.drop('abbreviation',axis = 1,inplace=True)
pop_m.head()
查看存在缺失數據的列。
使用.isnull().any(),只有某一列存在一個缺失數據,就會顯示True。
pop_m.isnull().any()
#population 和 state這兩列有數據缺失的情況
查看缺失數據
#為空的行索引
pop_m.loc[pop_m.isnull().any(axis = 1)]
根據數據是否缺失情況顯示數據,如果缺失為True,那么顯示
找到有哪些state/region使得state的值為NaN,使用unique()查看非重復值
condition = pop_m['state'].isnull() pop_m['state/region'][condition].unique()
areas
只有兩個州,對應的州名為空
為找到的這些state/region的state項補上正確的值,從而去除掉state這一列的所有NaN!
記住這樣清除缺失數據NaN的方法!
#Puerto Rico
conditon = pop_m['state/region'] == 'PR' condition
pop_m['state'][condition] = 'Puerto Rico'
condition = pop_m['state/region'] == 'USA' pop_m['state'][condition] = 'United State'
#剛才的填補操作,起作用了
pop_m.isnull().any()
合並各州面積數據areas,使用左合並。
思考一下為什么使用外合並?
pop.head() #人口的DataFrame和abb合並,有了州名全程 #可以和areas DataFrame進行合並
pop_areas_m = pop_m.merge(areas,how = 'outer')
繼續尋找存在缺失數據的列
pop_areas_m.shape
areas
pop_areas_m.isnull().any()
我們會發現area(sq.mi)這一列有缺失數據,為了找出是哪一行,我們需要找出是哪個state沒有數據
cond = pop_areas_m['area (sq. mi)'].isnull() cond
pop_areas_m['state/region'][cond]
去除含有缺失數據的行
pop_areas_m.shape
pop_areas_r = pop_areas_m.dropna()
pop_areas_r.shape
查看數據是否缺失
pop_areas_r.isnull().any()
找出2010年的全民人口數據,df.query(查詢語句)
pop_areas_r.head()
t_2010 = pop_areas_r.query("ages == 'total' and year == 2010")
t_2010.shape
t_2010
對查詢結果進行處理,以state列作為新的行索引:set_index
t_2010.set_index('state',inplace=True)
t_2010
計算人口密度。注意是Series/Series,其結果還是一個Series。
pop_density = t_2010['population']/t_2010["area (sq. mi)"] pop_density
排序,並找出人口密度最高的五個州sort_values()
type(pop_density)
pop_density.sort_values(inplace=True)
找出人口密度最低的五個州
pop_density[:5]
pop_density.tail()
要點總結:
- 統一用loc()索引
- 善於使用.isnull().any()找到存在NaN的列
- 善於使用.unique()確定該列中哪些key是我們需要的
- 一般使用外合並、左合並,目的只有一個:寧願該列是NaN也不要丟棄其他列的信息
回顧:Series/DataFrame運算與ndarray運算的區別
- Series與DataFrame沒有廣播,如果對應index沒有值,則記為NaN;或者使用add的fill_value來補缺失值
- ndarray有廣播,通過重復已有值來計算