Pandas Python обновляет значение фрейма данных A, если оно найдено в фрейме данных B

#python #pandas #numpy

#питон #pandas #numpy

Вопрос:

У меня есть два фрейма данных: пользователи и устройства. Фрейм данных пользователей представляет собой список всех взаимодействий по идентификатору пользователя и метке времени. Однако, если кто-то использует наше приложение в качестве гостя, его идентификатору пользователя присваивается значение device_id. Если эти гости в конечном итоге становятся участниками, мы сопоставляем их user_id с их device_id в фрейме данных devices.

Итак, у нас есть для пользователей

 user_id                                 timestamp
user13123                               2019-02-17
user224234                              2019-02-17
user32134234                            2019-02-17
00029AD9-X5X5-999N-807F-73F0EAE4A98B    2019-02-17
 

Где последняя строка — это гостевой пользователь, с идентификатором устройства, сохраненным как user_id

Затем для устройств

 device_id                               user_id
00029AD9-X5X5-999N-807F-73F0EAE4A98B    user3423
37029BD9-D5D5-435D-837F-73F0EAE4A98B    user34423
...
 

Что представляет собой простое сопоставление между идентификаторами устройств и известными идентификаторами пользователей

Итак, что я хочу сделать, это проверить, совпадает ли Users.user_id с Devices.device_id , и если да, установите Users.user_id в Devices.user_id . По сути, я хочу обновить все старые гостевые взаимодействия, чтобы использовать user_id, если у нас есть эта информация в Устройствах.

Некоторое время возился с этим, и это становилось все более и более запутанным, и кажется, что это можно было бы решить довольно чисто в pandas. Любая помощь будет очень признательна.

Спасибо!

Комментарии:

1. users.user_id.replace(devices.set_index('device_id')['user_id']) ?? или users.user_id.map(devices.set_index('device_id')['user_id']).fillna(users.user_id) ??

Ответ №1:

Фреймы данных

 In [32]: users
Out[32]:
                                user_id   timestamp
0                             user13123  2019-02-17
1                            user224234  2019-02-17
2                          user32134234  2019-02-17
3  00029AD9-D5D5-435D-807F-73F0EAE4A98B  2019-02-17

In []: devices
Out[]:
                              device_id    user_id
0  00029AD9-D5D5-435D-807F-73F0EAE4A98B   user3423
1  37029BD9-D5D5-435D-837F-73F0EAE4A98B  user34423
 

Вычислить фильтр

Все пользователи, для которых user_id соответствует device_id

 In []: filtr = users.user_id.isin(devices.device_id)

In []: filtr
Out[]:
0    False
1    False
2    False
3     True
Name: user_id, dtype: bool
 

Замените значения

Все отфильтрованные пользователи user_id заменяются соответствующими user_id правами устройства users в фрейме данных.

 In []: users.loc[filtr, "user_id"] = users[filtr].user_id.map(devices.set_index("device_id").user_id)

In []: users
Out[]:
        user_id   timestamp
0     user13123  2019-02-17
1    user224234  2019-02-17
2  user32134234  2019-02-17
3      user3423  2019-02-17
 

Использование np.where

Просто еще один вариант.

 users.loc[:, 'user_id'] = pd.np.where(users.user_id.isin(devices.device_id),
                                      users.user_id.map(devices.set_index('device_id').user_id),
                                      users.user_id)
 

Эти решения ожидают, что user_id для каждого существует только один device_id .

Ответ №2:

левое слияние users с devices , fillna в столбце с левым соединением user_id (это имя as user_id_y ). Наконец, назначьте это обратно столбцу users.user_id

 In [59]: users['user_id'] = users.merge(devices, how='left', left_on='user_id', right_on='device_id')['user_id_y'].fillna(users.user_id)

In [60]: users
Out[60]:
    timestamp       user_id
0  2019-02-17     user13123
1  2019-02-17    user224234
2  2019-02-17  user32134234
3  2019-02-17      user3423
 

Ответ №3:

Это цикл, который будет выполняться, хотя все записи, проверяющие идентификатор пользователя, соответствуют идентификатору устройства, и если это так, он обновит фрейм данных пользователя с правильным идентификатором.

 for i in range(len(Users.index)):
    for p in range(len(Devices.index)):
        if(Users.loc[i,"user_id"] == Devices.loc[p,"device_id"]):
             # Fixed part of the code, check old version.
             Users.loc[i,"user_id"] = Devices.loc[p,"user_id"]
 

Ответ №4:

Это решение находит список совпадающих идентификаторов, затем перебирает один раз и обновляет идентификаторы пользователя, используя его в качестве индекса.

 devices = pd.DataFrame({'device_id':{0:'00029AD9-X5X5-999N-807F-73F0EAE4A98B',1:'37029BD9-D5D5-435D-837F-73F0EAE4A98B'},'user_id':{0:'user3423',1:'user34423'}})
users = pd.DataFrame({'user_id':{0:'user13123',1:'user224234',2:'user32134234',3:'00029AD9-X5X5-999N-807F-73F0EAE4A98B'},'timestamp':{0:'2019-02-17',1:'2019-02-17',2:'2019-02-17',3:'2019-02-17'}})

matching_ids = list(set(users.user_id).intersection(set(devices.device_id)))
for id in matching_ids:
    users.loc[users.user_id == id, 'user_id'] = devices.set_index('device_id').at[id, 'user_id']