【问题标题】:Summing and plotting by month and arbitrary attribute in PandasPandas 中按月份和任意属性求和和绘图
【发布时间】:2018-08-11 20:51:50
【问题描述】:

我目前正在从事数据分析,并正在构建一个小型会计应用程序来跟踪我的开支。

我的目标是在一个 Django 应用程序中跟踪我的开支,使用 Pandas 对其进行一些分析,并使用 Matplotlib 将其可视化。

我的数据基础来自这样的 Django ORM 查询:

qs = MyExpenses.objects.values('date', 'amount', 'category')

然后我使用 Pandas 的 from_records 方法创建一个索引 DataFrame:

df = pd.DataFrame.from_records(qs, index='date', coerce_float=True)
df.index = pd.to_datetime(df.index)  # manually make index a proper DateTimeIndex, datetime.date objects don't seem to be converted automatically

使用df.head()检查DataFrame的内容:

            amount  category
date        
2017-12-29  14.90   Food
2017-12-27  2.98    Household
2017-12-27  9.72    Food
2017-12-24  2.00    Food
2017-12-23  1.49    Household

目前看起来不错。

此时我不知道如何正确进行。 我希望每月按类别汇总我的费用。

这个 groupby 操作:

summed_df = df.groupby([pd.Grouper(freq='1M'), 'category']).sum()

返回正确聚合的数据:

                                amount
date        category    
2016-02-29  Cosmetics           2.45
            Food                376.41
            Household           43.82
            Leisure             630.13
2016-03-31  Food                345.41
            Household           14.76
            Leisure             553.35
...

但是调用summed_df.plot() 会呈现这个情节:

显然 Panda 使用日期和类别的组合索引作为 x 轴,将金额列作为单个数据系列。如上所述,这不是我想要的。

因此,我必须以另一种方式求和,或者以某种方式从索引中删除类别并再次使其成为常规列,但我不知道如何处理。

那里的一些 Pandas 破解可以帮助我吗?

【问题讨论】:

  • 你在寻找什么样的情节?你能描述一下你的理想情节是什么样的吗?
  • 你应该看看其他问题,例如this recent one 有一个 minimal reproducible example 和所需输出的清晰描述,以便可以回答。还要说明其他问题在多大程度上不能帮助您解决问题。
  • 所需的输出是一个折线图,x 轴是时间,y 轴是花费的总和,每个类别都有一个系列。抱歉,如果我最初的帖子没有说明这一点。
  • 这似乎与 this question here 重复

标签: python pandas matplotlib


【解决方案1】:

考虑将您的 groupby 结果旋转,其中每个类别都成为自己的列,成为单独的行。下面使用随机数据进行演示(为了重现性而播种):

数据

import numpy as np
import pandas as pd
import datetime as dt
import time    
import matplotlib.pyplot as plt

epoch_time = int(time.time())

np.random.seed(55)
df = pd.DataFrame({'date': [dt.datetime.fromtimestamp(np.random.randint(1450000000, epoch_time)) 
                                for _ in range(500)],
                   'category': ["".join(np.random.choice(['Cosmetics', 'Food', 'Household', 'Leisure'],1)) 
                                 for _ in range(500)],
                   'amount': abs(np.random.randn(500))*100}).set_index('date')

print(df.head(10))
#                          amount   category
# date                                      
# 2016-12-23 10:30:18   10.711083  Household
# 2016-05-05 15:40:07  176.670986  Cosmetics
# 2017-04-24 17:55:04   16.700308  Cosmetics
# 2018-01-02 06:41:33  242.877311       Food
# 2017-12-15 00:06:29   95.990759  Household
# 2016-07-30 18:22:13   45.610068       Food
# 2016-07-13 16:00:11   60.704399    Leisure
# 2017-04-15 20:28:03   12.410939       Food
# 2017-12-07 19:33:18   61.599076  Cosmetics
# 2017-10-29 20:20:07  117.341928    Leisure

分组和绘图

summed_df = df.groupby([pd.Grouper(freq='1M'), 'category']).sum()\
                .reset_index().pivot(index='date', columns='category', values='amount')

summed_df.plot()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-21
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 2015-11-28
    • 2018-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多