【问题标题】:Looping trough pandas dataframe efficiently有效循环熊猫数据框
【发布时间】:2020-07-05 07:25:44
【问题描述】:

我有 2 个数据框,

  • 来自我的后端 (df_be) 的一个,带有时间戳、id 和 id_type(id_type 标识 ID 字段上的 ID 的类型,可以是盒子/设备/帐户。如果是盒子/设备,则会显示一个 mac 地址,如果是帐户,则会显示一个帐号。
  • 一个来自另一个数据帧 (df_sa),其中包含两列 (sa, mac_stb),其中包含所有 mac 地址和所有存在的客户帐户之间的所有对应关系。

我需要做的是,对于在 df_be 中找到的每个客户账户(这些账户在开始时没有 mac 地址),我需要在 df_sa 中搜索对应关系,并在 df_be 上添加一个包含所有对应 mac 的列地址。下面的代码已经完成了这项工作,但是非常非常非常低效。我一直在为此寻找解决方案,因为这不适合我拥有的大量信息。

非常感谢您!

# Iterate through df_be with mac_stb = NaN
for i in np.arange(sum(df_be['mac_stb'].isnull())):
    # Get account number when mac_stb = NaN
    account = df_be[df_be['mac_stb'].isnull()].iloc[i]['id']

    # Copy row with mac_stb = NaN so that you can replace it later by the appropriates mac_stb
    new_df_be_row = df_be[df_be['mac_stb'].isnull()][df_be['id'] == account].copy()

    # Iterate through mac_stb associated with account id
    for mac in df_sa.loc[df_sa['sa'] == account]['mac_stb']:
        new_df_be_row['mac_stb'] = mac
        df_be = df_be.append(new_df_be_row, ignore_index=True)

# Drop rows with mac_stb = NaN as these have been replaced with possible mac_stb
df_be.dropna(subset=['mac_stb'], inplace=True)
df_be.reset_index(drop=True, inplace=True)

原始数据:

    timestamp               time_ms id              id_type mac_stb
720 2019-07-07 17:16:06.304 18.0    641269DD04B1    boxId   641269DD04B1
721 2019-07-07 17:16:06.291 9.0     98F7D7198F88    boxId   98F7D7198F88
722 2019-07-07 17:16:06.291 6.0     A0C5624B2D79    boxId   A0C5624B2D79
723 2019-07-07 17:16:06.288 18.0    7085C6AAB849    device  7085C6AAB849
724 2019-07-07 17:16:06.304 18.0    S828093664      account NaN
725 2019-07-07 17:16:06.319 4.0     707630BC92E7    boxId   707630BC92E7
726 2019-07-07 17:16:06.319 8.0     S827336056      account NaN
727 2019-07-07 17:16:06.320 9.0     707630BC8FA8    device  707630BC8FA8
728 2019-07-07 17:16:06.340 9.0     S831286437      account NaN
729 2019-07-07 17:16:06.335 13.0    S841512815      account NaN

    mac_stb         mac_cm          sa
0   001E690D2C83    001E690D2C82    S827336056
1   001E690D2D8F    001E690D2D8E    S831286437
2   001E690D311D    001E690D311C    S841512815
3   001E690D4053    001E690D4052    S830161775
4   001E690D4B91    001E690D4B90    S825327910

忽略 mac_cm

重要更新: 对于每个帐户,可能存在多个 mac_stb,因此对于 BE 中的每个请求,它必须显示所有可能的 mac_stb,如果有多个,则应添加一个新行,其中第二个/第三个 mac_stb 可用。

示例: This is the example of df_be before populating mac_stb

This is the example of df_sa with mac correspondence

This is the example of what should look like the rows which have client accounts after being populated with mac_stb from df_sa

【问题讨论】:

  • 感谢您的解释和代码 - 真正有帮助的是您的数据框与您的预期输出以将问题情境化。阅读minimal reproducible example
  • 贴了一些例子的图片
  • 可以添加原始数据吗?将其粘贴到代码块中,目前的问题不可重现。
  • 抱歉,这是我在此类论坛上的第一篇文章。更新!希望现在没事。但在这种情况下,df_sa 对于某种相关性来说太短了,我无法上传 1000000 行 xD。

标签: pandas loops dataframe iterator


【解决方案1】:

您可以使用合并。它可能看起来相当复杂,但本质上它与您的解决方案非常相似。掩码替换您的第一个循环,merge() 替换第二个循环。剩下的只是清理。

mask_no_mac_stb = df_be['mac_stb'].isnull()
df_merged = pd.merge(df_be[mask_no_mac_stb], df_sa, left_on='id', right_on='sa').set_index('id').drop('mac_stb_x', axis=1).rename({'mac_stb_y': 'mac_stb'}, axis=1)
df_be = df_be.set_index('id')
df_be.loc[df_merged.index, 'mac_stb'] = df_merged.loc[df_merged.index, 'mac_stb']
df_be = df_be.reset_index()

更新:

如果不能保证所有 id 都是唯一的,可以使用 dict 并应用:

mask_no_mac_stb = df_be['mac_stb'].isnull()
map_id2mac = {id: mac for (id, mac) in zip(df_sa['sa'].to_list(), df_sa['mac_stb'].to_list())}
df_be.loc[mask_no_mac_stb, 'mac_stb'] = df_be.loc[mask_no_mac_stb, 'id'].apply(lambda x: map_id2mac.get(x, np.nan))

提供的原始数据的输出(两种方式相同):

             id     timestamp  time_ms  id_type       mac_stb
0  641269DD04B1  17:16:06.304    18.00    boxId  641269DD04B1
1  98F7D7198F88  17:16:06.291     9.00    boxId  98F7D7198F88
2  A0C5624B2D79  17:16:06.291     6.00    boxId  A0C5624B2D79
3  7085C6AAB849  17:16:06.288    18.00   device  7085C6AAB849
4    S828093664  17:16:06.304    18.00  account           NaN
5  707630BC92E7  17:16:06.319     4.00    boxId  707630BC92E7
6    S827336056  17:16:06.319     8.00  account  001E690D2C83
7  707630BC8FA8  17:16:06.320     9.00   device  707630BC8FA8
8    S831286437  17:16:06.340     9.00  account  001E690D2D8F
9    S841512815  17:16:06.335    13.00  account  001E690D311D

注意:id 7085C6AAB849 的值仍然是 NaN,因为它不在 df_sa 中

【讨论】:

  • 我认为在 df_be 上为帐户类型填充 mac_stb 时出现问题。我了解您的代码,但对于帐户类型,我的输出仍然为空
  • 它给出错误“无法从重复轴重新索引”
  • 它不再给出错误,但它不会填充我的 mac_stb 字段。我的数据框比我放在那里的原始数据大得多。并且所有帐号都关联了 1 个或多个 mac_stb,我需要所有这些。所以我需要在需要时将列添加到 df_be
猜你喜欢
  • 1970-01-01
  • 2020-11-20
  • 2017-10-29
  • 1970-01-01
  • 1970-01-01
  • 2018-08-10
  • 2022-01-08
  • 2017-06-08
相关资源
最近更新 更多