【问题标题】:How to efficiently map entries in a dataframe to dictionary如何有效地将数据框中的条目映射到字典
【发布时间】:2016-02-10 00:09:39
【问题描述】:

长期以来,我一直是 stackoverflow 的粉丝,我发现它非常有用。但是,这一次我觉得有必要就我编写的代码提出一个与性能相关的问题,我希望我能从社区中得到一些有价值的帮助。

我的问题涉及向“users”数据框中的给定用户推荐广告(见下文)的问题,其中“adids”数据框中的每个广告都必须满足某些条件才能被推荐给用户。数据在表格上:

users = pd.DataFrame({"loginid" : [0, 0, 0, 1, 1, 0], 
                  "min_price" : [10, 10, 10, 20, 20, 10], 
                  "max_price" : [30, 30, 30, 40, 40, 30], 
                  "municipal" : ["a", "b", "c", "d", "e", "e"] })

广告数据框如下所示:

adids = pd.DataFrame({"adid" : [100, 101, 102, 103, 104, 105], 
                  "totalprice" : [11., 15, 15, 25, 35, 25], 
                  "municipal" : ["a", "a", "d", "d", "e", "d"]})

我想要(有效地)实现的是过滤给定用户(即给定登录 ID)的相关广告。目前,我正在填充一个名为“adsdict”的字典,其中键是用户的登录 ID,值是所有推荐的 adid。如果“totalprice”在用户的最高和最低价格范围之间(由“min_price”和“max_price”给出)并且用户也与市政当局匹配,则推荐使用广告。下面的代码实现了这一点,但是,我不确定我这样做的效率如何。在我非常大的完整数据集(10^6++ 行的顺序)上,这部分绝对是我在时间消耗方面的瓶颈。

adsdict = {}

unique_logins = np.unique(users.loginid)
for logid in unique_logins:
    row_indexer = (users.loginid == logid)
    user = users[row_indexer]
    max_price = user.ix[row_indexer, "max_price"].max()
    min_price = user.ix[row_indexer, "min_price"].min()
    row_indexer_2 = (adids.totalprice >= min_price) \
                                & (adids.totalprice <= max_price)    
    ads = adids.loc[row_indexer_2, ["adid", "municipal"]]
    adsdict[logid] = list( pd.merge(user, ads, on="municipal").adid.values )

在我的玩具数据集上,输出变为:

0: [100, 101], 1: [103, 105, 104]}

这是期望的结果。但是,如前所述,我担心他们编写此代码的方式效率低下,因为我必须为每个登录 ID 执行连接操作。

如果更有经验的 python 用户(我使用 python 3.4,带有 pandas 0.16.2)可以就如何优化它提供建议,我将不胜感激。我对各种(快速!)解决方案持开放态度,但内存也是一个因素(尽管我可以访问具有大量内存的服务器,所以这不是目前最关键的问题。)所以,解决方案甚至不需要使用字典,我拥有的唯一标准就是能够查看哪些广告已推荐给给定用户(登录名)。

提前致谢。

问候,

马格纳斯

附言。在此处发布问题时,我已尝试遵循最佳实践。如果我没有提供必要的信息,请提前道歉。

【问题讨论】:

    标签: python python-3.x dictionary optimization pandas


    【解决方案1】:

    所以首先你需要从ads 中找到匹配的municipalusers,你可以简单地通过合并两个框架来做到这一点,这就是你满足第一个条件的方式

    In [15]:
    match_minicipal_df = pd.merge(users , adids , on = 'municipal')
    match_minicipal_df
    Out[15]:
    loginid    max_price    min_price   municipal   adid    totalprice
    0               30          10          a       100         11
    0               30          10          a       101         15
    1               40          20          d       102         15
    1               40          20          d       103         25
    1               40          20          d       105         25
    1               40          20          e       104         35
    0               30          10          e       104         35
    

    那么为了满足您的第二个条件,即 total 应该介于 minmax 值之间,您可以这样做

    In [32]:
    match = np.logical_and(match_minicipal_df.totalprice > match_minicipal_df.min_price , match_minicipal_df.totalprice < match_minicipal_df.max_price)
    match
    Out[32]:
    0     True
    1     True
    2    False
    3     True
    4     True
    5     True
    6    False
    dtype: bool
    

    根据您的条件分割dataframe 的最后一步

    In [33]:
    match_minicipal_df[match]
    Out[33]:
    loginid max_price     min_price municipal   adid    totalprice
    0           30              10      a       100         11
    0           30              10      a       101         15
    1           40              20      d       103         25
    1           40              20      d       105         25
    1           40              20      e       104         35
    

    如你所见

    In [53]:
    match_minicipal_df.ix[match ,['loginid' , 'adid'] ]
    Out[53]:
    loginid adid
    0       100
    0       101
    1       103
    1       105
    1       104
    

    【讨论】:

    • 非常感谢纳德,非常感谢。回答也很快。
    猜你喜欢
    • 2016-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    • 1970-01-01
    • 1970-01-01
    • 2021-01-01
    • 2021-07-14
    相关资源
    最近更新 更多