Создайте новый столбец из двух существующих столбцов, применяя универсальную функцию (x, y), чтобы я мог использовать функцию с различными столбцами - PullRequest
2 голосов
/ 15 апреля 2019

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

Я уже пробовал много способов, следуя существующимпримеры, но каждый раз возникает ошибка.

Я определяю функцию как:

def delta_perc(x,y):
    if y == 0:
        return 0
    else:
        return (x-y)/x*100

и затем пытаюсь применить функцию к моему фрейму данных

ordini["discount"] = ordini.apply(delta_perc(ordini["revenue1"],ordini["revenue2"]), axis=1)

Я ожидал новый столбец, где каждая строка быларезультат применения функции к ordini ["доход1"] и к ордини ["доход2"].

Но я получаю следующую ошибку:

ValueError: Истинное значение ряданеоднозначно.Используйте a.empty, a.bool (), a.item (), a.any () или a.all ().

Я также пытался применить все предложения из здесь , но каждый раз происходит ошибка.

Ответы [ 4 ]

3 голосов
/ 15 апреля 2019

Вы перепутали несколько понятий. Когда вы используете pandas.DataFrame.applyaxis=1), вы выполняете итерацию по каждой строке и передаете эту строку (как объект pandas.Series) функции, которую вы использовали, когда вызывали apply.

Первая точка отказа

Вместо этого вы вызываете свою функцию внутри apply и передаете в нее два столбца. Это передаст возвращаемое значение функции в apply. Поскольку ваша функция не передает обратно вызываемый объект, это должно завершиться ошибкой.

Вторая точка отказа

Кроме того, ваша функция предназначена для просмотра скалярных значений, следовательно, if y == 0:, и когда вы передаете столбец, такой как ordini["revenue1"] (который является pandas.Series объектом), он пытается оценить if pandas.Series == 0:, и именно это генерирует ошибка, которую вы видите:

ValueError: The truth value of a Series is ambiguous.

Подход № 1

Исправьте свою функцию и не используйте apply

def delta_perc(x, y):
    return x.sub(y).div(x).mask(x == 0, 0).mul(100)

ordini["discount"] = delta_perc(ordini["revenue1"], ordini["revenue2"])

Подход № 2

Исправьте свою функцию и используйте map. Это было бы похоже на использование понимания.

def delta_perc(x, y):
    if x == 0:
        return 0
    else:
        return (x - y) / x * 100

ordini["discount"] = [*map(delta_perc, ordini["revenue1"], ordini["revenue2"])]

Подход № 3

На самом деле, используя apply

def delta_perc(x, y):
    if x == 0:
        return 0
    else:
        return (x - y) / x * 100

# Because remember `apply` takes a function that gets a row (or column) passed to it
ordini["discount"] = ordini.apply(
    lambda row: delta_perc(row['revenue1'], row['revenue2']),
    axis=1
)
2 голосов
/ 15 апреля 2019

Вы также можете попробовать:

ordini["discount"] = [delta_perc(a,b) for a,b in zip(ordini["revenue1"],ordini["revenue2"])]
2 голосов
/ 15 апреля 2019

Вы должны применить этот расчет ко всей серии с np.where:

import pandas as pd
import numpy as np

def delta_perc(x, y):
    return np.where(y != 0, (x-y)/x*100, 0)
    # I think you may want when x != 0, since you divide by x: 
    #return np.where(x != 0, (x-y)/x*100, 0)

Пример:

np.random.seed(12)
df = pd.DataFrame(np.random.randint(0,10,(10,2)))

df['new_col'] = delta_perc(df[0], df[1])
#   0  1     new_col
#0  6  1   83.333333
#1  2  3  -50.000000
#2  3  0    0.000000
#3  6  1   83.333333
#4  4  5  -25.000000
#5  9  2   77.777778
#6  6  0    0.000000
#7  5  8  -60.000000
#8  2  9 -350.000000
#9  3  4  -33.333333
1 голос
/ 15 апреля 2019

Вы пробовали добавить lambda внутрь apply, как это?

ordini["discount"] = ordini.apply(
    lambda x: delta_perc(x["revenue1"], x["revenue2"]), axis=1
)

Попробуйте, если производительность важна для вас.

import numpy as np

delta_perc_vec = np.vectorize(delta_perc)
ordini["discount"] = delta_perc_vec(df["revenue1"].values, df["revenue2"].values)
...