Циклический цикл pandas эффективно - PullRequest
0 голосов
/ 24 марта 2020

У меня есть 2 кадра данных,

  • один с моего бэкэнда (df_be) с меткой времени, id и id_type (id_type определяет тип идентификатора в поле идентификатора, который может быть полем / устройство / учетная запись. Если это поле / устройство, ему отображается ма c адрес, если это учетная запись, ему показан номер учетной записи.
  • один из другого фрейма данных (df_sa), который содержит два столбца (sa, mac_stb) со всем соответствием между всеми адресами ma c и всеми существующими учетными записями клиентов.

Что мне нужно сделать, так это для каждой учетной записи клиента, найденной в df_be (у этого нет ma c адресов в начале), мне нужно найти корреспонденцию в df_sa и добавить столбец в df_be со всеми соответствующими адресами ma c. Код ниже уже делает свою работу, но очень очень очень неэффективен. Я искал решение для этого, так как это не подходит для того объема информации, который у меня есть.

Заранее большое спасибо!

# 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)

Необработанные данные: * 101 4 *

    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

IGNORE mac_cm

ВАЖНОЕ ОБНОВЛЕНИЕ: для каждой учетной записи можно использовать более одного mac_stb, поэтому для каждого запроса в BE должны быть показаны все возможные mac_stb, если есть больше чем один, он должен добавить новую строку со вторым / третьим доступным mac_stb.

Примеры: Это пример df_be перед заполнением mac_stb

This это пример df_sa с ма c соответствием

Это пример того, как должны выглядеть строки, имеющие учетные записи клиентов после заполнения mac_stb из df_sa

1 Ответ

0 голосов
/ 25 марта 2020

Вы можете использовать слияние. Это может выглядеть довольно сложно, но по сути это очень похоже на ваше решение. Маска заменяет ваш первый l oop, а merge () заменяет второй l oop. Остальное просто убирает.

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()

ОБНОВЛЕНИЕ:

Если вы не можете гарантировать, что все идентификаторы уникальны, вы можете использовать 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

Примечание. Значение для идентификатора 7085C6AAB849 по-прежнему равно NaN, поскольку оно отсутствует в df_sa

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...