Объедините «влево», но по возможности переопределите «правые» значения - PullRequest
5 голосов
/ 03 мая 2019

Цель

Я просмотрел документацию pandas по слиянию , но у меня возник вопрос об эффективном переопределении значений при слиянии «влево». Я могу сделать это просто для одной пары значений (как видно здесь ), но это становится загроможденным при попытке сделать несколько пар.

Настройка

Если я беру следующие кадры данных:

a = pd.DataFrame({
   'id': [0,1,2,3,4,5,6,7,8,9],
    'val': [100,100,100,100,100,100,100,100,100,100]
})

b = pd.DataFrame({
    'id':[0,2,7],
    'val': [500, 500, 500]
})

Я могу объединить их:

df = a.merge(b, on=['id'], how='left', suffixes=('','_y'))

чтобы получить

   id  val  val_y
0   0  100  500.0
1   1  100    NaN
2   2  100  500.0
3   3  100    NaN
4   4  100    NaN
5   5  100    NaN
6   6  100    NaN
7   7  100  500.0
8   8  100    NaN
9   9  100    NaN

Я хочу сохранить левые значения там, где правого значения не существует, но, где это возможно, перезаписать правильные значения.

Мой желаемый результат :

   id    val
0   0  500.0
1   1  100.0
2   2  500.0
3   3  100.0
4   4  100.0
5   5  100.0
6   6  100.0
7   7  500.0
8   8  100.0
9   9  100.0

Моя попытка

Я знаю, что могу сделать это с помощью нескольких строк кода:

df.loc[df.val_y.notnull(), 'val'] = df[df.val_y.notnull()].val_y
df = df.drop(['val_y'], axis = 1)

Или я могу использовать логику из этого вопроса .

Но это становится загроможденным, когда есть несколько пар столбцов, где я хочу применить эту логику.

Например, используя a и b ниже:

a = pd.DataFrame({
   'id': [0,1,2,3,4,5,6,7,8,9],
    'val': [100,100,100,100,100,100,100,100,100,100],
    'val_2':[200, 200, 200, 200, 200, 200, 200, 200, 200, 200]
})
b = pd.DataFrame({
    'id':[0,2,7],
    'val': [500, 500, 500],
    'val_2': [500,500,500]
})

Есть ли более быстрый и чистый способ получить желаемый результат?

Ответы [ 4 ]

5 голосов
/ 04 мая 2019

Я бы сделал это, используя set_index и update:

u = a.set_index('id')
u.update(b.set_index('id'))  # Update a's values with b's values

u.reset_index()

   id    val
0   0  500.0
1   1  100.0
2   2  500.0
3   3  100.0
4   4  100.0
5   5  100.0
6   6  100.0
7   7  500.0
8   8  100.0
9   9  100.0

Обновление выровнено по индексу.По этой причине я устанавливаю «id» в качестве индекса в обоих DataFrames перед выполнением шага обновления.

Обратите внимание, что столбец «id» должен быть уникальным.


Другая опцияиспользует concat и drop_duplicates:

pd.concat([b, a]).drop_duplicates('id').sort_values('id')

   id  val
0   0  500
1   1  100
1   2  500
3   3  100
4   4  100
5   5  100
6   6  100
2   7  500
8   8  100
9   9  100

Поскольку b переопределяет a, b должен идти первым на шаге concat.

3 голосов
/ 04 мая 2019

numpy searchsorted и присвоить

a.iloc[np.searchsorted(a.id,b.id),1]=b.val.values
a
Out[1382]: 
   id  val
0   0  500
1   1  100
2   2  500
3   3  100
4   4  100
5   5  100
6   6  100
7   7  500
8   8  100
9   9  100
2 голосов
/ 04 мая 2019

Отлет с dict

d = dict(a.values)
d.update(dict(b.values))
pd.DataFrame(dict(zip(a, zip(*d.items()))))

   id  val
0   0  500
1   1  100
2   2  500
3   3  100
4   4  100
5   5  100
6   6  100
7   7  500
8   8  100
9   9  100
0 голосов
/ 04 мая 2019

Еще один вариант - выполнить слияние, как вы уже это делаете, затем заполните NaN значения вправо

df

    id  val val_y
0   0   100 500.0
1   1   100 NaN
2   2   100 500.0
3   3   100 NaN
4   4   100 NaN
5   5   100 NaN
6   6   100 NaN
7   7   100 500.0
8   8   100 NaN
9   9   100 NaN

df.fillna(method='ffill', axis=1)

    id  val val_y
0   0.0 100.0   500.0
1   1.0 100.0   100.0
2   2.0 100.0   500.0
3   3.0 100.0   100.0
4   4.0 100.0   100.0
5   5.0 100.0   100.0
6   6.0 100.0   100.0
7   7.0 100.0   500.0
8   8.0 100.0   100.0
9   9.0 100.0   100.0

Затем нарежьте только последний столбец с помощью iloc[:,-1]

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