Пользовательский алгоритм для работы с отрицательными значениями внутри DataFrame - PullRequest
2 голосов
/ 04 марта 2020

Для начала у меня есть DataFrame, который выглядит следующим образом:

df = pd.DataFrame({'a': [25, 22, -2, 16, 10], 'b': [-5, 18, -2, 25, 48], 'c': [34, -12, 7, 8, 22],
'd': [10, 8, -2, -4, 12]})

Цель: устранить все нули с помощью специального сценария c или функции, которая сохраняет эффект отрицательного значения в каждом столбце .

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

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

Кроме того : В случаях, когда значение, следующее за отрицательным значением, также является отрицательным, я хочу выполнить одну и ту же операцию для обоих отрицательных значений. значения, но я хочу вычесть сумму абсолютного значения плюс один, для каждого отрицательного числа, и вычесть ее из следующей положительной строки. Если значение строки после исправленного отрицания становится меньше 1 после того, как я хочу вычесть из строки после этого, пока отрицательное значение не исчезнет и ни одна строка после них не станет меньше 1.

Ожидаемый результат будет надеюсь, помогите gr asp, что я собираюсь сделать:

expected_output = pd.DataFrame({'a': [25, 22, 1, 13, 10], 'b': [1, 12, 1, 22, 48],
'c': [34, 1, 1, 1, 22],'d': [10, 8, 1, 1, 4]})

Я могу заменить отрицательное значение абсолютным значением отрицательного значения плюс один, используя:

df[df < 0] = abs(df[df < 0] + 1)

Я также знаю, что могу найти местоположение отрицательного значения, используя:

neg_loc = df.loc[df['a'] < 0].index

Теперь я нахожу значение после отрицательного значения, используя:

row_after_neg = df['a'].iloc[neg_loc + 1]

Наконец, я могу добавить абсолютное значение отрицательного значения плюс один к строке после отрицательного значения с помощью:

total = row_after_neg.add(abs(neg_loc  + 1))

Итак, мой вопрос, как мне сшить это вместе, чтобы оно проходило через весь DataFrame и делало то, что я указал.

Заранее спасибо за совет / помощь!

1 Ответ

1 голос
/ 05 марта 2020

Ваш запрос был немного запутанным, поэтому я надеюсь, что я отвечу на все требования, если не сообщите мне в комментариях. Я решил использовать for-l oop, так как вы хотите сделать сравнение строк за строкой. Если скорость - проблема, я бы избегал for-l oop и посмотрел бы, можете ли вы остаться в рамках архитектуры панды.

Настройка:

import pandas as pd
df = pd.DataFrame({'a': [25, 22, -2, 16, 10], 'b': [-5, 18, -2, 25, 48], 'c': [34, -12, 7, 8, 22],
'd': [10, 8, -2, -4, 12]})

Создание версии кадра данных, которая имеет abs (отрицательные значения) + 1 и 0 вместо nans для положительных значений:

pos_df = (abs(df[df < 0]) + 1).fillna(0)

Для l oop для итерации по фрейму данных начиная со второй строки:

for index, row in df.iloc[1:,:].iterrows():

Затем вы вычитаете строку фрейма данных из предыдущей строки положительного фрейма данных

df.loc[index] = row - pos_df.loc[index - 1]

Затем вы пересчитываете строку pos_df, так как вы хотите проверить, не стало ли число отрицательным. Следует заметить, что я переключаю все негативное в df кадре данных, а не pos_df.

pos_df.loc[index][df.loc[index] < 0] = (abs(df.loc[index][df.loc[index] < 0]) + 1).fillna(0)

Наконец, измените все отрицательные значения на 1:

df[df < 0] = 1

Вот весь код:

import pandas as pd
df = pd.DataFrame({'a': [25, 22, -2, 16, 10], 'b': [-5, 18, -2, 25, 48], 'c': [34, -12, 7, 8, 22],
'd': [10, 8, -2, -4, 12]})
pos_df = (abs(df[df < 0]) + 1).fillna(0)

for index, row in df.iloc[1:,:].iterrows():
    df.loc[index] = row - pos_df.loc[index - 1]
    pos_df.loc[index][df.loc[index] < 0] = (abs(df.loc[index][df.loc[index] < 0]) + 1).fillna(0)

df[df < 0] = 1

С окончательным выводом:

    a       b       c       d
0   25.0    1.0     34.0    10.0
1   22.0    12.0    1.0     8.0
2   1.0     1.0     1.0     1.0
3   13.0    22.0    1.0     1.0
4   10.0    48.0    22.0    4.0

Надеюсь, это поможет!

Редактировать:

Итак, код:

pos_df.loc[index][df.loc[index] < 0] = (abs(df.loc[index][df.loc[index] < 0]) + 1).fillna(0)

является относительно сложным pandas выражением. Немного контекста. В Pandas есть series и dataframes, вы можете думать о series как о столбце или строке кадра данных. Когда вы выполняете условный выбор в фреймах данных, фрейм данных сохраняет свою форму, а значения, которые не соответствуют критериям, отображаются как Nan. С серией вы получаете только те значения, которые удовлетворяют условию.

Вот пример:

df[df == 1]
series[series == 1]


   a       b       c       d
0   Nan    Nan    Nan    Nan
1   Nan    Nan    1.0    Nan
2   Nan    Nan    1.0    1.0
3   Nan    Nan    1.0    1.0
4   Nan    Nan    Nan    Nan

c
1.0
1.0
1.0

Итак, как вы можете видеть выше, серия меняет форму с [5,1] на [3,1]. Теперь вернемся к коду. pos_df.loc[index] выбирает интересующую нас строку из кадра данных с преобразованными отрицательными числами. Возможно, было бы проще осмыслить это, если бы вы рассматривали его как:

pos_s = pos_df.loc[index]
s = df.loc[index]

pos_s[s < 0] = (abs(s[s < 0]) + 1).fillna(0)

Так что, как вы можете видеть выше, это то же самое выражение, которое вы использовали в своем вопросе, но оно выполнялось в строках, которые for-l oop выполняет итерацию в данный момент, а не весь фрейм данных. В коде:

(abs(s[s < 0]) + 1).fillna(0)

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

c
13
12
4

Так как это серия, вы заметите, что форма [3,1], а не [5,1], как ожидалось. Поэтому, чтобы не испортить информационный фрейм, я должен только заменить отрицательные значения. Поэтому я использую код:

pos_s[s < 0]

Я выбираю все в строке df, что является отрицательным, поэтому вывод

[False, True, True, False, True] 

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

...