7

Как применить функцию к двум столбцам DataFrame в Pandas

1

У меня есть функция и датафрейм, определенные следующим образом:

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 ответ(ов)

6

В 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)
4

Вот пример использования метода 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 на этой группе.

1

Простое решение:

df['col_3'] = df[['col_1', 'col_2']].apply(lambda x: f(*x), axis=1)

В данном коде мы используем метод apply для применения функции f ко всем строкам, объединяя значения из столбцов col_1 и col_2. Результат записывается в новый столбец col_3.

0

Интересный вопрос! Вот мой ответ:

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)

Надеюсь, это поможет!

0

Метод, который вам нужен, — это 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 позволяет избежать конфликта типов данных при комбинировании.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь