【问题标题】:pandas dataframe split values in one row by weights熊猫数据框按权重将值拆分为一行
【发布时间】:2020-04-12 00:23:58
【问题描述】:

这似乎是一个基本问题,但一个优雅的解决方案正在逃避我。

我有一个 pandas 数据框,其中所有值都已分配到一行中。但是,我需要按权重在多行中拆分值。此处示例:

输入数据框:

import pandas as pd

# starting df with weights W.
df_input = pd.DataFrame({
    'W': [0.3, 0.2, 0.5],
    'X1': [100, 0, 0],
    'X2': [150, 0, 0],
    'X3': [200, 0, 0],
    'X4': [300, 0, 0]
})

所需的输出数据帧:

df_output = pd.DataFrame({
    'W': [0.3, 0.2, 0.5],
    'X1': [30, 20, 50],
    'X2': [45, 30, 75],
    'X3': [60, 40, 100],
    'X4': [90, 60, 150]
})

屏幕截图:

【问题讨论】:

    标签: python pandas dataframe split weighted


    【解决方案1】:

    纯熊猫解决方案:

    df_output = df_input.copy()
    df_output.loc[:, 'X1':] = df_output.loc[:, 'X1':].apply(lambda col: col[0] * df_output['W'])
    

    或者使用 numpy 广播:

    df_output = df_input.copy()
    df_output.loc[:, 'X1':] = df_output.loc[0, 'X1':].values[None, :] * df_output['W'].values[:, None]
    

    【讨论】:

    • 这不会通过零分配值 - 因此产品不会产生输出所需的内容。如果你添加一个max(col) 那么它工作得很好!
    • 这适用于 W=0.3 的第一行,但 df_output 中其他行的 X1:X4 仍然为 0。
    • 谢谢 - 它有效。尽管我也从其他每个答案中吸取了教训,但仍将这个作为解决方案投票。
    • 最好使用第一个索引来获取最大值。 +1
    【解决方案2】:

    优雅是主观的 - 一种可能的方法是使用pd.clip

     for col in ['X1', 'X2', 'X3', 'X4']:
         df_input[col] = df_input[col].clip(lower=df_input[col].max())
         df_input[col]*=df_input['W']
    

    结果会如上。

    【讨论】:

    • 在我的主观意见中,这很优雅! :) 它是一种创造性的方式来使用剪辑。与使用填充相比,这有一些优势,因为它不假设第一行是要加权的值。感谢您的帖子!
    【解决方案3】:

    使用DataFrame.ffill 填充列中的值,然后将它们乘以DataFrame.multiply 的因子

    values = df_input.replace(0, np.NaN).ffill()
    df_input.iloc[:, 1:] = values.iloc[:, 1:].mul(df_input['W'], axis=0)
    

    或者我们可以使用numpy,但首先我们必须将数组重塑为(,1)

    values = df_input.replace(0, np.NaN).ffill()
    df_input.iloc[:, 1:] = values.iloc[:, 1:] * values['W'].to_numpy()[:, None]
    
         W    X1    X2     X3     X4
    0  0.3  30.0  45.0   60.0   90.0
    1  0.2  20.0  30.0   40.0   60.0
    2  0.5  50.0  75.0  100.0  150.0
    

    【讨论】:

    • 有这么多好答案,很难选择。我也喜欢这个。感谢您抽出宝贵时间回复!
    【解决方案4】:

    将数据输出到numpy数组,然后计算点积

    • 根据行和列数据创建两个数组
    • 调整数组的形状
    • np.dot两个数组
    import pandas as pd
    import numpy as np
    
    # using your data
    
    # weight
    w = df_input.iloc[:, 0].to_numpy().reshape(len(df_input), 1)
    
    array([[0.3],
           [0.2],
           [0.5]])
    
    # values
    v = df_input.iloc[0, 1:].to_numpy().reshape(1, len(df_input.columns[1:]))
    
    array([[30., 45., 60., 90.]])
    
    # load dot product into a dataframe
    df_out = pd.DataFrame(np.dot(w, v))
    
    # add column names
    df_out.columns = df_input.columns[1:]
    
    # insert W if needed
    df_out.insert(0, 'W', df_input['W'])
    
    # output
       W    X1    X2     X3     X4
     0.3  30.0  45.0   60.0   90.0
     0.2  20.0  30.0   40.0   60.0
     0.5  50.0  75.0  100.0  150.0
    

    【讨论】:

    • 我也喜欢这个解决方案。非常合乎逻辑且易于理解。谢谢!
    【解决方案5】:

    这里是已经提供的优秀答案的替代方案:

    获取仅 x 列:

    x_columns = df_input.filter(like='X').columns
    

    计算(嵌入在 cmets 中的解释):

    df_input.loc[:,x_columns] = (df_input.loc[:,x_columns]
                                #spill the non zero values downwards
                                .replace(0,method='ffill')
                                #multiply by the 'W' column
                                .mul(df_input['W'],axis=0)
                                .astype(int)
                                )
    
    
         W  X1  X2  X3  X4
    0   0.3 30  45  60  90
    1   0.2 20  30  40  60
    2   0.5 50  75  100 150
    

    【讨论】:

    • 不错!我也喜欢这个。请注意,如果非零行不是第一行,则使用 ffill 的方法将需要排序(也许我应该将第二行设为具有值的行:)。完全匹配的奖励积分(甚至将演员添加到 int! - 虽然我不需要)。谢谢你的回答!
    • 是的,感谢您对排序角度的反馈。我们在这里分享想法,这是刺激的一部分
    【解决方案6】:

    如果我理解正确,这只是一个简单的矩阵乘法。 从 (3,1) 矩阵开始,然后乘以 (1,3)。 最终结果将是 (3,3)。如果这种解决方法有任何帮助,请告诉我:

    import numpy as np
    A = np.array([[3,6,7],[5,-3,0]])
    B = np.array([[1,1],[2,1],[3,-1]])
    C = A.dot(B)
    print (C)
    
    Output:
    [[36,-12],
     [-1,  2] 
    

    【讨论】:

    • 嗨 - 感谢您的帖子。由于它与输入和输出不匹配,因此我没有投票。然而,正如其他人所说,它确实让我走上了正轨——使用点积是一个很好的线索。
    猜你喜欢
    • 2021-12-04
    • 2022-07-15
    • 2019-12-28
    • 2017-05-08
    • 1970-01-01
    • 1970-01-01
    • 2018-12-04
    • 1970-01-01
    • 2021-05-10
    相关资源
    最近更新 更多