Python - применение пользовательской функции к строковым столбцам не работает - PullRequest
0 голосов
/ 09 апреля 2020

Допустим, у меня есть этот набор игрушечных данных

import pandas as pd

df = pd.DataFrame({
    'animal': ['lama', 'cow', 'lama', 'beetle', 'lama', 'hippo'],
    'num': range(6)
})

, и я создаю две простые пользовательские функции (одну для строкового столбца animal, одну для числового c столбца num), который я позже будет использовать функцию apply. Такими функциями являются

def fn_num(x):
    if x['num'] >= 5:
        return 1
    elif x['num'] <= 1:
        return 0
    else:
        return -1

def fn_animal(x):
    if x['animal'].isin(['cow', 'hippo']):
        return 1
    elif x['animal'].str.contains('ee'):
        return 0
    else:
        return -1

, где аргумент x должен быть pandas DataFrame, например, объект df.

Позже я использую их в apply функция ( Я знаю, что это не самый оптимизированный код с точки зрения эффективности, но я предпочитаю оставить его таким образом для ясности )

df.apply(fn_num, axis=1)

0    0
1    0
2   -1
3   -1
4   -1
5    1
dtype: int64



df.apply(fn_animal, axis=1)

AttributeError: ("'str' object has no attribute 'isin'", 'occurred at index 0')

Функция fn_num, примененный к столбцу цифр c, работает нормально, тогда как функция fn_animal, примененная к столбцу строк, возвращает ошибку. Однако если я напишу код вне пользовательской функции, я не получу ошибок с атрибутом isin:

df['animal'].isin(['cow', 'hippo'])

0    False
1     True
2    False
3    False
4    False
5     True
Name: animal, dtype: bool



df['animal'].str.contains('ee')

0    False
1    False
2    False
3     True
4    False
5    False
Name: animal, dtype: bool

Мой желаемый результат будет:

df.apply(fn_animal, axis=1)

0   -1
1    1
2   -1
3    0
4   -1
5    1
dtype: int64

Я потратил довольно какой-то тип в этом вопросе, и я уверен, что мне не хватает чего-то очень глупого, но я не мог понять это. Что я могу сделать, чтобы функция fn_animal работала внутри apply?

Ответы [ 3 ]

1 голос
/ 09 апреля 2020

Ошибка говорит сама за себя, вы применяете функции pandas к строковым объектам, а не к Dataframe, поэтому просто используйте стандартный оператор in для проверки строки или подстроки.

Обновленный код:

import pandas as pd

df = pd.DataFrame({
    'animal': ['lama', 'cow', 'lama', 'beetle', 'lama', 'hippo'],
    'num': range(6)
})

def fn_num(x):
    if x['num'] >= 5:
        return 1
    elif x['num'] <= 1:
        return 0
    else:
        return -1

def fn_animal(x):
    if x['animal'] in (['cow', 'hippo']):
        return 1
    elif 'ee' in x['animal']:
        return 0
    else:
        return -1

print(df.apply(fn_num, axis=1))




print(df.apply(fn_animal, axis=1))

Out:

0    0
1    0
2   -1
3   -1
4   -1
5    1
dtype: int64
0   -1
1    1
2   -1
3    0
4   -1
5    1
dtype: int64

1 голос
/ 09 апреля 2020

Объекты, передаваемые в функцию, являются объектами серии в соответствии с параметром индекса. Таким образом, x['animal'] является str

Код модификации tp fn_animal():

def fn_animal(x):
    if x['animal'] in ['cow', 'hippo']:
        return 1
    elif 'ee' in x['animal']:
        return 0
    else:
        return -1

Цитирование документации

DataFrame .apply (self, fun c, axis = 0, raw = False, result_type = None, args = (), ** kwds) [source] ¶ Применить функцию вдоль оси DataFrame.

Объекты, передаваемые в функцию, являются объектами Series, индекс которых является либо индексом DataFrame (axis = 0), либо столбцами DataFrame (axis = 1). По умолчанию (result_type = None) окончательный тип возвращаемого значения определяется на основе типа возвращаемого значения применяемой функции. В противном случае это зависит от аргумента result_type.

1 голос
/ 09 апреля 2020

Проблема в том, что в функции применения x является серией и больше не является фреймом данных. Из-за этого x[y] является скалярным значением, либо число c (и fn_num работает нормально, x['num'] это число), либо простая строка.

То есть в fn_animal, x['animal'] - простая строка, в которой нет метода isin: ошибка нормальная.

...