У меня есть следующий набор данных:

print(df)

  Date      Product_Code     Quantity_ordered
01/01/18         01                 6
02/01/18         04                 3
03/01/18         01                 4
...

Я хотел бы создать дополнительный столбец «Заказ», используя Pandas, который для каждого продукта и дня равен 1, если заказано количество, иначе 0; например:

print(final_df)

  Date      Product_Code          Order
01/01/18         01                 1
01/01/18         04                 0

02/01/18         04                 1
02/01/18         01                 0    

03/01/18         01                 1
03/01/18         04                 0
...

Я старался:

a = pd.date_range(min(df["Date"]), max(df["Date"]))
final_df = pd.merge(df, a, on = ["Date", "Product_Code"])

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

Отношении

1
Alessandro Ceccarelli 13 Мар 2018 в 13:06

2 ответа

Лучший ответ

Вы можете использовать reindex по значениям unique Date и Product_Code, что создает NaN для отсутствующих строк, поэтому возможна проверка с помощью notnull и преобразование в 0,1:

mux = pd.MultiIndex.from_product([df['Date'].unique(), df['Product_Code'].unique()], 
                                 names=('Date','Product_Code'))

df1 = (df.set_index(['Date','Product_Code'])['Quantity_ordered']
        .reindex(mux)
        .notnull()
        .astype(int)
        .reset_index()
        .rename(columns={'Quantity_ordered':'Order'}))

Альтернативным решением является использование unstack для изменения формы - добавляются NaN, затем проверяются и преобразуются в 0,1, в последнюю очередь для обратного преобразования используйте stack:

df1 = (df.set_index(['Date','Product_Code'])['Quantity_ordered']
         .unstack()
         .notnull()
         .astype(int)
         .stack()
         .reset_index(name='Order')
)

print (df1)
       Date Product_Code  Order
0  01/01/18           01      1
1  01/01/18           04      0
2  02/01/18           01      0
3  02/01/18           04      1
4  03/01/18           01      1
5  03/01/18           04      0

Решение для работы с дубликатами:

print (df)
       Date Product_Code  Quantity_ordered
0  01/01/18           01                 6
1  01/01/18           01                 7
2  02/01/18           04                 3
3  03/01/18           01                 4

from  itertools import product
df1 = pd.DataFrame(list(product(df['Date'].unique(), df['Product_Code'].unique())),
                                columns=('Date','Product_Code'))

print (df1)
       Date Product_Code
0  01/01/18           01
1  01/01/18           04
2  02/01/18           01
3  02/01/18           04
4  03/01/18           01
5  03/01/18           04

df2 = pd.merge(df, df1, how='right').sort_values(['Date','Product_Code'])
df2 = (df2.rename(columns={'Quantity_ordered':'Order'})
         .assign(Order=lambda x:x['Order'].notnull().astype(int)))
print (df2)
       Date Product_Code  Order
0  01/01/18           01      1
1  01/01/18           01      1
4  01/01/18           04      0
5  02/01/18           01      0
2  02/01/18           04      1
3  03/01/18           01      1
6  03/01/18           04      0
0
jezrael 13 Мар 2018 в 11:33

Преобразовать в категории и применить groupby.sum. Это позволяет получить декартово произведение ваших категорий, которое вы ищете.

import pandas as pd

df = pd.DataFrame({'Date': ['01/01/18', '02/01/18', '03/01/18'],
                   'Product_Code': ['01', '04', '01'],
                   'Quantity_ordered': [6, 3, 4]})

# Convert to categories
df['Date'] = df['Date'].astype('category')
df['Product_Code'] = df['Product_Code'].astype('category')

# Groupby categories to retrieve cartesian product
df = df.groupby(['Date', 'Product_Code'], as_index=False)['Quantity_ordered'].sum()

# Define Order column
df['Quantity_ordered'] = df['Quantity_ordered'].notnull().astype(int)

Результат

       Date Product_Code  Quantity_ordered
0  01/01/18           01                 1
1  01/01/18           04                 0
2  02/01/18           01                 0
3  02/01/18           04                 1
4  03/01/18           01                 1
5  03/01/18           04                 0
0
jpp 13 Мар 2018 в 11:48