Функция lamba с if else

У меня есть фрейм данных, который выглядит так:

A   B   C   D   SUM 
2   5   -4  12  15

Я пытаюсь запустить:

df.apply((lambda x: x / x.sum() if x/x.sum() >= 0 else None), axis=1).fillna(0)

чтобы получить, если ячейка в целом такая же, вычислите x / total:

A         B     C   D
2/15    5/15    0   12/15

Я получил:

'The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

Как я могу улучшить код.

что должен вернуть x/x.sum()?

Liora Haydont 10.08.2018 17:33

Почему бы просто не проверить, отрицательное число или нет? x/x.sum() когда-либо будет отрицательным, только если x < 0 или x.sum() < 0? Вам даже не понадобится функция lambda. Вы можете заменить все отрицательные значения в Dataframe на None и также установить строки, сумма которых <0, на None.

vielkind 10.08.2018 17:36

x / x.sum (): значение в ячейке, деленное на сумму значений во всех ячейках строки.

Mutenda Tshipala 10.08.2018 17:37

Это не проблема if/else или lambda, а проблема того, как последовательность значений должна рассматриваться как логическое значение.

chepner 10.08.2018 17:37

Что означает «если ячейка в целом такая же»?

FatihAkici 10.08.2018 17:51

Это то, чего вы пытаетесь достичь: «Как я могу разделить положительные значения на значение столбца SUM и присвоить 0 отрицательным?»

FatihAkici 10.08.2018 17:54

FWIW немного странно включать отрицательные числа как часть суммы строки, обнуляя их дробные вклады. Не неслыханно, просто редко. Обычно вы либо сохраняете их в обоих, либо игнорируете их в обоих.

DSM 10.08.2018 17:55

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

Mutenda Tshipala 10.08.2018 17:59
1
8
62
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы путаете pd.Series.apply и pd.DataFrame.apply. Это разные методы: один работает над серией и работает с каждым элементом; другой работает во фрейме данных вдоль оси. В последнем случае axis=1 означает, что каждый строка передается в функцию последовательно.

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

df2 = df.copy()

for col in df.columns[:-1]:
    df2[col] = df.iloc[:, :-1].apply(lambda x: x[col] / x.sum() if x[col]/x.sum() >= 0 \
                                     else None, axis=1).fillna(0)

print(df2)

          A         B  C    D  SUM
0  0.133333  0.333333  0  0.8   15

Однако все это очень неэффективно. Мы не используем базовые массивы NumPy. Вместо этого вы можете использовать векторизованные операции:

res = df.iloc[:, :-1].div(df.iloc[:, :-1].sum(1), axis=0)
res.mask(res < 0, 0, inplace=True)

print(res)

          A         B    C    D
0  0.133333  0.333333  0.0  0.8

Другие вопросы по теме