Заменить значения столбцов на основе другого фрейма python pandas - лучший способ?
Примечание: для простоты я использую игрушечный пример, потому что копирование/вставка кадров данных затрудняет переполнение стека (пожалуйста, дайте мне знать, если есть простой способ сделать это).
Есть ли способ объединить значения из одного кадра данных в другой, не получая столбцы _X, _Y? Я хотел бы, чтобы значения в одном столбце заменяли все нулевые значения другого столбца.
df1:
Name Nonprofit Business Education
X 1 1 0
Y 0 1 0 <- Y and Z have zero values for Nonprofit and Educ
Z 0 0 0
Y 0 1 0
df2:
Name Nonprofit Education
Y 1 1 <- this df has the correct values.
Z 1 1
pd.merge(df1, df2, on='Name', how='outer')
Name Nonprofit_X Business Education_X Nonprofit_Y Education_Y
Y 1 1 1 1 1
Y 1 1 1 1 1
X 1 1 0 nan nan
Z 1 1 1 1 1
В предыдущем посте я пробовал комбинировать_F_FIRST и DropNA(), но они не делают работу.
Я хочу заменить нули в df1 значениями в df2. Кроме того, я хочу, чтобы все строки с одинаковыми именами были изменены в соответствии с df2.
Name Nonprofit Business Education
Y 1 1 1
Y 1 1 1
X 1 1 0
Z 1 0 1
(необходимо уточнить: значение в столбце "Бизнес", где имя = Z, должно равняться 0.)
Мое существующее решение делает следующее: я делаю подмножество на основе имен, существующих в df2, а затем заменяю эти значения правильными значениями. Тем не менее, я хотел бы менее хакерский способ сделать это.
pubunis_df = df2
sdf = df1
regex = str_to_regex(', '.join(pubunis_df.ORGS))
pubunis = searchnamesre(sdf, 'ORGS', regex)
sdf.ix[pubunis.index, ['Education', 'Public']] = 1
searchnamesre(sdf, 'ORGS', regex)
Ответы
Ответ 1
Используйте логическую маску из isin
чтобы отфильтровать df и назначить нужные значения строк из rhs df:
In [27]:
df.loc[df.Name.isin(df1.Name), ['Nonprofit', 'Education']] = df1[['Nonprofit', 'Education']]
df
Out[27]:
Name Nonprofit Business Education
0 X 1 1 0
1 Y 1 1 1
2 Z 1 0 1
3 Y 1 1 1
[4 rows x 4 columns]
Ответ 2
В [27]:
Это правильно.
df.loc[df.Name.isin(df1.Name), ['Nonprofit', 'Education']] = df1[['Nonprofit', 'Education']].values
df
Out[27]:
Name Nonprofit Business Education
0 X 1 1 0
1 Y 1 1 1
2 Z 1 0 1
3 Y 1 1 1
[4 строки x 4 столбца]
Вышеупомянутое будет работать только тогда, когда все строки в df1 существуют в df. Другими словами, df должен быть супер-множеством df1
Если у вас есть несколько несоответствующих строк в df в df1, вы должны следовать ниже
Другими словами, df не является надмножеством df1:
df.loc[df.Name.isin(df1.Name), ['Nonprofit', 'Education']] =
df1.loc[df1.Name.isin(df.Name),['Nonprofit', 'Education']].values
Ответ 3
Внимание: в последней версии панд оба ответа выше не работают:
Ответ KSD вызовет ошибку:
df1 = pd.DataFrame([["X",1,1,0],
["Y",0,1,0],
["Z",0,0,0],
["Y",0,0,0]],columns=["Name","Nonprofit","Business", "Education"])
df2 = pd.DataFrame([["Y",1,1],
["Z",1,1]],columns=["Name","Nonprofit", "Education"])
df1.loc[df1.Name.isin(df2.Name), ['Nonprofit', 'Education']] = df2.loc[df2.Name.isin(df1.Name),['Nonprofit', 'Education']].values
df1.loc[df1.Name.isin(df2.Name), ['Nonprofit', 'Education']] = df2[['Nonprofit', 'Education']].values
Out[851]:
ValueError: shape mismatch: value array of shape (2,) could not be broadcast to indexing result of shape (3,)
и ответ EdChum даст нам неверный результат:
df1.loc[df1.Name.isin(df2.Name), ['Nonprofit', 'Education']] = df2[['Nonprofit', 'Education']]
df1
Out[852]:
Name Nonprofit Business Education
0 X 1.0 1 0.0
1 Y 1.0 1 1.0
2 Z NaN 0 NaN
3 Y NaN 1 NaN
Хорошо, он будет работать безопасно только в том случае, если значения в столбце "Имя" уникальны и отсортированы в обоих фреймах данных.
Вот мой ответ:
Способ 1:
df1 = df1.merge(df2,on='Name',how="left")
df1['Nonprofit_y'] = df1['Nonprofit_y'].fillna(df1['Nonprofit_x'])
df1['Business_y'] = df1['Business_y'].fillna(df1['Business_x'])
df1.drop(["Business_x","Nonprofit_x"],inplace=True,axis=1)
df1.rename(columns={'Business_y':'Business','Nonprofit_y':'Nonprofit'},inplace=True)
Способ 2:
df1 = df1.set_index('Name')
df2 = df2.set_index('Name')
df1.update(df2)
df1.reset_index(inplace=True)
Подробнее об обновлении. Имена столбцов обоих фреймов данных, для которых требуется установить индекс, не обязательно должны совпадать перед обновлением. Вы можете попробовать "Имя1" и "Имя2". Кроме того, это работает, даже если другая ненужная строка в df2, которая не будет обновлять df1. Другими словами, df2 не обязательно должен быть супернабором df1.
Пример:
df1 = pd.DataFrame([["X",1,1,0],
["Y",0,1,0],
["Z",0,0,0],
["Y",0,1,0]],columns=["Name1","Nonprofit","Business", "Education"])
df2 = pd.DataFrame([["Y",1,1],
["Z",1,1],
['U',1,3]],columns=["Name2","Nonprofit", "Education"])
df1 = df1.set_index('Name1')
df2 = df2.set_index('Name2')
df1.update(df2)
результат:
Nonprofit Business Education
Name1
X 1.0 1 0.0
Y 1.0 1 1.0
Z 1.0 0 1.0
Y 1.0 1 1.0