【问题标题】:Python: How to replace only 0 values in a column by multiplication of 2 columns in Dataframe with a loop?Python:如何通过循环将Dataframe中的2列相乘来替换一列中的0值?
【发布时间】:2020-02-23 23:50:40
【问题描述】:

这是我的数据框:

df={'pack':[2,2,2,2], 'a_cost':[10.5,0,11,0], 'b_cost':[0,6,0,6.5]}

应该是这样的:

此时您会发现 a_costb_cost 列有 0,而其他列有值。我希望我的函数遵循这个逻辑......

for i in df.a_cost:
    if i==0:
       b_cost(column):value *(multiply) pack(column):value
       replace 0 with this new multiplied value (example: 6.0*2=12)
for i in df_b.cost:
    if i==0:
       a_cost(column):value /(divide) pack(column):value
       replace 0 with this new divided value (example: 10.5/2=5.25)

我无法弄清楚如何成功编写此逻辑...这是预期的输出:

代码输出:

df={'pack':[2,2,2,2], 'a_cost':[10.5,12.0,11,13.0], 'b_cost':[5.25,6,5.50,6.5]}

非常感谢您的帮助!

【问题讨论】:

    标签: python pandas dataframe for-loop if-statement


    【解决方案1】:
    import numpy as np
    df = pd.DataFrame({'pack':[2,2,2,2], 'a_cost':[10.5,0,11,0], 'b_cost':[0,6,0,6.5]})
    
    df['a_cost'] = np.where(df['a_cost']==0, df['pack']*df['b_cost'], df['a_cost'])
    df['b_cost'] = np.where(df['b_cost']==0, df['a_cost']/df['pack'], df['b_cost'])
    
    print (df)
    #pack  a_cost  b_cost
    #0     2    10.5     5.25
    #1     2    12.0     6.0
    #2     2    11.0     5.50
    #3     2    13.0     6.5
    

    【讨论】:

    • 嗨!所以,你说 .apply 应该被用作最后的手段......你会说如果我使用具有数十万个观察值的数据框 - 你的方法会不那么足智多谋吗?在旁注中,您的输出中似乎 b_cost 没有改变
    • @DGomonov 在速度方面会更快。还编辑了我的答案的输出,因为我没有运行下一行来测试哈哈。
    【解决方案2】:

    IIUC,

    df.loc[df.a_cost.eq(0), 'a_cost'] = df.b_cost * df.pack
    df.loc[df.b_cost.eq(0), 'b_cost'] = df.a_cost / df.pack
    

    你也可以玩maskfillna

    df['a_cost'] = df.a_cost.mask(df.a_cost.eq(0)).fillna(df.b_cost * df.pack)
    df['b_cost'] = df.b_cost.mask(df.b_cost.eq(0)).fillna(df.a_cost / df.pack)
    

    更新如评论,你可以在mask中使用other

    df['a_cost'] = df.a_cost.mask(df.a_cost.eq(0), other=df.b_cost * df.pack)
    

    另请注意,一旦您已经在 a_cost 列中填写了 0,则不需要进行第二次过滤。也就是说,我们可以这样做:

    df['b_cost'] = df.a_cost / df.pack
    

    在这两种方法的第一个命令之后。

    输出:

       pack  a_cost  b_cost
    0     2    10.5    5.25
    1     2    12.0    6.00
    2     2    11.0    5.50
    3     2    13.0    6.50
    

    【讨论】:

    • 我只是快速阅读这篇文章,但是您不能使用mask 的第二个参数而不是fillna 吗?
    • @rafaelc 确实非常正确。以前从未在mask 中使用过other
    • @DGomonov 恕我直言,where(series)mask(~series) 是相同的。对于你的情况,我觉得mask 更具可读性。
    • @DGomonov 如果您在 ycx 的回答中询问 np.wheremask(),我会说 np.where 更快一些。但我更喜欢loc 方法,因为它对我来说更具可读性。
    【解决方案3】:

    试试这个:

    df['a_pack'] = df.apply(lambda x: x['b_cost']*x['pack'] if x['a_cost'] == 0 and x['b_cost'] != 0 else x['a_cost'], axis = 1)
    
    df['b_pack'] = df.apply(lambda x: x['a_cost']/x['pack'] if x['b_cost'] == 0 and x['a_cost'] != 0 else x['b_cost'], axis = 1)
    

    【讨论】:

    • 行得通!谢谢,我肯定需要更熟悉 lambda 函数
    • 请注意,.apply 通常只能作为最后的手段使用,因为它非常耗费资源
    • @ycx AFAIK,不鼓励使用.apply 主要是因为它的速度慢(基本上相当于for 循环),而不是因为资源限制。
    • @QuangHoang 这就是我的意思,但输入方式不同。你是对的。
    • @QuangHoang 感谢分解。但是,在您的情况下,您使用 .where 或 .mask - 如果我使用大型数据集,哪个更好?
    猜你喜欢
    • 2022-10-02
    • 1970-01-01
    • 2018-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-21
    • 1970-01-01
    相关资源
    最近更新 更多