Панды группируются по идентификатору и году (дате), но показывают год для всех лет, а не только для тех, которые присутствуют в идентификаторе?

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

tmp = invoices[invoice['invoice_year'].isin([2018,2019,2020]]
tmp = tmp.groupby(['id', pd.Grouper(key = 'invoice_date', freq = 'Y')])['sales'].sum()

Это вернет что-то вроде:

id    invoice_year    sales
1        2018       483982.20
1        2019       3453
1        2020       453533
2        2018       243
2        2020       23423
3        2020       2330202

Однако желаемый результат будет:

id    invoice_year    sales
1        2018       483982.20
1        2019       3453
1        2020       453533
2        2018       243
2        2019       nan
2        2020       23423
3        2018       nan
3        2019       nan
3        2020       2330202

Идеи?

Отвечает ли это на ваш вопрос? столбцы pandas GroupBy со значениями NaN (отсутствуют)

crackaf 12.12.2020 00:07

Я так не думаю. Нет. В приведенном выше вопросе мы генерируем np.nans из-за отсутствия данных, а не заменяем nans или управляем существующими nans.

WolVes 12.12.2020 00:13

Вы можете попробовать вариант dropna = False, если у вас есть последние версии панд.

Stefan 12.12.2020 00:15
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
3
282
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Предположим, что исходные значения определены в фрейме данных с именем df, тогда вы можете попробовать следующее:

output = (df.groupby(['id', 'invoice_date'])['val'].sum()
                .unstack(fill_value=0)
                .stack()
                .reset_index(name='val'))

В противном случае вы можете предварительно создать столбец invoice_year:

df['invoice_year'] = df['invoice_date'].dt.year

И повторите тот же код, это выводит:

   id  invoice_year  val
0   1          2018    1
1   1          2019    1
2   1          2020    0
3   2          2018    1
4   2          2019    0
5   2          2020    1
6   3          2018    0
7   3          2019    1
8   3          2020    1

Используя следующие данные в качестве примера:

df = pd.DataFrame({'id':[1]*2+[2]*2+[3]*2,'invoice_date':pd.to_datetime(['2018-12-01','2019-12-01','2020-12-01']*2,infer_datetime_format=True),'val':[1]*6})

Вам не хватает скобки перед df :) Я добавлю это, чтобы ваш код работал с вашим фреймом данных.

David Erickson 12.12.2020 01:09

Большое спасибо Давид! Должно быть, я что-то пропустил, когда копировал из colab!

Celius Stingher 12.12.2020 11:45

Стефан опубликовал комментарий, который может помочь. Просто передать dropna=False вашему .groupby кажется лучшим выбором; но вы также можете использовать подход, при котором вы возвращаете NaNs позже, что может потребоваться в более ранних версиях панд, которые не имеют параметра dropna=False:

id    invoice_year  sales
1        2018       483982.20
1        2019       3453
1        2020       453533
2        2018       243
2        2020       23423
3        2020       2330202

Вы можете использовать pd.MultiIndex.from_product и переиндексировать фрейм данных из вновь созданного индекса с именем idx:

i, iy = df['id'], df['invoice_year']
idx = pd.MultiIndex.from_product([range(i.min(), i.max()+1), 
                                  range(iy.min(), iy.max()+1)],
                                  names=[i.name, iy.name])
df = df.set_index([i.name, iy.name]).reindex(idx).reset_index()
df
Out[1]: 
   id  invoice_year      sales
0   1          2018   483982.2
1   1          2019     3453.0
2   1          2020   453533.0
3   2          2018      243.0
4   2          2019        NaN
5   2          2020    23423.0
6   3          2018        NaN
7   3          2019        NaN
8   3          2020  2330202.0

Другие вопросы по теме