Python calcualte новый столбец в зависимости от состояния существующих столбцов - PullRequest
0 голосов
/ 05 ноября 2018

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

DF["A"][0] = 0
for x in range(1,rows):
    if(DF["B"][x]>DF["B"][x-1]):
        DF["A"][x] = DF["A"][x-1] + DF["C"][x]
    elif(DF["B"][x]<DF["B"][x-1]):
        DF["A"][x] = DF["A"][x-1] - DF["C"][x]
    else:
        DF["A"][x] = DF["A"][x-1]

Ответы [ 2 ]

0 голосов
/ 05 ноября 2018

Если я вас правильно понял, это то, что вы хотите:

import pandas as pd
import numpy as np

df = pd.DataFrame({'A': [1, 2, 3, 4, 5],
                   'B': [12, 15, 9, 8, 15],
                   'C': [3, 9, 12, 6, 8]})

df['A'] = np.where(df.index==0,
                   0,
                   np.where(df['B']>df['B'].shift(),
                            df['A']-df['A'].shift(),
                            np.where(df['B']<df['B'].shift(),
                                     df['A'].shift()-df['C'],
                                     df['A'].shift())))
df
#      A   B   C
#0   0.0  12   3
#1   1.0  15   9
#2 -10.0   9  12
#3  -3.0   8   6
#4   1.0  15   8
0 голосов
/ 05 ноября 2018

новый столбец, основанный на определенных условиях существующих столбцов,

Я использую DataFrame, предоставленный @zipa:

df = pd.DataFrame({'A': [1, 2, 3, 4, 5],
                   'B': [12, 15, 9, 8, 15],
                   'C': [3, 9, 12, 6, 8]})

Первый подход

Вот функция, которая реализуется эффективно, как вы указали. Он работает за счет использования функций индексации Pandas, в частности масок строк

def update(df):
    cond_larger = df['B'] > df['B'].shift().fillna(0)
    cond_smaller = df['B'] < df['B'].shift().fillna(0)
    cond_else = ~(cond_larger | cond_smaller)
    for cond, sign in [(cond_larger, +1),  # A[x-1] + C[x] 
                       (cond_smaller, -1), # A[x-1] - C[x]
                       (cond_else, 0)]:    # A[x-1] + 0
        if any(cond):
            df.loc[cond, 'A_updated'] = (df['A'].shift().fillna(0) + 
                                         sign * df[cond]['C'])
    df['A'] = df['A_updated']
    df.drop(columns=['A_updated'], inplace=True)
    return df

update(df)
=> 
      A   B   C
0   3.0  12   3
1  10.0  15   9
2 -10.0   9  12
3  -3.0   8   6
4  12.0  15   8

Оптимизированный

Оказывается, вы можете использовать DataFrame.mask для достижения того же, что и выше. Обратите внимание, что вы можете объединить условия в вызов mask, однако мне проще читать так:

# specify conditions
cond_larger = df['B'] > df['B'].shift().fillna(0)
cond_smaller = df['B'] < df['B'].shift().fillna(0)
cond_else = ~(cond_larger | cond_smaller)
# apply
A_shifted = (df['A'].shift().fillna(0)).copy()
df.mask(cond_larger, A_shifted + df['C'], axis=0, inplace=True)
df.mask(cond_smaller, A_shifted - df['C'], axis=0, inplace=True)
df.mask(cond_else, A_shifted, axis=0, inplace=True)
=>
(same results as above)

Примечания:

  • Я предполагаю значение по умолчанию 0 для A/B[x-1]. Если к первому ряду следует относиться иначе, удалите или замените .fillna(0). Результаты будут другими.

  • Условия проверяются последовательно. В зависимости от того, должны ли обновления использовать исходные значения в A или те, которые были обновлены в предыдущем условии, вам может не понадобиться вспомогательный столбец A_updated

  • Смотрите предыдущие версии этого ответа для истории того, как я попал сюда

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...