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


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)

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

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

16
Я знаю, это всего лишь пример, демонстрирующий мою проблему с применением функции к нескольким столбцам
— Энди

18

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

def add5(x):
    return x+5

df[['a', 'b']].apply(add5)

Я получаю следующее сообщение об ошибке при попытке вашего кода. Ошибка типа: («должен быть 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 циклов в каждом)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.