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有广播,通过重复已有值来计算