根据几个条件将列从一个数据帧映射到另一个数据帧,以考虑存在的多个映射中的一个映射

Posted

技术标签:

【中文标题】根据几个条件将列从一个数据帧映射到另一个数据帧,以考虑存在的多个映射中的一个映射【英文标题】:Mapping columns from one dataframe to another based on few conditions to consider one mapping out of multiple mappings present 【发布时间】:2021-09-29 18:13:59 【问题描述】:

我有两个数据框 A 和 B 有一个公共列“标签”。我想在数据框 A 中创建一个新列“地图”,其中包含来自数据框 B 的相应映射。

必要条件:

    每次映射时,将变量计数加 1(将与数据帧 B 中的“容量”列进行比较) 'label' 列的映射应基于数据帧 B 中 'Num' 列的较高值来完成。此外,如果计数变得大于 'Capacity' 以进行下一次分配,则分配次佳的 'Num' 映射,依此类推. 如果没有可用映射或可用映射的“容量”已满,则将“映射”更新为无

数据框 A

   Id     label
    1      1       
    2      1       
    3      1     
    4      2 
    5      2     
    6      3
    7      3

数据框 B

label   Capacity  Map Num
  1        1       A   0.1
  1        2       B   0.2
  2        2       C   0.3
  3        1       D   0.2

预期的输出数据帧

   Id     label   Map
    1      1       B
    2      1       B
    3      1       A
    4      2       C
    5      2       C
    6      3       D
    7      3       None

任何pythonic方式。我希望能对代码进行一些解释。

【问题讨论】:

有任何答案解决了您的问题吗? 【参考方案1】:

假设您的初始数据帧是:

>>> dfa
   Id  label
0   1      1
1   2      1
2   3      1
3   4      2
4   5      2
5   6      3
6   7      3

>>> dfb
   label  Capacity Map  Num
0      1         1   A  0.1
1      1         2   B  0.2
2      2         2   C  0.3
3      3         1   D  0.2

首先,从重构一点数据帧开始。我们计算 dfa 的 cumcount 和 dfb 的 cumsum。这为我们提供了可以按地图顺序分配多少行,并具有累积限制。

dfa['count'] = dfa.groupby('label').cumcount()+1

dfb.sort_values(by='Num', ascending=False, inplace=True)
dfb['count'] = dfb.groupby('label')['Capacity'].cumsum()

然后我们定义一个自定义函数来进行映射。 try/except 块处理没有行可用于映射的情况,函数将返回None

def custom_map(s):
    try:
        return (dfb[dfb['label'].eq(s['label']) &  # same label
                    dfb['count'].ge(s['count'])    # within capacity
                   ].iloc[0]['Map'])               # take first element
    except IndexError:
        pass

最后,我们使用以下方法映射值:

dfa['Map'] = dfa.apply(custom_map, axis=1)
dfa.drop('count', axis=1)

输出:

   Id  label   Map
0   1      1     B
1   2      1     B
2   3      1     A
3   4      2     C
4   5      2     C
5   6      3     D
6   7      3  None

【讨论】:

【参考方案2】:

我试图复制提到的数据框。我的方法是首先按“Num”对“B”数据帧进行排序,然后按“容量”排序。然后循环“A”数据框,我能够选择正确的“地图”标签并减少可用容量。

import pandas as pd
        
        dfA = pd.DataFrame()
        dfA["Id"] = [1,2,3,4,5,6,7

]
    dfA["label"] = [1,1,1,2,2,3,3]
    
    dfB = pd.DataFrame()
    dfB["label"] = [1,1,2,3]
    dfB["cap"] = [1,2,2,1]
    dfB["map"] = ["A","B","C","D"]
    dfB["num"] = [0.1,0.2,0.3,0.2]
     
    
    test = dfB.copy()
    test = test.sort_values(by = ['num', "cap"], ascending = [False, False], na_position = 'first')
    
    
    map_list = []
    
    for index, row in dfA.iterrows():
        currLabel = row["label"]
        x = test.loc[test['label'] == currLabel]
        if len(x):
            foundMap = False
            for i,r in x.iterrows():
                if r["cap"] > 0:
                    test.at[i,"cap"] = r["cap"]-1
                    map_list.append(r["map"])
                    foundMap = True
                    break
            if not foundMap:
                map_list.append(None)
        else:
            map_list.append(None)
            
    dfA["map"] = map_list

您也可以在 dfB 中创建一个新列,而不是创建 dfB 的副本,这将保持实时容量。

【讨论】:

以上是关于根据几个条件将列从一个数据帧映射到另一个数据帧,以考虑存在的多个映射中的一个映射的主要内容,如果未能解决你的问题,请参考以下文章

将列从一个数据帧合并到另一个数据帧(left_join不起作用) - rstudio

在scala中将列从一个数据帧添加到另一个数据帧[重复]

根据来自不同数据帧的行名将列从另一个数据帧复制到

Pandas:根据条件将值从一个数据帧合并到另一个数据帧

如何根据多个条件将 1 个 pandas 数据帧合并或组合到另一个数据帧

根据 pandas df 中的多个条件映射不同的数据帧