Datawhale组队学习(Pandas) task6-连接

第六章 连接

目录

  • 1. 关系型连接
    • 1.1 连接基本概念
    • 1.2 值连接
    • 1.3 索引连接
  • 2. 方向连接
    • 2.1 concat
    • 2.2 序列与表的合并
  • 3. 类连接操作
    • 3.1 比较
    • 3.2 组合
  • Ex1:美国疫情数据集
  • Ex2:实现join函数

1. 关系型连接

1.1 连接基本概念

将两张相关的表按照某一个或某一组键连接起来,关键要素是连接形式,其中连接形式包含:

  • 左连接 left:以左边的键为准,若右表中的键 出现于左表,则将改键添加到左表。否则处理为缺失值。
  • 右连接 right:类似处理
  • 内连接 inner:合并两边同时出现的键
  • 外连接 out:又叫全连接,在内连接基础上也包含仅在单侧表中出现的键。

1.2 值连接

根据某一列连接
Datawhale组队学习(Pandas) task6-连接_第1张图片
连接不具备相同列名的表
Datawhale组队学习(Pandas) task6-连接_第2张图片
连接两个出现相同列名的表
Datawhale组队学习(Pandas) task6-连接_第3张图片
指定多个列作为on参数
Datawhale组队学习(Pandas) task6-连接_第4张图片
validate 参数
Datawhale组队学习(Pandas) task6-连接_第5张图片

练一练

上面以多列为键的例子中,错误写法显然是一种多对多连接,而正确写法是一对一连接,请修改原表,使得以多列为键的正确写法能够通过 validate=‘1:m’ 的检验,但不能通过 validate=‘m:1’ 的检验。

df2 = pd.DataFrame({
     'Name':['San Zhang', 'San Zhang'],'Gender':['F', 'M'],'Class':['two', 'two']})
df1.merge(df2, on=['Name', 'Class'], how='left',validate="1:m")
>>>
	Name	Age	Class	Gender
0	San Zhang	20	one	NaN
1	San Zhang	21	two	F
2	San Zhang	21	two	M

df1.merge(df2, on=['Name', 'Class'], how='left',validate="m:1")
>>> MergeError: Merge keys are not unique in right dataset; not a many-to-one merge

1.3 索引连接

要实现类似merge 多列为键 的操作,join需要使用 多级索引

df1 = pd.DataFrame({
     'Age':[20,21]},index=pd.MultiIndex.from_arrays([['San Zhang', 'San Zhang'],['one', 'two']],names=('Name','Class')))
df1

df2 = pd.DataFrame({
     'Gender':['F', 'M']},index=pd.MultiIndex.from_arrays([['San Zhang', 'San Zhang'],['two', 'one']],names=('Name','Class')))
df2

df1.join(df2)

Datawhale组队学习(Pandas) task6-连接_第6张图片

2. 方向连接

2.1 concat

  • axis 拼接方向,0-纵向拼接多表(常用于多样本拼接),1-横向拼接多表(常用于多字段/特征拼接)
  • join 连接形式,默认状态下join=outer 表示保留所有的列,将不存在的值设为缺失,join=inner 表示 两个表都出现过的列
  • key 在新表中指示来自于哪一张旧表的名字
# 纵向拼接:根据列索引对齐
df1 = pd.DataFrame({
     'Name':['San Zhang','Si Li'],'Age':[20,30]})
df1

Name	Age
0	San Zhang	20
1	Si Li	30
======
df2 = pd.DataFrame({
     'Name':['Wu Wang'], 'Age':[40],'Gender':['F']})
df2

	Name	Age	Gender
0	Wu Wang	40	F
======
pd.concat([df1, df2])

Name	Age	Gender
0	San Zhang	20	NaN
1	Si Li	30	NaN
0	Wu Wang	40	F
# 横向拼接:根据行索引对齐
df2 = pd.DataFrame({
     'Grade':[80, 90]}, index=[1, 2])
pd.concat([df1, df2], 1)
>>>
        Name   Age  Grade
0  San Zhang  20.0    NaN
1      Si Li  30.0   80.0
2        NaN   NaN   90.0

当使用多表直接方向合并时,尤其是横向合并,先用reset_index方法恢复默认整数索引再进行合并,防止出现由索引误对齐和重复索引的笛卡尔积带来的错误结果。

# keys参数 能够表示新表中的数据来自于哪个原表
df1 = pd.DataFrame({
     'Name':['San Zhang','Si Li'],'Age':[20,21]})
df1

Name	Age
0	San Zhang	20
1	Si Li	21
======
df2 = pd.DataFrame({
     'Name':['Wu Wang'],'Age':[21]})
df2

Name	Age
0	Wu Wang	21
======
pd.concat([df1, df2], keys=['one', 'two'])

Datawhale组队学习(Pandas) task6-连接_第7张图片

2.2 序列与表的合并

  • append 将序列追加到行末
  • assign 将序列追加到列末
s = pd.Series(['Wu Wang', 21], index = df1.columns)
df1.append(s, ignore_index=True)

Datawhale组队学习(Pandas) task6-连接_第8张图片

s = pd.Series([80, 90])
df1.assign(Grade=s)

在这里插入图片描述

3. 类连接操作

3.1 比较

Datawhale组队学习(Pandas) task6-连接_第9张图片

  • 两表相同的值会被填充为NaN
  • other 指代传入的参数表
  • self 指代被调用的表自身

3.2 组合

# 选出对应索引位置较小的元素
def choose_min(s1, s2):
    s2 = s2.reindex_like(s1)
    res = s1.where(s1<s2, s2)  # 注意where逻辑,若df1
    res = res.mask(s1.isna())
    return res

df1 = pd.DataFrame({
     'A':[1,2], 'B':[3,4], 'C':[5,6]})
df2 = pd.DataFrame({
     'B':[5,6], 'C':[7,8], 'D':[9,10]}, index=[1,2])

df1.combine(df2, choose_min)

>>>
   A    B    C   D
0 NaN  NaN  NaN NaN
1 NaN  4.0  6.0 NaN
2 NaN  NaN  NaN NaN

练一练

请在上述代码的基础上修改,保留 df2 中4个未被 df1 替换的相应位置原始值。

def choose_min(s1, s2):
    s2 = s2.reindex_like(s1)
    res = s1.where(s1<s2, s2)  # 注意where逻辑,若df1
    # res = res.mask(s1.isna())
    return res
# overwrite=False 可以保留 被调用表 中未出现在传入的参数表中的列
df1.combine(df2, choose_min, overwrite=False)

>>>
    A    B    C   D
0  1.0  NaN  NaN NaN
1  2.0  4.0  6.0 NaN
2  NaN  NaN  NaN NaN

练一练

除了 combine 之外, pandas 中还有一个 combine_first 方法,其功能是在对两张表组合时,若第二张表中的值在第一张表中对应索引位置的值不是缺失状态,那么就使用第一张表的值填充。下面给出一个例子,请用 combine 函数完成相同的功能。

df1.combine(df2, lambda x,y : x.mask(x.isna(), y))

Ex1:美国疫情数据集

Datawhale组队学习(Pandas) task6-连接_第10张图片
我的思路

# zfill() 方法返回指定长度的字符串,原字符串右对齐,前面填充0。
date = date.dt.month.astype('string').str.zfill(2) + '-' + date.dt.day.astype('string').str.zfill(2) + '-' + '2020'
date = date.tolist()

result = pd.DataFrame(columns=['Confirmed', 'Deaths', 'Recovered', 'Active'])

for date_item in date:
    data = pd.read_csv('./data/us_report/%s.csv'%(date_item))
    data = data.set_index('Province_State')
    res = data.loc['New York',['Confirmed', 'Deaths', 'Recovered', 'Active']]
	result = result.append(res,ignore_index=True)
	
result.index = date

Datawhale组队学习(Pandas) task6-连接_第11张图片
哈哈哈哈哈哈哈哈居然和答案写得基本一样

# 答案中的for循环部分
L.append(data.to_frame().T)

# 拼接使用的是 concat,两个表之间的方向连接
res = pd.concat(L)

Ex2:实现join函数

Datawhale组队学习(Pandas) task6-连接_第12张图片

# 想了一下下,然后直接看了答案
def join(df1, df2, how='left'):
    res_col = df1.columns.tolist() +  df2.columns.tolist()
    dup = df1.index.unique().intersection(df2.index.unique())  # 取交集
    res_df = pd.DataFrame(columns = res_col) # 定义结果的df
    for label in dup:
        cartesian = [list(i)+list(j) for i in df1.loc[label].values for j in df2.loc[label].values]  # 两表查询结果拼接
        dup_df = pd.DataFrame(cartesian, index = [label]*len(cartesian), columns = res_col)  # 放入df中
        res_df = pd.concat([res_df,dup_df])  # 两个df拼接,公共部分的拼接结果
    
    # 左连接
    if how in ['left', 'outer']:
        for label in df1.index.unique().difference(dup):  # 取差集,据df1与公共部分的差集作为查询依据
            if isinstance(df1.loc[label], pd.DataFrame):  # 如果是df
                cat = [list(i)+[np.nan]*df2.shape[1] for i in df1.loc[label].values]
            else: cat = [list(i)+[np.nan]*df2.shape[1] for i in df1.loc[label].to_frame().values]
            dup_df = pd.DataFrame(cat, index = [label]*len(cat), columns = res_col)
            res_df = pd.concat([res_df,dup_df])
    
    # 右连接
    if how in ['right', 'outer']:
        for label in df2.index.unique().difference(dup):
            if isinstance(df2.loc[label], pd.DataFrame):
                cat = [[np.nan]+list(i)*df1.shape[1] for i in df2.loc[label].values]
            else: cat = [[np.nan]+list(i)*df1.shape[1] for i in df2.loc[label].to_frame().values]
            dup_df = pd.DataFrame(cat, index = [label]*len(cat), columns = res_col)
            res_df = pd.concat([res_df,dup_df])
            
    return res_df

你可能感兴趣的:(datawhale组队学习,code)