Почему не работает моя функция «Применить», относящаяся к нескольким столбцам? [закрыто]

239

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

df = DataFrame ({'a' : np.random.randn(6),
                 'b' : ['foo', 'bar'] * 3,
                 'c' : np.random.randn(6)})

и следующая функция

def my_test(a, b):
    return a % b

Когда я пытаюсь применить эту функцию с:

df['Value'] = df.apply(lambda row: my_test(row[a], row[c]), axis=1)

Я получаю сообщение об ошибке:

NameError: ("global name 'a' is not defined", u'occurred at index 0')

Я не понимаю это сообщение, я правильно определил имя.

Я был бы очень признателен за любую помощь по этому вопросу

Обновить

Спасибо за вашу помощь. Я действительно допустил некоторые синтаксические ошибки с кодом, индекс должен быть поставлен ''. Однако я все еще получаю ту же проблему, используя более сложные функции, такие как:

def my_test(a):
    cum_diff = 0
    for ix in df.index():
        cum_diff = cum_diff + (a - df['a'][ix])
    return cum_diff 
Энди
источник
1
Избегайте использования applyкак можно больше. Если вы не уверены, что вам нужно его использовать, скорее всего, нет. Я рекомендую взглянуть на то, когда я хочу использовать pandas apply () в своем коде? ,
cs95
Речь идет о синтаксических ошибках, ссылающихся на столбец данных, и почему функциям нужны аргументы. Что касается вашего второго вопроса, функция my_test(a)не знает, что dfесть, поскольку она не была передана в качестве аргумента (если dfне предполагается, что она глобальная, что было бы ужасной практикой). Вам нужно передать все значения, которые вам понадобятся, внутри функции в качестве аргументов (желательно по порядку), иначе как функция узнает, откуда она dfберется? Кроме того, программирование в пространстве имен, усеянном глобальными переменными, является плохой практикой, поэтому вы не будете ловить подобные ошибки.
SMCI

Ответы:

379

Кажется, вы забыли ''свою строку.

In [43]: df['Value'] = df.apply(lambda row: my_test(row['a'], row['c']), axis=1)

In [44]: df
Out[44]:
                    a    b         c     Value
          0 -1.674308  foo  0.343801  0.044698
          1 -2.163236  bar -2.046438 -0.116798
          2 -0.199115  foo -0.458050 -0.199115
          3  0.918646  bar -0.007185 -0.001006
          4  1.336830  foo  0.534292  0.268245
          5  0.976844  bar -0.773630 -0.570417

Кстати, на мой взгляд, более элегантно выглядит следующий способ:

In [53]: def my_test2(row):
....:     return row['a'] % row['c']
....:     

In [54]: df['Value'] = df.apply(my_test2, axis=1)
waitingkuo
источник
Спасибо, Вы правы, я забыл ''. Однако у меня все та же проблема с более сложной функцией. Я был бы очень признателен за вашу помощь с этим. Спасибо
Энди
5
@ И следуя [53-54], вы можете применять более сложные функции.
Энди Хейден
@ И вы можете определить свою сложную функцию как In [53].
waitkuo
все применяемые стратегии выполняют то же самое? Я новичок в пандах и всегда находил применение немного загадочным, но вашу стратегию в [53-54] мне легко понять (и, надеюсь, помнить) ... на большом столе это так же быстро, как и другая форма применения представлены?
Whytheq
Почему создание отдельного метода считается более элегантным - даже для крошечных методов. Я занимался значительными проектами в python в течение 7 лет, но, вероятно, никогда не будет рассматриваться pythonistaиз-за некоторых перспектив, включая эту.
Джавадба
33

Если вы просто хотите вычислить (столбец a)% (столбец b), вам это не нужно apply, просто сделайте это напрямую:

In [7]: df['a'] % df['c']                                                                                                                                                        
Out[7]: 
0   -1.132022                                                                                                                                                                    
1   -0.939493                                                                                                                                                                    
2    0.201931                                                                                                                                                                    
3    0.511374                                                                                                                                                                    
4   -0.694647                                                                                                                                                                    
5   -0.023486                                                                                                                                                                    
Name: a
herrfz
источник
16
Я знаю, это всего лишь пример, демонстрирующий мою проблему с применением функции к нескольким столбцам
Энди
18

Допустим, мы хотим применить функцию add5 к столбцам 'a' и 'b' в DataFrame df.

def add5(x):
    return x+5

df[['a', 'b']].apply(add5)
Mir_Murtaza
источник
Я получаю следующее сообщение об ошибке при попытке вашего кода. Ошибка типа: («должен быть str, а не int», «произошел в индексе b»), пожалуйста, посмотрите на это.
debaonline4u
Столбец b вашего фрейма данных является столбцом строкового типа или типа объекта, он должен быть целочисленным столбцом, добавляемым с числом.
Мир_Муртаза
Разве изменения не будут применяться только после назначения?
С.Аад
11

Все предложения, приведенные выше, работают, но если вы хотите, чтобы ваши вычисления были более эффективными, вы должны воспользоваться крошечными векторными операциями (как указано здесь) .

import pandas as pd
import numpy as np


df = pd.DataFrame ({'a' : np.random.randn(6),
             'b' : ['foo', 'bar'] * 3,
             'c' : np.random.randn(6)})

Пример 1: цикл с pandas.apply():

%%timeit
def my_test2(row):
    return row['a'] % row['c']

df['Value'] = df.apply(my_test2, axis=1)

Самый медленный пробег длился в 7,49 раза дольше, чем самый быстрый. Это может означать, что промежуточный результат кэшируется. 1000 петель, лучшее из 3: 481 мкс на петлю

Пример 2: векторизация с использованием pandas.apply():

%%timeit
df['a'] % df['c']

Самый медленный пробег занял 458,85 раза дольше самого быстрого. Это может означать, что промежуточный результат кэшируется. 10000 петель, лучшее из 3: 70,9 мкс на петлю

Пример 3: векторизация с использованием массивов NumPy:

%%timeit
df['a'].values % df['c'].values

Самый медленный пробег длился в 7,98 раза дольше, чем самый быстрый. Это может означать, что промежуточный результат кэшируется. 100000 циклов, лучшее из 3: 6,39 мкс на цикл

Таким образом, векторизация с использованием массивов numpy увеличила скорость почти на два порядка.

Блэйн
источник
Результаты меняются еще более резко для больших чисел, например, заменяя 6 на 10K, я получаю 248 мс, 332 мкс, 263 мкс соответственно. Таким образом, оба векторизованных решения намного ближе друг к другу, но не векторизованное решение в 1000 раз медленнее. (проверено на питон-3,7)
Stason
3

Это то же самое, что и в предыдущем решении, но я определил функцию в самом df.apply:

df['Value'] = df.apply(lambda row: row['a']%row['c'], axis=1)
Шаурья Айри
источник
2

Я дал сравнение всех трех, обсужденных выше.

Используя значения

% timeit df ['value'] = df ['a']. values% df ['c']. values

139 мкс ± 1,91 мкс на цикл (среднее ± стандартное отклонение из 7 циклов, 10000 циклов в каждом)

Без ценностей

% timeit df ['value'] = df ['a']% df ['c'] 

216 мкс ± 1,86 мкс на цикл (среднее ± стандартное отклонение из 7 циклов, 1000 циклов в каждом)

Применить функцию

% timeit df ['Value'] = df.apply (лямбда-строка: row ['a']% row ['c'], axis = 1)

474 мкс ± 5,07 мкс на цикл (среднее ± стандартное отклонение из 7 циклов, 1000 циклов в каждом)

Гурсвак Сингх
источник