Как применить функцию к двум столбцам DataFrame в Pandas
У меня есть функция и датафрейм, определенные следующим образом:
def get_sublist(sta, end):
return mylist[sta:end+1]
df = pd.DataFrame({'ID':['1','2','3'], 'col_1': [0,2,3], 'col_2':[1,4,5]})
mylist = ['a','b','c','d','e','f']
Теперь я хочу применить функцию get_sublist
к колонкам df
'col_1'
и 'col_2'
, чтобы поэлементно вычислить новую колонку 'col_3'
, которая должна выглядеть следующим образом:
ID col_1 col_2 col_3
0 1 0 1 ['a', 'b']
1 2 2 4 ['c', 'd', 'e']
2 3 3 5 ['d', 'e', 'f']
Я попробовал сделать это следующим образом:
df['col_3'] = df[['col_1','col_2']].apply(get_sublist, axis=1)
Однако это приводит к следующей ошибке:
TypeError: get_sublist() missing 1 required positional argument:
Как мне это сделать?
5 ответ(ов)
В Pandas есть удобный и лаконичный способ сделать это в одну строку:
df['col_3'] = df.apply(lambda x: f(x.col_1, x.col_2), axis=1)
Таким образом, f
может быть определенной пользователем функцией, принимающей несколько значений, и вы используете (безопасные) имена столбцов вместо (небезопасных) числовых индексов для доступа к столбцам.
Пример с данными (основанный на вашем вопросе):
import pandas as pd
df = pd.DataFrame({'ID':['1', '2', '3'], 'col_1': [0, 2, 3], 'col_2':[1, 4, 5]})
mylist = ['a', 'b', 'c', 'd', 'e', 'f']
def get_sublist(sta, end):
return mylist[sta:end+1]
df['col_3'] = df.apply(lambda x: get_sublist(x.col_1, x.col_2), axis=1)
Результат выполнения print(df)
будет следующим:
ID col_1 col_2 col_3
0 1 0 1 [a, b]
1 2 2 4 [c, d, e]
2 3 3 5 [d, e, f]
Если ваши имена столбцов содержат пробелы или совпадают с именами существующих атрибутов DataFrame, можно индексировать, используя квадратные скобки:
df['col_3'] = df.apply(lambda x: f(x['col 1'], x['col 2']), axis=1)
Вот пример использования метода apply
для DataFrame, при этом я вызываю его с параметром axis = 1
.
Обратите внимание на то, что вместо того, чтобы пытаться передать две отдельных величины в функцию f
, мы переписываем функцию так, чтобы она принимала объект pandas Series, а затем индексируем Series для получения необходимых значений.
In [49]: df
Out[49]:
0 1
0 1.000000 0.000000
1 -0.494375 0.570994
2 1.000000 0.000000
3 1.876360 -0.229738
4 1.000000 0.000000
In [50]: def f(x):
....: return x[0] + x[1]
....:
In [51]: df.apply(f, axis=1) # передает объект Series по строкам
Out[51]:
0 1.000000
1 0.076619
2 1.000000
3 1.646622
4 1.000000
В зависимости от вашего конкретного случая использования, иногда полезно создать объект group
в pandas, а затем использовать apply
на этой группе.
Простое решение:
df['col_3'] = df[['col_1', 'col_2']].apply(lambda x: f(*x), axis=1)
В данном коде мы используем метод apply
для применения функции f
ко всем строкам, объединяя значения из столбцов col_1
и col_2
. Результат записывается в новый столбец col_3
.
Интересный вопрос! Вот мой ответ:
import pandas as pd
def sublst(row):
return lst[row['J1']:row['J2']]
df = pd.DataFrame({'ID':['1','2','3'], 'J1': [0,2,3], 'J2':[1,4,5]})
print(df)
lst = ['a','b','c','d','e','f']
df['J3'] = df.apply(sublst, axis=1)
print(df)
Вывод:
ID J1 J2
0 1 0 1
1 2 2 4
2 3 3 5
ID J1 J2 J3
0 1 0 1 [a]
1 2 2 4 [c, d]
2 3 3 5 [d, e]
Я изменил названия столбцов на ID, J1, J2, J3, чтобы обеспечить порядок: ID < J1 < J2 < J3, таким образом столбцы отображаются в правильной последовательности.
Еще одна краткая версия:
import pandas as pd
df = pd.DataFrame({'ID':['1','2','3'], 'J1': [0,2,3], 'J2':[1,4,5]})
print(df)
lst = ['a','b','c','d','e','f']
df['J3'] = df.apply(lambda row: lst[row['J1']:row['J2']], axis=1)
print(df)
Надеюсь, это поможет!
Метод, который вам нужен, — это Series.combine
. Однако следует учитывать, что необходимо быть внимательным с типами данных. В вашем примере вы могли бы (как это сделал я, тестируя ответ) наивно вызвать
df['col_3'] = df.col_1.combine(df.col_2, func=get_sublist)
Однако это приведет к ошибке:
ValueError: setting an array element with a sequence.
Как я предполагаю, метод ожидает, что результат будет того же типа, что и серия, вызывающая метод (в данном случае df.col_1
). Тем не менее, следующий код работает:
df['col_3'] = df.col_1.astype(object).combine(df.col_2, func=get_sublist)
В результате вы получите следующий DataFrame:
ID col_1 col_2 col_3
0 1 0 1 [a, b]
1 2 2 4 [c, d, e]
2 3 3 5 [d, e, f]
Это связано с тем, что приведение col_1
к типу object
позволяет избежать конфликта типов данных при комбинировании.
Как выбрать строки из DataFrame на основе значений столбцов?
Создание DataFrame в Pandas путём последовательного добавления строк
Преобразование списка словарей в DataFrame pandas
Объединение двух столбцов текста в DataFrame pandas
Получение списка из заголовков столбцов DataFrame в Pandas