【问题标题】:PANDAS vlookup against series with common index using map使用地图针对具有公共索引的系列进行 PANDAS vlookup
【发布时间】:2017-09-14 06:48:20
【问题描述】:
import pandas as pd
import numpy as np

pb = {"mark_up_id":{"0":"123","1":"456","2":"789","3":"111","4":"222"},"mark_up":{"0":1.2987,"1":1.5625,"2":1.3698,"3":1.3333,"4":1.4589}}

data = {"id":{"0":"K69","1":"K70","2":"K71","3":"K72","4":"K73","5":"K74","6":"K75","7":"K79","8":"K86","9":"K100"},"cost":{"0":29.74,"1":9.42,"2":9.42,"3":9.42,"4":9.48,"5":9.48,"6":24.36,"7":5.16,"8":9.8,"9":3.28},"mark_up_id":{"0":"123","1":"456","2":"789","3":"111","4":"222","5":"333","6":"444","7":"555","8":"666","9":"777"}}

pb = pd.DataFrame(data=pb).set_index('mark_up_id')
df = pd.DataFrame(data=data)

我知道我可以使用类似的东西:

df['mark_up_id'].map(pb['mark_up'])

执行 v 查找。我想将这个返回的加价乘以每个成本和一个公共索引,以产生一个名为价格的新列。

我知道我可以将两者合并然后运行计算。这就是我产生所需输出的方式。我希望能够做到这一点,类似于您遍历字典并使用键在另一个字典中查找值并在循环内执行某种计算的方式。考虑到 PANDAS 数据帧位于字典之上,必须有一种方法可以使用 join/map/apply 的组合来执行此操作,而无需实际连接内存中的两个数据集。

期望的输出:

desired_output = {"cost":{"0":29.74,"1":9.42,"2":9.42,"3":9.42,"4":9.48},"id":{"0":"K69","1":"K70","2":"K71","3":"K72","4":"K73"},"mark_up_id":{"0":"123","1":"456","2":"111","3":"123","4":"789"},"price":{"0":38.623338,"1":14.71875,"2":12.559686,"3":12.233754,"4":12.985704}}
do = pd.DataFrame(data=desired_output)

奖励积分:

解释接受的答案和...之间的区别

pb.loc[df['mark_up_id']]['mark_up'] * df.set_index('mark_up_id')['cost']

以及为什么我从上面派生的以下 lambda 函数遇到错误...

df.apply(lambda x : x['cost']*pb.loc[x['mark_up_id']],axis=1 )

返回一个错误说:

KeyError: ('the label [333] is not in the [index]', u'occurred at index 5')

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    试试

    df['price'] = df['mark_up_id'].map(pb['mark_up']) * df['cost']
    

    你得到

        cost    id  mark_up_id  price
    0   29.74   K69 123         38.623338
    1   9.42    K70 456         14.718750
    2   9.42    K71 111         12.559686
    3   9.42    K72 123         12.233754
    4   9.48    K73 789         12.985704
    

    【讨论】:

    • 这仅在将两个相同长度的系列对象相乘时有效吗?如果索引不同+一个系列更长怎么办。
    • 地图会将 df 中的 mark_up_id 的值映射到 pb 中的 str_price_band 并返回相应的 mark_up 值乘以价格。所以长度不必相同
    • 如果你正在处理 df 中的 mark_up_id 而 pb 中不存在,那么它显然无法找到相应的 mark_up 并返回 NaN。
    • 看起来我比我意识到的更接近!不知道你可以像这样乘以系列。这是在 Pandas 中通过计算执行 vlookup 的最佳方法吗?看来我可以使用 apply + join 等
    • 这个解决方案是矢量化的,绝对比应用更好,是的,你只是一步之遥:)
    【解决方案2】:

    更新:更新问题:

    In [79]: df = df.assign(price=df['mark_up_id'].map(pb['mark_up']) * df['cost']).dropna()
    
    In [80]: df
    Out[80]:
        cost   id mark_up_id      price
    0  29.74  K69        123  38.623338
    1   9.42  K70        456  14.718750
    2   9.42  K71        789  12.903516
    3   9.42  K72        111  12.559686
    4   9.48  K73        222  13.830372
    

    旧答案:

    In [67]: df = df.assign(price=df['mark_up_id'].map(pb['mark_up']) * df['cost'])
    
    In [68]: df
    Out[68]:
        cost   id mark_up_id      price
    0  29.74  K69        123  38.623338
    1   9.42  K70        456  14.718750
    2   9.42  K71        111  12.559686
    3   9.42  K72        123  12.233754
    4   9.48  K73        789  12.985704
    

    【讨论】:

    • 是否可以使用 apply 和 Lamba 函数来做到这一点?
    • @YaleNewman,是的,但它会看起来很丑,而且会更慢......你为什么要这样做?
    • 试图更好地理解底层数据对象的工作方式以及如何相互关联
    • @YaleNewman 我同意 MaxU,它很丑,但是,以防万一你需要它......我添加到我的答案中......
    • @Wen 谢谢!如果你们中的任何一个人能从高层次上解释为什么接受的解决方案比使用应用更快,我将不胜感激:)
    【解决方案3】:

    通过使用merge

    df=df.merge(df1,left_on='mark_up_id',right_index=True)
    df.assign(price=df['cost'].mul(df['mark_up'])).drop('mark_up',1)
    Out[254]: 
        cost   id mark_up_id      price
    0  29.74  K69        123  38.623338
    3   9.42  K72        123  12.233754
    1   9.42  K70        456  14.718750
    2   9.42  K71        111  12.559686
    4   9.48  K73        789  12.985704
    

    如果您确实想要 applylambda :这很丑......真的......

    df.apply(lambda x : x['cost']*df1.loc[x['mark_up_id']],axis=1 )
    

    改成(更丑...T_T)

    df.apply(lambda x :x['cost']*df1.loc[x['mark_up_id']] if pd.Series(x['mark_up_id']).isin(df1.index)[0] else np.nan,axis=1 )
    

    【讨论】:

      【解决方案4】:
      df['price'] = df['cost'] * df['mark_up_id'].map(pb['markup'])
      

      现在df 将成为您想要的输出。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-03-02
        • 2019-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-18
        • 2020-01-01
        相关资源
        最近更新 更多