Гистограмма с накоплением из фрейма данных

Программа

Вот небольшая программа на Python, которая получает налоговые данные через API treasury.gov:

import pandas as pd
import treasury_gov_pandas
# ----------------------------------------------------------------------
df = treasury_gov_pandas.update_records(
    url = 'https://api.fiscaldata.treasury.gov/services/api/fiscal_service/v1/accounting/dts/deposits_withdrawals_operating_cash')

df['record_date'] = pd.to_datetime(df['record_date'])

df['transaction_today_amt'] = pd.to_numeric(df['transaction_today_amt'])

tmp = df[(df['transaction_type'] == 'Deposits') &   ((df['transaction_catg'].str.contains('Tax'))   |   (df['transaction_catg'].str.contains('FTD')))   ]

Программа использует следующую библиотеку для загрузки данных:

https://github.com/dharmatech/treasury-gov-pandas.py

Кадр данных

Вот как выглядят полученные данные:

>>> tmp.tail(20).drop(columns=['table_nbr', 'table_nm', 'src_line_nbr', 'record_fiscal_year', 'record_fiscal_quarter', 'record_calendar_year', 'record_calendar_quarter', 'record_calendar_month', 'record_calendar_day', 'transaction_mtd_amt', 'transaction_fytd_amt', 'transaction_catg_desc', 'account_type', 'transaction_type'])

       record_date                          transaction_catg  transaction_today_amt
371266  2024-04-03    DHS - Customs and Certain Excise Taxes                     84
371288  2024-04-03                  Taxes - Corporate Income                    237
371289  2024-04-03                   Taxes - Estate and Gift                     66
371290  2024-04-03       Taxes - Federal Unemployment (FUTA)                     10
371291  2024-04-03  Taxes - IRS Collected Estate, Gift, misc                     23
371292  2024-04-03              Taxes - Miscellaneous Excise                     41
371293  2024-04-03  Taxes - Non Withheld Ind/SECA Electronic                   1786
371294  2024-04-03       Taxes - Non Withheld Ind/SECA Other                   2315
371295  2024-04-03               Taxes - Railroad Retirement                      3
371296  2024-04-03          Taxes - Withheld Individual/FICA                  12499
371447  2024-04-04    DHS - Customs and Certain Excise Taxes                     82
371469  2024-04-04                  Taxes - Corporate Income                    288
371470  2024-04-04                   Taxes - Estate and Gift                     59
371471  2024-04-04       Taxes - Federal Unemployment (FUTA)                      8
371472  2024-04-04  Taxes - IRS Collected Estate, Gift, misc                    127
371473  2024-04-04              Taxes - Miscellaneous Excise                     17
371474  2024-04-04  Taxes - Non Withheld Ind/SECA Electronic                   1905
371475  2024-04-04       Taxes - Non Withheld Ind/SECA Other                   1092
371476  2024-04-04               Taxes - Railroad Retirement                      1
371477  2024-04-04          Taxes - Withheld Individual/FICA                   2871

В кадре данных есть данные, относящиеся к 2005 году:

>>> tmp.drop(columns=['table_nbr', 'table_nm', 'src_line_nbr', 'record_fiscal_year', 'record_fiscal_quarter', 'record_calendar_year', 'record_calendar_quarter', 'record_calendar_month', 'record_calendar_day', 'transaction_mtd_amt', 'transaction_fytd_amt', 'transaction_catg_desc', 'account_type', 'transaction_type'])

       record_date                                   transaction_catg  transaction_today_amt
2       2005-10-03                   Customs and Certain Excise Taxes                    127
7       2005-10-03                              Estate and Gift Taxes                     74
10      2005-10-03                          FTD's Received (Table IV)                   2515
12      2005-10-03  Individual Income and Employment Taxes, Not Wi...                    353
21      2005-10-03                          FTD's Received (Table IV)                  15708
...            ...                                                ...                    ...
371473  2024-04-04                       Taxes - Miscellaneous Excise                     17
371474  2024-04-04           Taxes - Non Withheld Ind/SECA Electronic                   1905
371475  2024-04-04                Taxes - Non Withheld Ind/SECA Other                   1092
371476  2024-04-04                        Taxes - Railroad Retirement                      1
371477  2024-04-04                   Taxes - Withheld Individual/FICA                   2871

Вопрос

Я хотел бы представить эти данные в виде гистограммы с накоплением.

  • Ось X должна быть «record_date».
  • Ось Y должна быть «transaction_today_amt».
  • Значения «transaction_catg» следует использовать для сложенных элементов.

Я открыт для любой библиотеки графиков. Т.е. matplotlib, боке, сюжет и т. д.

Каков хороший способ реализовать это?

Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
62
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете использовать pandas, он поставляется со встроенными функциями matplotlib, такими как метод plot(), и вы можете указать, что вам нужна составная гистограмма, как показано ниже (сначала вам нужно повернуть фрейм данных):

# First agg the data
df_agg = df.groupby(['record_date', 'transaction_catg']).agg({'transaction_today_amt': 'sum'}).reset_index()

# Pivot the dataframe
pivot_df = df_agg.pivot(index='record_date', columns='transaction_catg', values='transaction_today_amt')

# Plot stacked bar chart
pivot_df.plot(kind='bar', stacked=True, figsize=(10, 6))
plt.title('Stacked Bar Chart of Transaction Amount by Category')
plt.xlabel('Record Date')
plt.ylabel('Transaction Amount')
plt.xticks(rotation=45)
plt.legend(title='Transaction Category', bbox_to_anchor=(1.05, 1), loc='upper left') # Put legend outside of the plot
plt.tight_layout()
plt.show()

Со следующей строкой: pivot_df = tmp.pivot(index='record_date', columns='transaction_catg', values='transaction_today_amt') я получаю: ValueError: Index contains duplicate entries, cannot reshape.

dharmatech 07.04.2024 12:54

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

Adrien Riaux 07.04.2024 13:13
Ответ принят как подходящий

Я создал манекен df и проверил, работает ли он.

Этот код создает DataFrame со случайными данными транзакции grouped по date и category. Затем это pivots данные для отображения гистограммы с накоплением, где каждая полоса представляет собой date, а сегменты стека представляют transaction amounts для разных категорий. Я надеюсь, что это решение поможет вашему проекту.

И окончательный код показан ниже.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.dates import DayLocator

data = {
    'record_date': pd.to_datetime(['2023-10-01', '2023-10-02', '2023-10-03','2023-10-04', '2023-10-05', '2023-10-06','2023-10-07', '2023-10-08', '2023-10-09'] * 5),
    'transaction_catg': ['A', 'B', 'C', 'D', 'E'] * 9,
    'transaction_today_amt': np.random.randint(100, 1000, 45)
}
tmp = pd.DataFrame(data)

tmp_agg = tmp.groupby(['record_date', 'transaction_catg'])['transaction_today_amt'].sum().reset_index()

tmp_agg['record_date'] = tmp_agg['record_date'].dt.date

pivot_df = tmp_agg.pivot(index='record_date', columns='transaction_catg', values='transaction_today_amt').fillna(0)

ax = pivot_df.plot(kind='bar', stacked=True, figsize=(10, 6))

ax.xaxis.set_major_locator(DayLocator(interval=3))

plt.xticks(rotation=45)

plt.xlabel('Record Date')
plt.ylabel('Transaction Today Amount')
plt.title('Stacked Bar Chart of Transaction Amounts by Category and Date')

plt.show()

Вывод такой:

Мухаммед, спасибо за ваше предложение. Кажется, это работает! Однако есть две проблемы. Если вы попробуете это на реальных данных, это займет очень много времени. Чтобы запустить его, я использовал только последние 1000 записей. Кроме того, ось X неразборчива. Смотрите этот скриншот: i.imgur.com/thMHIOG.png

dharmatech 07.04.2024 13:21
mdates locators может помочь решить проблему с осью X. Пришло время, не знаю, как я могу это улучшить. @dharmatech
msamedozmen 07.04.2024 13:25

@dharmatech я отредактировал, добавив locator. Вам нужно будет выбрать локатор в зависимости от вашего кода. Для вашего кода вы можете использовать MonthLocator или YearLocator, это поможет вам решить проблему оси X.

msamedozmen 07.04.2024 14:19

Да, ось X выглядит лучше. Если увеличить масштаб, вот как это будет выглядеть: i.imgur.com/SsV5xWJ.png

dharmatech 07.04.2024 15:00

Мне удалось загрузить весь набор данных. Единственный недостаток, как я уже упоминал, заключается в том, что производительность пользовательского интерфейса matplotlib очень низкая при таком большом наборе данных. Я могу рассмотреть возможность преобразования этого в боке или сюжет для этого случая.

dharmatech 07.04.2024 15:02

Я опубликовал ответ на основе ваших предложений: stackoverflow.com/a/78287908/268581

dharmatech 07.04.2024 15:07

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

dharmatech 07.04.2024 15:08

@dharmatech, вы можете использовать colormap пример ax = pivot_df.plot(kind='bar', stacked=True, figsize=(10, 6),colormap = "tab20") дополнительные варианты можно найти в matplotlib.org/stable/gallery/color/colormap_reference.html

msamedozmen 07.04.2024 15:21

Я преобразовал код в боке. Теперь это довольно быстро! Код доступен здесь. Я также дал вам должное в README. 👍🙂 github.com/dharmatech/tga_taxes.py/tree/main

dharmatech 08.04.2024 08:42

@dharmatech я оценил

msamedozmen 08.04.2024 12:23

Вот полная программа, основанная на ответе Мухаммеда:

import pandas as pd
import treasury_gov_pandas
import matplotlib.pyplot as plt
import matplotlib
# ----------------------------------------------------------------------
df = treasury_gov_pandas.update_records(
    url = 'https://api.fiscaldata.treasury.gov/services/api/fiscal_service/v1/accounting/dts/deposits_withdrawals_operating_cash')

df['record_date'] = pd.to_datetime(df['record_date'])

df['transaction_today_amt'] = pd.to_numeric(df['transaction_today_amt'])

# ----------------------------------------------------------------------

tmp = df[(df['transaction_type'] == 'Deposits') &   ((df['transaction_catg'].str.contains('Tax'))   |   (df['transaction_catg'].str.contains('FTD')))   ]

# tmp.drop(columns=['table_nbr', 'table_nm', 'src_line_nbr', 'record_fiscal_year', 'record_fiscal_quarter', 'record_calendar_year', 'record_calendar_quarter', 'record_calendar_month', 'record_calendar_day', 'transaction_mtd_amt', 'transaction_fytd_amt', 'transaction_catg_desc', 'account_type', 'transaction_type'])

# tmp.tail(20).drop(columns=['table_nbr', 'table_nm', 'src_line_nbr', 'record_fiscal_year', 'record_fiscal_quarter', 'record_calendar_year', 'record_calendar_quarter', 'record_calendar_month', 'record_calendar_day', 'transaction_mtd_amt', 'transaction_fytd_amt', 'transaction_catg_desc', 'account_type', 'transaction_type'])

# ----------------------------------------------------------------------

tmp_agg = tmp.groupby(['record_date', 'transaction_catg'])['transaction_today_amt'].sum().reset_index()

tmp_agg['record_date'] = tmp_agg['record_date'].dt.date

pivot_df = tmp_agg.pivot(index='record_date', columns='transaction_catg', values='transaction_today_amt').fillna(0)

# ax = pivot_df.plot(kind='bar', stacked=True)

# ax = pivot_df.tail(1000).plot(kind='bar', stacked=True)

ax = pivot_df.plot(kind='bar', stacked=True)

ax.xaxis.set_major_locator(matplotlib.dates.DayLocator(interval=10))

plt.xticks(rotation=45)

plt.ylabel('transaction_today_amt')

plt.title('TGA Taxes')

plt.ion()

plt.show()

Скриншот

Если увеличить масштаб, то это выглядит следующим образом:

Недостатки

Недостатком matplotlib является то, что пользовательский интерфейс работает очень медленно при таком большом наборе данных.

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

Мне нужно уникальное количество слов, начинающееся с буквы P, это слово может находиться в нескольких строках или в нескольких столбцах в текстовом файле/файле Excel с использованием Python
Удаление выбросов с помощью IQR не работает, форма кадра данных не меняется
Написание кадра данных pandas с большим векторным столбцом
Скольжение стандартного отклонения всех столбцов, игнорируя NaN
Мне нужен один столбец фрейма данных Panadas, который представляет собой URL-адрес и который я сохраняю в формате CSV, чтобы его можно было напрямую щелкнуть
Pandas подсчитывает количество определенных столбцов, соответствующих определенным условиям
Разница между строками в Pandas DataFrame
Использование group_by в пандах, но с условием
Pandas to_csv не может добавить файл в облако Databricks (операция OSError Errno 95 не поддерживается)
Панды — процент от общего числа в сводной таблице