Как создать новые столбцы на основе определенных условий? - PullRequest
0 голосов
/ 03 октября 2019

У меня есть многоиндексный фрейм данных. Индексы представлены идентификатором и датой. У меня есть 3 столбца: стоимость, доход и расходы.

Я хочу создать 3 новых столбца на основе определенных условий.

1) Первый новый столбец, который я хотел бы создать, будет основан на условии, для трех самых предыдущих дат для идентификатора, если столбец затрат последовательно уменьшается, пометьте новые значения строки как «NEG»,если нет, пометьте его как «Нет».

2) Второй столбец, который я хотел бы создать, будет основан на условии, для 3 самых последних дат, если столбец выручки последовательно уменьшается, обозначьте новую строкуЗначения как «NEG», если нет, то пометьте «Нет».

3) Третий столбец, который я хотел бы создать, будет основан на условии, для 3 самых последних дат, если столбец расходов постоянно увеличивается, пометьте новое значение строки как «POS» или если оно останетсята же самая метка новое значение строки как «STABLE».

idx = pd.MultiIndex.from_product([['001', '002', '003','004'],
                              ['2017-06-30', '2017-12-31', '2018-06-30','2018-12-31','2019-06-30']],
                             names=['ID', 'Date'])
col = ['Cost', 'Revenue','Expenditure']

 dict2 = {'Cost':[12,6,-2,-10,-16,-10,14,12,6,7,4,2,1,4,-4,5,7,9,8,1],
     'Revenue':[14,13,2,1,-6,-10,14,12,6,7,4,2,1,4,-4,5,7,9,18,91],
     'Expenditure':[17,196,20,1,-6,-10,14,12,6,7,4,2,1,4,-4,5,7,9,18,18]}

df = pd.DataFrame(dict2,idx,col)

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

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

idx = pd.MultiIndex.from_product([['001', '002', '003','004'],
                              ['2017-06-30', '2017-12-31', '2018-06-30','2018-12-31','2019-06-30']],
                             names=['ID', 'Date'])
col = ['Cost', 'Revenue','Expenditure', 'Cost Outlook', 'Revenue Outlook', 'Expenditure Outlook']

dict3= {'Cost':  [12,6,-2,-10,-16,
            -10,14,12,6,7,
            4,2,1,4,-4,
            5,7,9,8,1],


    'Cost Outlook':   ['no','no','NEG','NEG','NEG', 
                       'no','no','no','NEG','NEG', 
                       'no','no','NEG','no','no', 
                       'no','no','no','no','NEG'],



    'Revenue':[14,13,2,1,-6,
               -10,14,12,6,7,
               4,2,1,4,-4,
               5,7,9,18,91],

    'Revenue Outlook': ['no','no','NEG','NEG','NEG', 
                        'no','no','no','NEG','NEG', 
                        'no','no','NEG','no','no', 
                        'no','no','no','no','no'],



    'Expenditure':[17,196,1220,1220, -6,
                   -10,14,120,126,129, 
                   4,2,1,4,-4,
                   5,7,9,18,18],


    'Expenditure Outlook':['no','no','POS','POS','no', 
                           'no','no','POS','POS','POS', 
                           'no','no','no','no','no', 
                           'no','no','POS','POS','STABLE']
   }

df_new  = pd.DataFrame(dict3,idx,col)

Ответы [ 2 ]

0 голосов
/ 03 октября 2019

Проверьте, выполняет ли это задание:

is_descending = lambda a: np.all(a[:-1] > a[1:])
is_ascending = lambda a: np.all(a[:-1] <= a[1:])
df1 = df.reset_index()
df1["CostOutlook"] = df1.groupby("ID").Cost.rolling(3).apply(is_descending).fillna(0).apply(lambda x: "NEG" if x > 0 else "no").to_list()
df1["RevenueOutlook"] = df1.groupby("ID").Revenue.rolling(3).apply(is_descending).fillna(0).apply(lambda x: "NEG" if x > 0 else "no").to_list()
df1["ExpenditureOutlook"] = df1.groupby("ID").Expenditure.rolling(3).apply(is_ascending).fillna(0).apply(lambda x: "POS" if x > 0 else "no").to_list()
df1 = df1.set_index(["ID", "Date"])

Примечание. Требование "СТАБИЛЬНО" не обработано.

Редактировать: Это альтернативное решение:

is_descending = lambda a: np.all(a[:-1] > a[1:])
def is_ascending(a):
    if np.all(a[:-1] <= a[1:]):
        if a[-1] == a[-2]:
            return 2
        return 1
    return 0

for col in ['Cost', 'Revenue']:
    outlook = df[col].unstack(level="ID").rolling(3).apply(is_descending).fillna(0).replace({0.0:"no", 1.0:"NEG"}).unstack().rename(f"{col} outlook")
    df = df.join(outlook)

col = "Expenditure"
outlook = df[col].unstack(level="ID").rolling(3).apply(is_ascending).fillna(0).replace({0.0:"no", 1.0:"POS", 2.0:"STABLE"}).unstack().rename(f"{col} outlook")
df = df.join(outlook)
0 голосов
/ 03 октября 2019

Вот что я бы сделал:

# update Cost and Revenue Outlooks 
# because they have similar conditions
for col in ['Cost', 'Revenue']:
    groups = df.groupby('ID')

    outlook = f'{col} Outlook'
    df[outlook] = groups[col].diff().lt(0)

    # moved here
    df[outlook] = np.where(groups[outlook].rolling(2).sum().eq(2), 'NEG', 'no')

# update Expenditure Outlook
col = 'Expenditure'
outlook = f'{col} Outlook'
s = df.groupby('ID')[col].diff()

df[outlook] = np.select( (s.eq(0).groupby(level=0).rolling(2).sum().eq(2),
                          s.gt(0).groupby(level=0).rolling(2).sum().eq(2)),
                        ('STABLE', 'POS'), 'no')
...