【问题标题】:get count and sum grouping dataframe by Pandas通过 Pandas 获取计数和总和分组数据框
【发布时间】:2018-06-27 18:46:39
【问题描述】:

我有一个 sql 表是这样的:

+----+------------+--------+------------+
| id | department | amount |    date    |
+----+------------+--------+------------+
| 1  | d1         |     20 | 2018-06-10 |
| 2  | d1         |     12 | 2018-06-10 |
| 2  | d1         |     10 | 2018-06-11 |
| 3  | d2         |     31 | 2018-06-10 |
| 4  | d2         |     42 | 2018-06-10 |
| 5  | d3         |     82 | 2018-06-11 |
| 6  | d3         |     11 | 2018-06-11 |
| 7  | d3         |     10 | 2018-06-14 |
+----+------------+--------+------------+

我用 Pandas 的read_sql 方法读取它:

df = pd.read_sql("select * table my_table", ...)

我想绘制数据的时间序列,因为 x 轴是月份中的某天,y 轴是部门数。所以,我想我必须按月份对它们进行分组,比如

gdf = df.groupby(['department', pd.Grouper(key='date', freq='d')])['amount'].sum()

gdf 看起来像:

department   date      
d1           2018-06-10      32
             2018-06-11      10
d2           2018-06-10      73
d3           2018-06-11      93
             2018-06-14      10

但是,我不知道如何使用gdf。我想用 seaborn 或 mathplotlib 绘制它。

我还想绘制按月和部门分组的金额总和。

注意:通常,我会编辑我的 sql 语句以包含分组数据,但在我的情况下,我不允许这样做。我必须使用 Pandas 来做到这一点。

【问题讨论】:

  • 你应该使用Grouper而不是TimeGrouper
  • 你想要每个部门一个线图,因为一天有多个部门吗?或者,尝试其他一些情节(如堆积条形图)
  • 我想在同一张图表上绘制每个部门的时间序列。换句话说,例如,绿线代表 d1,蓝线代表 d2,依此类推……
  • 如果不是按部门分组,而是为每个独特的部门过滤数据并每天汇总并绘制它,会不会很好?
  • 是的,它也可以工作

标签: python sql pandas numpy matplotlib


【解决方案1】:

对于每个独特的部门,将一天中的“金额”相加并将其绘制在同一图上。

首先,date 必须是 datetime 类型,然后才能基于它进行任何分组。

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

然后绘制时间序列如下:

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
fig, ax = plt.subplots(figsize=(10,6))

for d in df['department'].unique():
    gdf = df[df['department']==d].groupby(pd.Grouper(key='date', freq='d')).sum()
    ax.plot(gdf.index, gdf['amount'], label=d)

ax.get_xaxis().set_major_locator(mdates.DayLocator())
ax.get_xaxis().set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.xticks(rotation=30)
fig.tight_layout()

plt.legend(bbox_to_anchor=(1, 0), loc="upper right", bbox_transform=fig.transFigure,
           ncol=4, columnspacing=0.5)
plt.show()

【讨论】:

    【解决方案2】:

    DEEPAK SURANA 的答案对于绘图是正确的。但是,应该说如果您的df['date'] 列有str 类型的数据,这将不起作用。我在下面添加了用于创建您的 DF 并将 df['date'] 列转换为 datetime 类型的示例代码。

    import pandas as pd
    data = [(1, 'd1', 20, '2018-06-10'),
            (2, 'd1', 12, '2018-06-10'),
            (2, 'd1', 10, '2018-06-11'),
            (3, 'd2', 31, '2018-06-10'),
            (4, 'd2', 42, '2018-06-10'),
            (5, 'd3', 82, '2018-06-11'),
            (6, 'd3', 11, '2018-06-11'),
            (7, 'd3', 10, '2018-06-14')]
    labels = ['id', 'department', 'amount', 'date']
    df = pd.DataFrame.from_records(data, columns=labels)
    df['date'] = pd.to_datetime(df['date'])
    

    来自 DEEPAK SURANA 的图形代码:

    import matplotlib.pyplot as plt
    import matplotlib.dates as mdates
    fig, ax = plt.subplots(figsize=(10,6))
    
    for d in df['department'].unique():
        gdf = df[df['department']==d].groupby(pd.Grouper(key='date', freq='d')).sum()
        ax.plot(gdf.index, gdf['amount'], label=d)
    
    ax.get_xaxis().set_major_locator(mdates.DayLocator())
    ax.get_xaxis().set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
    plt.xticks(rotation=30)
    fig.tight_layout()
    
    plt.legend(bbox_to_anchor=(1, 0), loc="upper right", box_transform=fig.transFigure,
               ncol=4, columnspacing=0.5)
    plt.show()
    

    【讨论】:

    • 是的,我同意日期必须采用datetime 格式。但由于pd.Grouper() 为问题中的freq=d 工作,我认为它的格式正确。
    猜你喜欢
    • 2021-07-15
    • 1970-01-01
    • 2017-03-13
    • 1970-01-01
    • 1970-01-01
    • 2020-09-09
    • 2012-08-22
    相关资源
    最近更新 更多