问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

pandas中的关系型连接操作详解

创作时间:
作者:
@小白创作中心

pandas中的关系型连接操作详解

引用
CSDN
1.
https://blog.csdn.net/qq_63432403/article/details/145427907

在数据分析和处理中,经常需要将两个或多个数据表按照某些键进行连接操作。pandas作为Python中最常用的数据分析库之一,提供了强大的关系型连接功能。本文将详细介绍pandas中的merge和join函数,帮助读者掌握不同连接方式的使用场景和技巧。

关系型连接基础

在关系型连接中,是十分重要的,往往用on参数表示。在pandas中的关系型连接函数mergejoin中提供了how参数来代表连接形式,分为左连接left、右连接right、内连接inner、外连接outer,它们的区别如下:

  • 左连接即以左表的键为准,如果右表中的键于左表存在,那么就添加到左表,否则则处理为缺失值,右连接类似处理。
  • 内连接只负责合并两边同时出现的键,而外连接则会在内连接的基础上包含只在左边出现以及只在右边出现的值,因此外连接又叫全连接。

如果出现重复的键,会以笛卡尔积的方式加入:

显然在不同的场合应该使用不同的连接形式。其中左连接和右连接是等价的,由于它们的结果中的键是被一侧的表确定的,因此常常用于有方向性地添加到目标表。内外连接两侧的表,经常是地位类似的(左右表位置的交换不引起结果的变化),想取出键的交集或者并集,具体的操作还需要根据业务的需求来判断。

左连接示例

import pandas as pd

df1 = pd.DataFrame({'Name':['San Zhang','Si Li'], 'Age':[20,30]})
df2 = pd.DataFrame({'Name':['Si Li','Wu Wang'], 'Gender':['F','M']})
df = df1.merge(df2, on='Name', how='left')
print(df)

指定连接键

如果两个表中想要连接的列不具备相同的列名,可以通过left_onright_on指定:

df1 = pd.DataFrame({'df1_name':['San Zhang','Si Li'], 'Age':[20,30]})
df2 = pd.DataFrame({'df2_name':['Si Li','Wu Wang'], 'Gender':['F','M']})
df = df1.merge(df2, left_on='df1_name', right_on='df2_name', how='left')
print(df)

处理重复列名

如果两个表中的列出现了重复的列名,那么可以通过suffixes参数指定。例如合并考试成绩的时候,第一个表记录了语文成绩,第二个是数学成绩:

df1 = pd.DataFrame({'Name':['San Zhang'],'Grade':[70]})
df2 = pd.DataFrame({'Name':['San Zhang'],'Grade':[80]})
df = df1.merge(df2, on='Name', how='left', suffixes=['_Chinese','_Math'])
print(df)

处理重复元素

在某些时候出现重复元素是麻烦的,例如两位同学来自不同的班级,但是姓名相同,这种时候就要指定on参数为多个列使得正确连接:

df1 = pd.DataFrame({'Name':['San Zhang', 'San Zhang'],
                    'Age':[20, 21],
                    'Class':['one', 'two']})
df2 = pd.DataFrame({'Name':['San Zhang', 'San Zhang'],
                    'Gender':['F', 'M'],
                    'Class':['two', 'one']})
df = df1.merge(df2, on=['Name', 'Class'], how='left')
print(df)

实战案例:部门工资最高的员工

查找出每个部门中薪资最高的员工。按任意顺序返回结果表。

准备数据

data = [[1, 'Joe', 70000, 1], [2, 'Jim', 90000, 1], [3, 'Henry', 80000, 2], [4, 'Sam', 60000, 2], [5, 'Max', 90000, 1]]
employee = pd.DataFrame(data, columns=['id', 'name', 'salary', 'departmentId']).astype({'id':'Int64', 'name':'object', 'salary':'Int64', 'departmentId':'Int64'})
data = [[1, 'IT'], [2, 'Sales']]
department = pd.DataFrame(data, columns=['id', 'name']).astype({'id':'Int64', 'name':'object'})

解题思路

有两个表,首先要进行合并,因此先用merge进行合并:

df = employee.merge(department, left_on='departmentId', right_on='id', how='left')
print(df) # 输出结果

查看当前DataFrame结构:

  id_x name_x  salary  departmentId  id_y name_y
0     1    Joe   70000             1     1     IT
1     2    Jim   90000             1     1     IT
2     3  Henry   80000             2     2  Sales
3     4    Sam   60000             2     2  Sales
4     5    Max   90000             1     1     IT

根据“如无必要,勿增实体”,同时也发现仅使用departmentIdEmployeesalary这个三个属性也可以完成操作,因此简化DataFrame:

df = df[['name_y', 'name_x', 'salary']].rename(
    columns={'name_y':'Department', 'name_x':'Employee'}
)
print(df) # 输出结果

得到:

 Department Employee  salary
0         IT      Joe   70000
1         IT      Jim   90000
2      Sales    Henry   80000
3      Sales      Sam   60000
4         IT      Max   90000

由于要获得每个部门的最大薪资的人,所以要对Department进行分组,同时使用transform使得每个分组中的每一行都会被赋予该分组的最大值。transform的关键特性是它会将每个分组的最大值广播回原始 DataFrame 的形状。也就是说,每个分组中的每一行都会被赋予该分组的最大值。

max_salary_column = df.groupby('Department')['salary'].transform(max)
print(max_salary_column) # 输出结果

得到:

0    90000
1    90000
2    80000
3    80000
4    90000

之后进行布尔判断:

df = df[df['salary'] == max_salary_column]

即得到了该题的求解。

总的思路代码(本地)

import pandas as pd
data = [[1, 'Joe', 70000, 1], [2, 'Jim', 90000, 1], [3, 'Henry', 80000, 2], [4, 'Sam', 60000, 2], [5, 'Max', 90000, 1]]
employee = pd.DataFrame(data, columns=['id', 'name', 'salary', 'departmentId']).astype({'id':'Int64', 'name':'object', 'salary':'Int64', 'departmentId':'Int64'})
data = [[1, 'IT'], [2, 'Sales']]
department = pd.DataFrame(data, columns=['id', 'name']).astype({'id':'Int64', 'name':'object'})
# 左连接
df = employee.merge(department, left_on='departmentId', right_on='id', how='left')
print(df) # 输出结果
# 简化DataFrame,只保留需要的列并改名
df = df[['name_y', 'name_x', 'salary']].rename(
    columns={'name_y':'Department', 'name_x':'Employee'}
)
print(df) # 输出结果
# 按部门分组,找出每个部门的最高工资
max_salary_column = df.groupby('Department')['salary'].transform(max)
print(max_salary_column) # 输出结果
# 保留最高工资的行
df = df[df['salary'] == max_salary_column]
# 输出
print(df)

力扣提交代码

import pandas as pd
def department_highest_salary(employee: pd.DataFrame, department: pd.DataFrame) -> pd.DataFrame:
    df = employee.merge(department, left_on='departmentId', right_on='id', how='left')
    df = df[['name_y', 'name_x', 'salary']].rename(
        columns={'name_y':'Department', 'name_x':'Employee'}
    )
    max_salary_column = df.groupby('Department')['salary'].transform(max)
    df = df[df['salary'] == max_salary_column]
    return df

通过本文的学习,相信读者已经掌握了pandas中关系型连接操作的核心概念和实用技巧。这些知识在实际的数据分析工作中非常有用,能够帮助你更高效地处理和合并数据。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号