Изменения значений в столбце датафрейма в соответствии с условием
Функция изменяет весь столбец датафрейма на одно и то же значение, игнорируя, что условия по строкам - разные. Или дает ошибку, если через .apply
Дайте, пожалуйста, совет на тему как правильно применить функцию через apply() в моей задаче, чтобы получить корректный результат.
Имеются 2 датафрейма Pandas с 'a','b','c' колонками. Я хочу изменить некоторые значения в 'c'-колонке для второго датафрейма df_2. Причем, нужно изменить данные в df_2 для 'c'-колонки только в тех строках, где 'a' равно 1. Значение 0 в ячейках этих строк в 'c'-колонках должны измениться на медиану, посчитанную от значений в 'c'-колонке первого датафрейма по строкам, где 'a' равно 1. Я написал функцию, которая делает это. Она применяется к df_2 и использует df_1.
Проблема в следующем:
Если применить функцию вот так: 'df_2['c'] = set_c(df_1, df_2)', то все 'c'-значения df_2 получают новую цену, и неважно, в данной строке 'a' == 1 или нет. Это неправильно.
Если применить функцию так: 'df_2['c'] = df_2.apply(set_c(df_2, df_1))', возникает ошибка без дополнительных комментариев: 'AssertionError:'.
Код такой:
import pandas as pd
df_1 = pd.DataFrame({'a': [1,2,1], 'b': [4,5,6], 'c': [7,100,9]}) # From C
df_2 = pd.DataFrame({'a': [1,2,3], 'b': [4,50,6], 'c': [0,0,0]}) # To C
display('df_1', df_1)
display('df_2', df_2)
def set_c(df1, df2):
mask = ( df1.loc[:, 'a'] == df2.loc[0, 'a'] )
final_c = df1[mask]['c'].median()
display("df2.loc[0, 'a']", df2.loc[0, 'a'])
display('df1[mask]', df1[mask])
print('final_c median', final_c)
return final_c
df_2['c'] = set_c(df_1, df_2)
display(df_2)
В коде df_2 и df_1 - это глобальные датафреймы вне функции, а df2 and df1 - датафреймы внутри функции, передаваемые как параметры.
Моя функция показывает весь процесс расчетов. Для варианта 1 получается следующее:
'df_1'
a b c
0 1 4 7
1 2 5 100
2 1 6 9
'df_2'
a b c
0 1 4 0
1 2 50 0
2 3 6 0
"df2.loc[0, 'a']" # 'a'=1 - основа маски для 0 строки
1
'df1[mask]' # Строки df_1 с 'a'=1 найдены!
a b c
0 1 4 7
2 1 6 9
final_c median 8.0 # Медиана по 'c' для df1 между 7 и 9 = 8
'df_2 result'
a b c
0 1 4 8.0
1 2 50 8.0
2 3 6 8.0
Могли бы вы показать мне, как правильно применить функцию через apply(), чтобы осуществились построчные расчеты и результирующий df_2 обрел бы такой вид, в котором новая ячейка колонки 'c' = 8.0 была бы только в строке [0], так как только в строке [0] в df_2 есть 'a'=1, чтобы в строке [1] возникло 100 ('a'=2 есть в df_1, единственное число по 'c' = 100), и чтобы в строке [2] остался 0, так как 'a'=3 есть в df_2, но нет в df_1, поэтому медиану не считаем:
'df_2 result'
a b c
0 1 4 8.0
1 2 50 100.0
2 3 6 0
Большое спасибо!
Ответы (1 шт):
я бы сделал так:
сначала получаем соответствия между колонками a в обоих фреймах:
mapper = df_1.loc[df_2["a"].isin(df_1["a"])]["c"]
затем делаем замену во втором фрейме
df_2["c"] = df_2.apply(lambda x: mapper.loc[x.name]
if x.name in mapper.index else x["c"], axis=1)
а потом присваиваем вашу медиану по заданному условию:
df_2.loc[df_2["a"]==1, "c"] = df_1.loc[df_1["a"]==1, "c"].median()
получаем df_2:
a b c
0 1 4 8
1 2 50 100
2 3 6 0