根据列值将值从一个数据帧映射到其他数据帧中的新列 - Pandas

jov*_*cbg 6 python mapping dataframe pandas

我从另一个数据帧映射值时遇到问题.

这些是两个数据帧的样本:

DF1

product   class_1   class_2   class_3
141A        11        13         5     
53F4        12        11        18  
GS24        14        12        10   
Run Code Online (Sandbox Code Playgroud)

DF2

id    product_type_0  product_type_1 product_type_2  product_type_3 measure_0 measure_1 measure_2   measure_3
1         141A            GS24             NaN           NaN          1         3           NaN       NaN
2         53F4            NaN              NaN           NaN          1        NaN          NaN       NaN
3         53F4            141A             141A          NaN          2         2            1        NaN
4         141A            GS24             NaN           NaN          3         2           NaN       NaN
Run Code Online (Sandbox Code Playgroud)

我接下来要做的是:我需要添加一个名为"Max_Class_1","Max_Class_2","Max_Class_3"的新列,并且该值将从df1中获取.对于每个订单号(_1,_2,_3),请查看现有列(例如product_type_1)product_type_1,并从产品具有相同值的df1中获取一行.然后查看度量列(例如measure_1),如果值为1(原始数据中可能最多有四个不同的值),则名为"Max_Class_1"的新列将具有与该product_type的class_1相同的值,在本例中为11.

我认为这比我解释的要简单一些.

期望的输出

id    product_type_0  product_type_1 product_type_2  product_type_3  measure_0 measure_1 measure_2  measure_3  max_class_0  max_class_1  max_class_2  max_class_3
1         141A            GS24             NaN         NaN            1         3         NaN        NaN        1           10            NaN NaN
2         53F4            NaN              NaN         NaN            1        NaN        NaN        NaN        12         NaN           NaN  NaN
3         53F4            141A             141A        NaN            2         2         1          NaN        11          13            11  NaN
4         141A            GS24             NaN         NaN            3         2         NaN        NaN        5           12            NaN NaN
Run Code Online (Sandbox Code Playgroud)

我试过的代码:

df2['max_class_1'] = None
df2['max_class_2'] = None
df2['max_class_3'] = None

def get_max_class(product_df, measure_df, product_type_column, measure_column, max_class_columns):
    for index, row in measure_df.iterrows():
        product_df_new = product_df[product_df['product'] == row[product_type_column]]
        for ind, r in product_df_new.iterrows():
            if row[measure_column] == 1:
                row[max_class_columns] = r['class_1']
            elif row[measure_column] == 2:
                row[max_class_columns] = r['class_2']
            elif row[measure_column] == 3:
                row[max_class_columns] = r['class_3']
            else:
                row[tilt_column] = "There is no measure or type"
    return measure_df

# And the function call 
first_class = get_max_class(product_df=df1, measure_df=df2, product_type_column=product_type_1, measure_column='measure_1', max_class_columns='max_class_1')

second_class = get_max_class(product_df=df1, measure_df=first_class, product_type_column=product_type_2, measure_column='measure_2', max_class_columns='max_class_2')

third_class = get_max_class(product_df=df1, measure_df=second_class, product_type_column=product_type_3, measure_column='measure_3', max_class_columns='max_class_3')
Run Code Online (Sandbox Code Playgroud)

我很确定有一个更简单的解决方案,但不知道为什么不起作用.我得到所有无价值,没有任何变化.

jpp*_*jpp 5

pd.DataFrame.lookup 是按行和列标签查找的标准方法.

存在空值会使您的问题变得复杂.但这可以通过修改输入映射数据帧来适应.

步骤1

将列重命名df1为整数并添加额外的行/列.稍后我们将使用添加的数据来处理空值.

def rename_cols(x):
    return x if not x.startswith('class') else int(x.split('_')[-1])

df1 = df1.rename(columns=rename_cols)

df1 = df1.set_index('product')
df1.loc['X'] = 0
df1[0] = 0
Run Code Online (Sandbox Code Playgroud)

您的映射数据框现在看起来像:

print(df1)

          1   2   3  0
product               
141A     11  13   5  0
53F4     12  11  18  0
GS24     14  12  10  0
X         0   0   0  0
Run Code Online (Sandbox Code Playgroud)

第2步

迭代类别的数量和使用pd.DataFrame.lookup.请注意我们如何fillna使用X0,正是我们在步骤1中用于额外的地图数据.

n = df2.columns.str.startswith('measure').sum()

for i in range(n):
    rows = df2['product_type_{}'.format(i)].fillna('X')
    cols = df2['measure_{}'.format(i)].fillna(0).astype(int)
    df2['max_{}'.format(i)] = df1.lookup(rows, cols)
Run Code Online (Sandbox Code Playgroud)

结果

print(df2)

   id product_type_0 product_type_1 product_type_2  product_type_3  measure_0  \
0   1           141A           GS24            NaN             NaN          1   
1   2           53F4            NaN            NaN             NaN          1   
2   3           53F4           141A           141A             NaN          2   
3   4           141A           GS24            NaN             NaN          3   

   measure_1  measure_2  measure_3  max_0  max_1  max_2  max_3  
0        3.0        NaN        NaN     11     10      0      0  
1        NaN        NaN        NaN     12      0      0      0  
2        2.0        1.0        NaN     11     13     11      0  
3        2.0        NaN        NaN      5     12      0      0  
Run Code Online (Sandbox Code Playgroud)

你可以转换0np.nan如果需要的话.这是因为考虑int到将你的系列转换为.floatNaNfloat

当然,如果X0是有效值,则可以从一开始就使用替代填充值.