04-2pandas的拼接操作

pandas的拼接操作

pandas的拼接分为两种:

  • 级联:pd.concat, pd.append (没有重复数据)
  • 合并:pd.merge, pd.join (有重复数据)

0. 回顾numpy的级联

============================================

练习12:

  1. 生成2个3*3的矩阵,对其分别进行两个维度上的级联

============================================

import numpy as np
import pandas as pd
from pandas import Series,DataFrame
nd1 = np.random.randint(0,10,size=(3,3))
nd2 = np.random.randint(10,100,size=(3,3))
display(nd1,nd2)
结果为:
array([[7, 2, 9],
       [4, 6, 5],
       [6, 0, 8]])
array([[18, 19, 44],
       [33, 71, 91],
       [69, 42, 33]])
np.concatenate((nd1,nd2))
结果为:
array([[ 5,  3,  9],
       [ 9,  4,  7],
       [ 3,  1,  5],
       [11, 46, 23],
       [40, 61, 70],
       [28, 47, 12]])
np.concatenate((nd1,nd2),axis=1)
结果为:
array([[ 7,  0,  8, 54, 81, 24],
       [ 3,  0,  3, 24, 66, 91],
       [ 3,  9,  5, 28, 40, 68]])

1. 使用pd.concat()级联

为方便讲解,我们首先定义一个生成DataFrame的函数:

df1 = DataFrame(nd1)
df2 = DataFrame(nd2)
display(df1,df2)
012
0708
1303
2395
012
0548124
1246691
2284068

1) 简单级联

pandas使用pd.concat函数,与np.concatenate函数类似

df3 = pd.concat((df1,df2)) #默认 axis是0 是纵向拼接
df3
012
0708
1303
2395
0548124
1246691
2284068

索引有重复 会产生一些问题

df3.loc[0]
012
0708
0548124

可以通过 重置索引的方式 去重新让索引不重复

# ignore_index=False 忽略原索引 建立新索引 默认是False
df3 = pd.concat((df1,df2),ignore_index=True,axis=0) # 默认是 0 竖直方向这样写:df3 = pd.concat((df1,df2),ignore_index=True)
df3
012
0708
1303
2395
3548124
4246691
5284068
df3 = pd.concat((df1,df2),axis=1) # 1 水平方向拼接
df3
012012
0708548124
1303246691
2395284068
df3 = pd.concat((df1,df2),ignore_index=True,axis=1)
df3
012345
0708548124
1303246691
2395284068
df3 = pd.concat((df1,df2),keys=["第一个","第二个"])
df3
012
第一个0708
1303
2395
第二个0548124
1246691
2284068

2) 不匹配级联

不匹配指的是级联的维度的索引不一致。例如纵向级联时列索引不一致,横向级联时行索引不一致

有3种连接方式:

  • 外连接:补NaN(默认模式)

  • 内连接:只连接匹配的项

  • 连接指定轴 join_axes

nd1,nd2
结果为:
(array([[7, 0, 8],
        [3, 0, 3],
        [3, 9, 5]]),
 array([[54, 81, 24],
        [24, 66, 91],
        [28, 40, 68]]))

把相同索引的行或列进行级联,如果存在不匹配的行列标签,补nan

df3 = DataFrame(data=nd1,columns=list("ABC"))
df4 = DataFrame(data=nd2,columns=list("BCD"))
display(df3,df4)
ABC
0708
1303
2395
BCD
0548124
1246691
2284068
pd.concat((df3,df4),sort=False) # dataframe 拼接 默认是 外联 
ABCD
07.008NaN
13.003NaN
23.095NaN
0NaN548124.0
1NaN246691.0
2NaN284068.0
pd.concat((df3,df4),sort=False,join="inner") 
BC
008
103
295
05481
12466
22840
pd.concat((df3,df4),sort="False",axis=1,ignore_index="True")
012345
0708548124
1303246691
2395284068

使用keys参数,可以自动设置为多层级索引,避免索引重复

pd.concat((df3,df4),keys=['期中','期末'],sort="False")
ABCD
期中07.008NaN
13.003NaN
23.095NaN
期末0NaN548124.0
1NaN246691.0
2NaN284068.0
index = pd.Index(["B","C"])#改变列标题
pd.concat((df3,df4),sort="False",join_axes=[index])
BC
008
103
295
05481
12466
22840

总结:pd.concat() 参数

  1. objs 传入列表或者元素 里面是要拼接的DataFrame
  2. axis 拼接的时候是沿着什么方向 默认值是0 纵向 如果是1就是横向
  3. join 指定了拼接的方式 默认是outer
    outer 外联 所有的列都会拼进来
    inner 内联 只有那些两个DataFrame都有的列才会拼进来
  4. join_axes 直接指定那些列要放进来
  5. ignore_index=False 忽略原有索引创建新的索引 (如果索引有重复可以通过忽略原索引来重置)
  6. keys 可以把不同的DataFrame分成多组 也可以用来解决index重复的问

============================================

练习13:

  1. 想一想级联的应用场景?
  2. 使用昨天的知识,建立一个期中考试张三、李四的成绩表df
  3. 假设新增考试学科"计算机",如何实现?
  4. 新增王老五同学的成绩,如何实现?

============================================

import numpy as np
data = np.random.randint(0,150,size=(2,3))
index = ["张三","李四"]
columns = ["语文","数学","外语"]
df1 = DataFrame(data,index,columns)
df1
语文数学外语
张三1121272
李四123792
data = np.random.randint(0,150,size=(2,1))
index = ["张三","李四"]
columns = ["计算机"]
df2 = DataFrame(data,index,columns)
df2
计算机
张三110
李四37
df5 = pd.concat((df1,df2),axis=1,sort=False)
df5
语文数学外语计算机
张三1121272110
李四12379237
data = np.random.randint(0,150,size=(1,4))
index = ["王老五"]
columns = ["语文","数学","外语","计算机"]
df3 = DataFrame(data,index,columns)
df3
语文数学外语计算机
王老五12011514011
pd.concat((df1,df3),sort=False)
语文数学外语计算机
张三1121272NaN
李四123792NaN
王老五12011514011.0

3) 使用append()函数添加

由于在后面级联的使用非常普遍,因此有一个函数append专门用于在后面添加

df5.append(df3)
语文数学外语计算机
张三1121272110
李四12379237
王老五12011514011

============================================

练习15:

新建一个只有张三李四王老五的期末考试成绩单ddd3,使用append()与期中考试成绩表ddd级联

============================================

2. 使用pd.merge()合并

merge与concat的区别在于,merge需要依据某一共同的行或列来进行合并

使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并。

注意每一列元素的顺序不要求一致

1) 一对一合并

2) 多对一合并

3) 多对多合并

table1 = pd.read_excel("./关系表.xls",sheet_name=0)
table2 = pd.read_excel("./关系表.xls",sheet_name=1)
table3 = pd.read_excel("./关系表.xls",sheet_name=2)
table4 = pd.read_excel("./关系表.xls",sheet_name=3)
table5 = pd.read_excel("./关系表.xls",sheet_name=4)
display(table1,table2)
手机型号参考价格
0windowsPhone2500
1iPhone7500
2Android4000
手机型号重量
0windowsPhone0.50
1iPhone0.40
2Android0.45
3other0.60

一一对应的表格 通过merge融合 把数据对应上就可以了

pd.merge(table1,table2)
手机型号参考价格重量
0windowsPhone25000.50
1iPhone75000.40
2Android40000.45

how指的是如何拼接 默认是inner 内联 (两个表格都有的项目才留下){‘left’, ‘right’, ‘outer’, ‘inner’}, default ‘inner’

pd.merge(table1,table2,how="inner") # inner  是取交集 两个都有的项目才出现
手机型号参考价格重量
0windowsPhone25000.50
1iPhone75000.40
2Android40000.45
pd.merge(table1,table2,how="outer") # outer 是取并集 任何一个表格里出现的项目都会出现
手机型号参考价格重量
0windowsPhone2500.00.50
1iPhone7500.00.40
2Android4000.00.45
3otherNaN0.60
pd.merge(table1,table2,how="left") # 左边的表格有多少项目 这里就有多少项目
手机型号参考价格重量
0windowsPhone25000.50
1iPhone75000.40
2Android40000.45
pd.merge(table1,table2,how="right") # 右边的表格有多少项目 这里就有多少项目
手机型号参考价格重量
0windowsPhone2500.00.50
1iPhone7500.00.40
2Android4000.00.45
3otherNaN0.60

一对多

display(table2,table3)
手机型号重量
0windowsPhone0.50
1iPhone0.40
2Android0.45
3other0.60
经销商发货地区手机型号
0peggebeijingiPhone
1lucybeijingAndroid
2tomguangzhouiPhone
3pettershenzhenwindowsPhone
4meryguangzhouAndroid

一对多 的 表格拼接 两个表格需要有一个相同的column 然后在把1*多个 计算出新的行

pd.merge(table2,table3,how="inner")
手机型号重量经销商发货地区
0windowsPhone0.50pettershenzhen
1iPhone0.40peggebeijing
2iPhone0.40tomguangzhou
3Android0.45lucybeijing
4Android0.45meryguangzhou
pd.merge(table2,table3,how="outer")
手机型号重量经销商发货地区
0windowsPhone0.50pettershenzhen
1iPhone0.40peggebeijing
2iPhone0.40tomguangzhou
3Android0.45lucybeijing
4Android0.45meryguangzhou
5other0.60NaNNaN
pd.merge(table2,table3,how="left")
手机型号重量经销商发货地区
0windowsPhone0.50pettershenzhen
1iPhone0.40peggebeijing
2iPhone0.40tomguangzhou
3Android0.45lucybeijing
4Android0.45meryguangzhou
5other0.60NaNNaN
pd.merge(table2,table3,how="right")
手机型号重量经销商发货地区
0windowsPhone0.50pettershenzhen
1iPhone0.40peggebeijing
2iPhone0.40tomguangzhou
3Android0.45lucybeijing
4Android0.45meryguangzhou

多对多

display(table3,table4)
经销商发货地区手机型号
0peggebeijingiPhone
1lucybeijingAndroid
2tomguangzhouiPhone
3pettershenzhenwindowsPhone
4meryguangzhouAndroid
发货地区手机型号价格
0beijingiPhone7000
1beijingwindowsPhone2300
2beijingAndroid3600
3guangzhouiPhone7600
4guangzhouwindowsPhone2800
5guangzhouAndroid4200
6shenzheniPhone7400
7shenzhenwindowsPhone2750
8shenzhenAndroid3900

方式1 我们通过on 指定 按照哪一列进行拼接 然后可以通过suffixes指定重复的列的后缀

pd.merge(table3,table4,on="手机型号",suffixes=["_1","_2"])
经销商发货地区_1手机型号发货地区_2价格
0peggebeijingiPhonebeijing7000
1peggebeijingiPhoneguangzhou7600
2peggebeijingiPhoneshenzhen7400
3tomguangzhouiPhonebeijing7000
4tomguangzhouiPhoneguangzhou7600
5tomguangzhouiPhoneshenzhen7400
6lucybeijingAndroidbeijing3600
7lucybeijingAndroidguangzhou4200
8lucybeijingAndroidshenzhen3900
9meryguangzhouAndroidbeijing3600
10meryguangzhouAndroidguangzhou4200
11meryguangzhouAndroidshenzhen3900
12pettershenzhenwindowsPhonebeijing2300
13pettershenzhenwindowsPhoneguangzhou2800
14pettershenzhenwindowsPhoneshenzhen2750

第二种方式 指定两个相同的列 这两列中的项目必须都对应上才会显示到新的表格中

pd.merge(table3,table4,on=["手机型号","发货地区"])
经销商发货地区手机型号价格
0peggebeijingiPhone7000
1lucybeijingAndroid3600
2tomguangzhouiPhone7600
3pettershenzhenwindowsPhone2750
4meryguangzhouAndroid4200
display(table4,table5)
发货地区手机型号价格
0beijingiPhone7000
1beijingwindowsPhone2300
2beijingAndroid3600
3guangzhouiPhone7600
4guangzhouwindowsPhone2800
5guangzhouAndroid4200
6shenzheniPhone7400
7shenzhenwindowsPhone2750
8shenzhenAndroid3900
型号价格
0iPhone7000
1windowsPhone2300
2Android3600
3iPhone7600
4windowsPhone2800
5Android4200
6iPhone7400
7windowsPhone2750
8Android3900

4) key的规范化

  • 使用on=显式指定哪一列为key,当有多个key相同时使用

  • 使用left_on和right_on指定左右两边的列作为key,当左右两边的key都不想等时使用

============================================

练习16:

  1. 假设有两份成绩单,除了ddd是张三李四王老五之外,还有ddd4是张三和赵小六的成绩单,如何合并?
  2. 如果ddd4中张三的名字被打错了,成为了张十三,怎么办?
  3. 自行练习多对一,多对多的情况
  4. 自学left_index,right_index

============================================

5) 内合并与外合并

  • 内合并:只保留两者都有的key(默认模式)

  • 外合并 how=‘outer’:补NaN

  • 左合并、右合并:how=‘left’,how=‘right’,

============================================

练习17:

  1. 考虑应用情景,使用多种方式合并ddd与ddd4

============================================

6) 列冲突的解决

当列冲突时,即有多个列名称相同时,需要使用on=来指定哪一个列作为key,配合suffixes指定冲突列名

可以使用suffixes=自己指定后缀

============================================

练习18:

假设有两个同学都叫李四,ddd5、ddd6都是张三和李四的成绩表,如何合并?

============================================

知识补充

s1 = Series(["A","B","C","B"])
s1
结果为:
0    A
1    B
2    C
3    B
dtype: object
s1.unique()   #去重
结果为:
array(['A', 'B', 'C'], dtype=object)

作业

3. 案例分析:美国各州人口数据分析

首先导入文件,并查看数据样本

df_abbr = pd.read_csv("./data/state-abbrevs.csv") # csv文件的数据导入后 会变成DataFrame供我们使用
df_areas = pd.read_csv("./data/state-areas.csv") 
df_pop = pd.read_csv("./data/state-population.csv")

合并popu与abbrevs两个DataFrame,分别依据state/region列和abbreviation列来合并。为了保留所有信息,使用外合并。

df_pop2 = pd.merge(df_abbr,df_pop,left_on="abbreviation",right_on="state/region",how="outer")

去除abbreviation的那一列(axis=1)

df_pop3 = df_pop2.drop(labels="abbreviation",axis=1)
df_pop3

查看存在缺失数据的列。使用.isnull().any(),只有某一列存在一个缺失数据,就会显示True。

df_pop3.isnull().any() # isnull()有空值是True 没有空值是False any()只要有True就是True 合在一起使用 就是 这一列中 只要有空值就是true
state            True
state/region    False
ages            False
year            False
population       True
dtype: bool

找到有哪些state/region使得state的值为NaN,使用unique()查看非重复值

df_pop3["state"].isnull() #这是一个序列 有值是False 没有值是True
df_pop3[df_pop3["state"].isnull()] #DataFrame 后面 的中括号 中可以传入 序列 如果序列中是布尔值 False这这一项不取 True就取出这一项
df_pop3[df_pop3["state"].isnull()]["state/region"].unique()
结果为:
array(['PR', 'USA'], dtype=object)

为找到的这些state/region的state项补上正确的值,从而去除掉state这一列的所有NaN!记住这样清除缺失数据NaN的方法!

df_pop3[df_pop3["state"].isnull()]["state"] = "Puerto Rico" # 为了安全不能直接设置值 
temp = df_pop3[df_pop3["state"].isnull()].copy()
temp["state"] = "Puerto Rico"
df_pop3[df_pop3["state"].isnull()] = temp # 不能直接操作值 但是可以把DataFrame赋值给DataFrame
temp2 = df_pop3[df_pop3["state/region"]=="USA"].copy()
temp2["state"]="United States"
df_pop3[df_pop3["state/region"]=="USA"] = temp2
df_pop3.isnull().any()
结果为:
state           False
state/region    False
ages            False
year            False
population       True
dtype: bool
df_pop4 = df_pop3.dropna()  #清除人口中为空的数据  
df_pop4.isnull().any()
结果为:
state           False
state/region    False
ages            False
year            False
population      False
dtype: bool

合并各州人口数据和面积数据areas,使用外合并。

思考一下为什么使用外合并?

df_pop_area = pd.merge(df_pop4,df_areas,how="outer")
df_pop_area.dropna() #清除面积为空的数据

找出2010年的全民人口数据,df.query(查询语句)

df_2010 = df_pop_area.query("year==2010 & ages=='total'")
df_2010.dropna()

对查询结果进行处理,以state列作为新的行索引:set_index

df_2010.set_index("state") 

计算人口密度。注意是Series/Series,其结果还是一个Series。

df_2010 = df_2010.dropna()
dens = df_2010["population"]/df_2010["area (sq. mi)"]

排序,并找出人口密度最高的五个州sort_values()的密度

dens.sort_values().tail(5)

找出人口密度最低的五个州的密度

dens.sort_values().head()

要点总结:

  • 统一用loc()索引
  • 善于使用.isnull().any()找到存在NaN的列
  • 善于使用.unique()确定该列中哪些key是我们需要的
  • 一般使用外合并、左合并,目的只有一个:宁愿该列是NaN也不要丢弃其他列的信息
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值