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

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

必要条件:

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

数据框 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方式。我希望能对代码进行一些解释。

【问题讨论】:

  • 有任何答案解决了您的问题吗?

标签: python pandas dataframe mapping


【解决方案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 的副本,这将保持实时容量。

    【讨论】:

      猜你喜欢
      • 2019-10-17
      • 1970-01-01
      • 1970-01-01
      • 2022-01-24
      • 1970-01-01
      • 2017-04-20
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多