pandas中的关系型连接操作
把两张相关的表按照某一个或某一组键连接起来是一种常见操作。在关系型连接中,键是十分重要的,往往用on
参数表示。
在pandas
中的关系型连接函数merge
和join
中提供了how
参数来代表连接形式,分为左连接left
、右连接right
、内连接inner
、外连接outer
,它们的区别如下:
- 左连接即以左表的键为准,如果右表中的键于左表存在,那么就添加到左表,否则则处理为缺失值,右连接类似处理。
- 内连接只负责合并两边同时出现的键,而外连接则会在内连接的基础上包含只在左边出现以及只在右边出现的值,因此外连接又叫全连接。
如果出现重复的键,九一笛卡尔积的方式加入:
显然在不同的场合应该使用不同的连接形式。其中左连接和右连接是等价的,由于它们的结果中的键是被一侧的表确定的,因此常常用于有方向性地添加到目标表。内外连接两侧的表,经常是地位类似的(左右表位置的交换不引起结果的变化),想取出键的交集或者并集,具体的操作还需要根据业务的需求来判断。
左连接:
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')
如果两个表中想要连接的列不具备相同的列名,可以通过left_on
和right_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')
如果两个表中的列出现了重复的列名,那么可以通过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'])
在某些时候出现重复元素是麻烦的,例如两位同学来自不同的班级,但是姓名相同,这种时候就要指定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')
184. 部门工资最高的员工 - 力扣(LeetCode)
查找出每个部门中薪资最高的员工。
按 任意顺序 返回结果表。注:点开
Pandas Schema
可以看到测试的准备数据。使用这个可以在本地编程。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')
查看当前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
根据“如无必要,勿增实体”,同时也发现仅使用departmentId
、Employee
和salary
这个三个属性也可以完成操作,因此简化DataFrame:
df = df[['name_y', 'name_x', 'salary']].rename(
columns={'name_y':'Department', 'name_x':'Employee'}
)
得到:
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)
得到:
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
Joyful-Pandas-课程详情 | Datawhale