Ваш запрос был немного запутанным, поэтому я надеюсь, что я отвечу на все требования, если не сообщите мне в комментариях. Я решил использовать 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
, чтобы выбрать второе, третье и пятое значения и обновить их, если любое из первоначально положительных значений стало отрицательным после вычитания.