2016-02-09 2 views
1

Допустит, один имеет DataFrame df1 с INDEX, Column1, Column2 и другим df2 с INDEX, Column1, Column3.Как сделать обновление только на части DataFrame

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

Мне сказали сделать следующие другими пользователями:

df1.update(df2, join='left', overwrite=True) 

Это работает, если оба INDEXES имеют одинаковые значения. В результате будет df1 теперь иметь INDEX, Column1 (от df2) и Column2 (оригинал от df1). Column3 не добавлен к df1 (это поведение требуется по сравнению с командой «merge», которая добавляет все).

Теперь я хотел бы обновить df1 только в нескольких случаях и на основе Column2. Я думал, что это сработает:

df1[df1['Column2'] == 'Cond'].update(df2, join='left', overwrite=True) 

Но это не так; иногда я получаю сообщение об ошибке, другая команда работает, но значения ALL df1 были изменены.

Любая идея о том, как это сделать?

PS: Использование .loc не будет работать, так как это требует, чтобы любой ИНДЕКС, который вы ищете, существует, и это не так.

EDIT: Дополнительный пример

In [37]: df1 = pd.DataFrame([['USA',1],['USA',2],['USA',3],['FRA',1],['FRA',2]], columns = ['country', 'value']) 

In [38]: df2 = pd.DataFrame([['USA',10],['FRA',20]], columns = ['country', 'value']) 

In [39]: df1 = df1.set_index('country') 

In [40]: df2 = df2.set_index('country') 

In [41]: mask = df1['value'] >= 2 

In [42]: idx = df1.index[mask] 

In [43]: idx = idx.unique() 

In [44]: df1 
Out[44]: 
     value 
country 
USA   1 
USA   2 
USA   3 
FRA   1 
FRA   2 

In [45]: df2 
Out[45]: 
     value 
country 
USA   10 
FRA   20 

In [46]: idx 
Out[46]: array(['USA', 'FRA'], dtype=object) 

In [47]: df1.update(df2.loc[idx]) 

In [48]: df1 
Out[48]: 
     value 
country 
USA   10 
USA   10 
USA   10 
FRA   20 
FRA   20 
+1

Вы можете добавить [Minimal, полный и проверяемый пример] (http://stackoverflow.com/help/mcve)? – jezrael

+0

Здравствуйте, jezrael, пример ниже из unutbu - это именно то, что я был после – Yona

ответ

1

Определить булеву маску

mask = (df1['Column2'] == 'Cond') 

Если df1.indexявляется идентичным к df2.index, то mask может быть использован для выбора строки из df2 - то есть, df2.loc[mask]. Но если они не совпадают, то df2.loc[mask] может поднять ошибку (если len(df1) != len(df2)), или, что еще хуже, тихо выбрать неправильные строки , потому что булева маска не выравнивает значения индекса между df1 и df2.

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

Если df1.index является уникальным затем вызвать df1.update на ограниченных df2:

idx = df1.index[mask] 
df1.update(df2.loc[idx]) 

Например,

import pandas as pd 
df1 = pd.DataFrame({'Column1':[1,2,3], 'Column2':['Cond',5,'Cond']}, index=['A','B','C']) 
# Column1 Column2 
# A  1 Cond 
# B  2  5 
# C  3 Cond 

df2 = pd.DataFrame({'Column1':[10,20,30], 'Column3':[40,50,60]}, index=['D','B','C']) 
# Column1 Column3 
# D  10  40 
# B  20  50 
# C  30  60 

mask = df1['Column2'] == 'Cond' 
idx = df1.index[mask] 
df1.update(df2.loc[idx]) 
print(df1) 

гравюр

Column1 Column2 
A  1 Cond 
B  2  5 
C  30 Cond 

Если df1.index не является уникальным, а затем сделать индекс уникальным, добавив к нему mask:

df1['mask'] = df1['value'] >= 2 
df2['mask'] = True 
df1 = df1.set_index('mask', append=True) 
df2 = df2.set_index('mask', append=True) 

Затем вызов df1.update(df2) производит желаемый результат, поскольку update выравнивает показатели.

Например,

import pandas as pd 

df1 = pd.DataFrame([['USA',1],['USA',2],['USA',3],['FRA',1],['FRA',2]], 
        columns = ['country', 'value']) 
df2 = pd.DataFrame([['USA',10],['FRA',20]], columns = ['country', 'value']) 
df1 = df1.set_index('country') 
#   value 
# country  
# USA   1 
# USA   2 
# USA   3 
# FRA   1 
# FRA   2 

df2 = df2.set_index('country') 
#   value 
# country  
# USA   10 
# FRA   20 

df1['mask'] = df1['value'] >= 2 
df2['mask'] = True 
df1 = df1.set_index('mask', append=True) 
#    value 
# country mask   
# USA  False  1 
#   True  2 
#   True  3 
# FRA  False  1 
#   True  2 

df2 = df2.set_index('mask', append=True) 
#    value 
# country mask  
# USA  True  10 
# FRA  True  20 

df1.update(df2) 
df1.index = df1.index.droplevel('mask') 
print(df1) 

уступает

  value 
country  
USA   1 
USA   10 
USA   10 
FRA   1 
FRA   20 
+0

Спасибо за этот Unutbu! – Yona

+0

Что касается случая, когда, например, индекс имеет значения повторения. Представьте, что у меня была страна в качестве индекса, поэтому это могут быть «США, США, США, FRA», а затем «COL1» будет «Cond, 10, 20, Cond, Cond». Моя маска будет '[США, FRA]' и поэтому влияет на все записи. – Yona

+1

Не могли бы вы построить полный пример и какой должен быть желаемый результат? – unutbu

Смежные вопросы