• 小白学 Python 数据分析(13):Pandas (十二)数据表拼接


    人生苦短,我用 Python

    前文传送门:

    小白学 Python 数据分析(1):数据分析基础

    小白学 Python 数据分析(2):Pandas (一)概述

    小白学 Python 数据分析(3):Pandas (二)数据结构 Series

    小白学 Python 数据分析(4):Pandas (三)数据结构 DataFrame

    小白学 Python 数据分析(5):Pandas (四)基础操作(1)查看数据

    小白学 Python 数据分析(6):Pandas (五)基础操作(2)数据选择

    小白学 Python 数据分析(7):Pandas (六)数据导入

    小白学 Python 数据分析(8):Pandas (七)数据预处理

    小白学 Python 数据分析(9):Pandas (八)数据预处理(2)

    小白学 Python 数据分析(10):Pandas (九)数据运算

    小白学 Python 数据分析(11):Pandas (十)数据分组

    小白学 Python 数据分析(12):Pandas (十一)数据透视表(pivot_table)

    引言

    说到数据表拼接,就不得不提一下 SQL ,对于熟悉 SQL 的同学来讲,这并不是一个难以理解的概念,数据表之间的关系可以分为以下这三种:

    一对一

    两个表之间的公共列是一对一的。

    这里的示例我们就不用图片了,直接使用代码来做展示,原因嘛就是小编懒的画了:

    import pandas as pd
    
    df1 = pd.read_excel("table_join_exp.xlsx", sheet_name='Sheet1')
    print(df1)
    
    # 输出内容
        编号  姓名  分数
    0  100  小明  96
    1  200  小红  48
    2  300  小王  72
    3  400  小刚  72
    
    df2 = pd.read_excel("table_join_exp.xlsx", sheet_name='Sheet2')
    print(df2)
    
    # 输出内容
        编号  班级
    0  100   1
    1  200   2
    2  300   3
    3  400   4
    

    这里可以很直观的看到,这两个表的编号是公共列,并且唯一对应。

    如果我们要讲这两个表进行连接操作,需要使用 merge() 方法:

    print(pd.merge(df1, df2))
    
    # 输出内容
        编号  姓名  分数  班级
    0  100  小明  96   1
    1  200  小红  48   2
    2  300  小王  72   3
    3  400  小刚  72   4
    

    在我们使用 merge() 方法的时候, merge() 方法会自动寻找两个表中的公共列,并且自动的进行对应操作。

    一对多

    两个表之间的公共列不是一对一的,而是其中一个表的公共列是唯一的,另一个表的公共列则会有重复的数据。

    import pandas as pd
    
    df1 = pd.read_excel("table_join_exp.xlsx", sheet_name='Sheet1')
    print(df1)
    
    # 输出内容
        编号  姓名  分数
    0  100  小明  96
    1  200  小红  48
    2  300  小王  72
    3  400  小刚  72
    
    df3 = pd.read_excel("table_join_exp.xlsx", sheet_name='Sheet3')
    print(df3)
    
    # 输出内容
        编号   分数
    0  100  101
    1  100  102
    2  100  103
    3  100  104
    4  200  201
    5  200  202
    6  300  301
    7  400  401
    

    从上面这两个 df 中可以看到, df1 中的编号在 df3 中会对应多条数据,我们在对这两个 df 进行连接操作的时候,需要使用属性 on 指明判断的条件:

    print(pd.merge(df1, df3, on='编号'))
    
    # 输出内容
        编号  姓名  分数_x  分数_y
    0  100  小明    96   101
    1  100  小明    96   102
    2  100  小明    96   103
    3  100  小明    96   104
    4  200  小红    48   201
    5  200  小红    48   202
    6  300  小王    72   301
    7  400  小刚    72   401
    

    多对多

    两个表之间的公共列都是会有重复数据的,相当于是多个一对多。

    注意理解多个一对多,这里的逻辑稍微有点绕,小编在第一次接触 SQL 的时候实际上是无法理解的。

    我们这里新建一个 df4 ,新增一个编号为 100 的小黑,还是通过编号对 df4 和 df3 进行连接操作:

    df4 = pd.read_excel("table_join_exp.xlsx", sheet_name='Sheet4')
    print(df4)
    
    # 输出结果
        编号  姓名   分数
    0  100  小明   96
    1  100  小黑  100
    2  200  小红   48
    3  300  小王   72
    4  400  小刚   72
    
    print(pd.merge(df4, df3, on='编号'))
         编号  姓名  分数_x  分数_y
    0   100  小明    96   101
    1   100  小明    96   102
    2   100  小明    96   103
    3   100  小明    96   104
    4   100  小黑   100   101
    5   100  小黑   100   102
    6   100  小黑   100   103
    7   100  小黑   100   104
    8   200  小红    48   201
    9   200  小红    48   202
    10  300  小王    72   301
    11  400  小刚    72   401
    

    连接方式

    学过 SQL 的同学都知道, SQL 中连接分为内连接、左连接、右连接和外连接,同样在 Pandas 也是一样的。

    内连接

    内连接就是取两个表中公共的部分,我们重新创建一个 df5 ,在 df5 中只有编号 100 和 200 能和前面的数据保持一致:

    df5 = pd.read_excel("table_join_exp.xlsx", sheet_name='Sheet5')
    print(df5)
    
    # 输出结果
        编号        姓名   分数
    0  100        小明   96
    1  100        小黑  100
    2  200        小红   48
    3  600  想不出来叫啥了1  600
    4  700  想不出来叫啥了2  700
    
    # 内连接
    print(pd.merge(df5, df3, on='编号', how='inner'))
    
    # 输出结果
        编号  姓名  分数_x  分数_y
    0  100  小明    96   101
    1  100  小明    96   102
    2  100  小明    96   103
    3  100  小明    96   104
    4  100  小黑   100   101
    5  100  小黑   100   102
    6  100  小黑   100   103
    7  100  小黑   100   104
    8  200  小红    48   201
    9  200  小红    48   202
    

    这里 how 属性是用来指定连接类型的。

    左连接

    左连接就是已左表为基础,右表像左表上拼数据:

    # 左连接
    print(pd.merge(df5, df3, on='编号', how='left'))
    
    # 输出结果
         编号        姓名  分数_x   分数_y
    0   100        小明    96  101.0
    1   100        小明    96  102.0
    2   100        小明    96  103.0
    3   100        小明    96  104.0
    4   100        小黑   100  101.0
    5   100        小黑   100  102.0
    6   100        小黑   100  103.0
    7   100        小黑   100  104.0
    8   200        小红    48  201.0
    9   200        小红    48  202.0
    10  600  想不出来叫啥了1   600    NaN
    11  700  想不出来叫啥了2   700    NaN
    

    可以看到,在 df5 中,编号 600 和 700 的两条数据在 df3 中没有,所以 分数_y 的值为 NaN 。

    右连接

    右连接正好和上面的左连接相反,已右表为基础,左表往右表上拼数据:

    # 右连接
    print(pd.merge(df5, df3, on='编号', how='right'))
    
    # 输出结果
         编号   姓名   分数_x  分数_y
    0   100   小明   96.0   101
    1   100   小黑  100.0   101
    2   100   小明   96.0   102
    3   100   小黑  100.0   102
    4   100   小明   96.0   103
    5   100   小黑  100.0   103
    6   100   小明   96.0   104
    7   100   小黑  100.0   104
    8   200   小红   48.0   201
    9   200   小红   48.0   202
    10  300  NaN    NaN   301
    11  400  NaN    NaN   401
    

    外连接

    外连接就是两个表的并集:

    # 外连接
    print(pd.merge(df5, df3, on='编号', how='outer'))
    
    # 输出结果
         编号        姓名   分数_x   分数_y
    0   100        小明   96.0  101.0
    1   100        小明   96.0  102.0
    2   100        小明   96.0  103.0
    3   100        小明   96.0  104.0
    4   100        小黑  100.0  101.0
    5   100        小黑  100.0  102.0
    6   100        小黑  100.0  103.0
    7   100        小黑  100.0  104.0
    8   200        小红   48.0  201.0
    9   200        小红   48.0  202.0
    10  600  想不出来叫啥了1  600.0    NaN
    11  700  想不出来叫啥了2  700.0    NaN
    12  300       NaN    NaN  301.0
    13  400       NaN    NaN  401.0
    

    纵向拼接

    顾名思义,纵向拼接就是在纵向上对两个表进行拼接,当然这需要两个表具有相同的结构,前面我们介绍的拼接方式都在横向上进行拼接。

    这里我们再加入一个 df6 ,使用 df5 和 df6 演示纵向拼接,在 Pandas 中使用纵向拼接使用的方法是 concat()

    df6 = pd.read_excel("table_join_exp.xlsx", sheet_name='Sheet6')
    print(df6)
    
    # 输出结果
        编号       姓名   分数
    0  800  起个名字好难啊  100
    1  900  起个名字真的难  200
    
    # 纵向拼接
    print(pd.concat([df5, df6]))
    
    # 输出结果
        编号        姓名   分数
    0  100        小明   96
    1  100        小黑  100
    2  200        小红   48
    3  600  想不出来叫啥了1  600
    4  700  想不出来叫啥了2  700
    0  800   起个名字好难啊  100
    1  900   起个名字真的难  200
    

    当我们使用 concat() 以后,发现索引还是保留了原有的索引,看着很不舒服,这时我们可以设置参数 ignore_index ,让其不在保留原有索引,而是生成新的索引:

    print(pd.concat([df5, df6], ignore_index=True))
    
    # 输出结果
        编号        姓名   分数
    0  100        小明   96
    1  100        小黑  100
    2  200        小红   48
    3  600  想不出来叫啥了1  600
    4  700  想不出来叫啥了2  700
    5  800   起个名字好难啊  100
    6  900   起个名字真的难  200
    

    本篇的分享到这里就算结束,如果有 SQL 基础的同学看起来应该毫无压力,没有基础的同学推荐自己动手试一下,很多看着不是很理解的东西一动手就立马打通任督二脉。

    示例代码

    老规矩,所有的示例代码都会上传至代码管理仓库 Github 和 Gitee 上,方便大家取用。

    示例代码-Github

    示例代码-Gitee

  • 相关阅读:
    Structured Streaming watermark总结
    技术实践第三期|HashTag在Redis集群环境下的使用
    元宇宙带来沉浸式智能登录?你学会了吗?
    技术实践第一期|友盟+开发者平台Node.js重构之路
    2021年度友盟+ APP消息推送白皮书:工作日68点通勤时间消息送达率每日最高
    技术实践第二期|Flutter异常捕获
    注意啦!还没有支持64位系统的App开发者,务必在12月底前完成这件事!
    一位大牛对于写技术博客的一些建议
    国内常用源开发环境换源(flutter换源,python换源,Linux换源,npm换源)
    初识Socket通讯编程(一)
  • 原文地址:https://www.cnblogs.com/babycomeon/p/12432957.html
Copyright © 2020-2023  润新知