根据列值-熊猫

时间:2018-07-10 13:44:55

标签: python pandas dataframe mapping

我在映射另一个数据框的值时遇到问题。

这些是两个数据帧的示例:

df1

product   class_1   class_2   class_3
141A        11        13         5     
53F4        12        11        18  
GS24        14        12        10   

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

接下来我要获得的是:  我需要添加一个名为“ 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

我尝试过的代码:

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')

我很确定有一个简单的解决方案,但是不知道为什么不起作用。我得到所有None值,什么都没有改变。

1 个答案:

答案 0 :(得分: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

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

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

第2步

迭代类别数并使用pd.DataFrame.lookup。请注意,我们如何fillnaX0一起使用,这正是我们在步骤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)

结果

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  

如果需要,可以将0转换为np.nan。这将以将您的系列从int转换为float为代价,因为NaN被认为是float

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