如何使用分组绘制连续数据

Posted

技术标签:

【中文标题】如何使用分组绘制连续数据【英文标题】:How to plot continous data with grouping 【发布时间】:2021-09-17 01:58:37 【问题描述】:

我想要什么

我想为每个 cod 项目绘制图表。例如:1746202 ...等

但如图所示,我只有一个项目的图表。

我想为每个cod 显示更多图表。

我拥有的数据框

鳕鱼行动日期数量 0 1746 购买 2021-06-15 0:00:00 45 1 202 购买 2021-06-15 0:00:00 60 2 1746 卖出 2021-06-17 0:00:00 1 3 1746 卖出 2021-06-17 0:00:00 3 4 1746 卖出 2021-06-17 0:00:00 7 5 202 卖出 2021-06-17 0:00:00 1 6 202 卖出 2021-06-17 0:00:00 3 7 1746 卖出 2021-06-18 0:00:00 1 8 1746 卖出 2021-06-18 0:00:00 1 9 1746 卖出 2021-06-18 0:00:00 1 10 1746 卖出 2021-06-18 0:00:00 1 11 1746 卖出 2021-06-18 0:00:00 1 12 1746 卖出 2021-06-18 0:00:00 1 13 1746 卖出 2021-06-18 0:00:00 2 14 1746 卖出 2021-06-18 0:00:00 2 15 1746 卖出 2021-06-18 0:00:00 2 16 1746 卖出 2021-06-18 0:00:00 2 17 1746 卖出 2021-06-18 0:00:00 2 18 1746 卖出 2021-06-18 0:00:00 2 19 1746 卖出 2021-06-18 0:00:00 2 20 202 购买 2021-06-19 0:00:00 30 21 202 卖出 2021-06-19 0:00:00 1 22 202 卖出 2021-06-20 0:00:00 3 23 1746 购买 2021-06-21 0:00:00 45 24 1746 卖出 2021-06-22 0:00:00 7

上面显示的图表是用下面的代码绘制的。但这只会绘制一个cod

# Convert to datetime
df['datetime'] = pd.to_datetime(df['datetime'])
# Negate Sale rows
df.loc[df['action'].eq('Sale'), 'amt'] *= -1
# Calculate the total amount
df['total_amt'] = df['amt'].cumsum()
# Plot datetime vs total_amt
ax = df.plot(x='datetime', y='total_amt', ylabel='Qty', xlabel='Date')
plt.show()

问题

如何分组或使用其他方式为每个 cod 绘制线条?

【问题讨论】:

【参考方案1】:

对于matplotlibpandas 解决方案,需要进行三项修改。

    标准cumsum 将不再起作用,因为每组需要滚动总数。替换为groupby cumsumplot 每个 cod 在一个循环中。 action 列包含单词“sell”而不是“Sale”,因此过滤器应为 df['action'].eq('sell')
# Convert to datetime
df['date'] = pd.to_datetime(df['date'])
# Negate sell rows in action column
df.loc[df['action'].eq('sell'), 'qty'] *= -1

# Create a groupby over `cod`
g = df.groupby('cod')
# Calculate the total amount (per group)
df['total_amt'] = g['qty'].cumsum()

fig, ax = plt.subplots()
# Plot for each group in groubpy
for n, g_df in g:
    g_df.plot(x='date', y='total_amt',
              ylabel='Qty', xlabel='Date',
              ax=ax, label=n)

plt.legend(title='cod')
plt.tight_layout()
plt.show()

DataFrame 和导入:

import pandas as pd
from matplotlib import pyplot as plt

df = pd.DataFrame(
    'cod': [1746, 202, 1746, 1746, 1746, 202, 202, 1746, 1746, 1746, 1746, 1746,
            1746, 1746, 1746, 1746, 1746, 1746, 1746, 1746, 202, 202, 202, 1746,
            1746],
    'action': ['buy', 'buy', 'sell', 'sell', 'sell', 'sell', 'sell', 'sell',
               'sell', 'sell', 'sell', 'sell', 'sell', 'sell', 'sell', 'sell',
               'sell', 'sell', 'sell', 'sell', 'buy', 'sell', 'sell', 'buy',
               'sell'],
    'date': ['2021-06-15 0:00:00', '2021-06-15 0:00:00', '2021-06-17 0:00:00',
             '2021-06-17 0:00:00', '2021-06-17 0:00:00', '2021-06-17 0:00:00',
             '2021-06-17 0:00:00', '2021-06-18 0:00:00', '2021-06-18 0:00:00',
             '2021-06-18 0:00:00', '2021-06-18 0:00:00', '2021-06-18 0:00:00',
             '2021-06-18 0:00:00', '2021-06-18 0:00:00', '2021-06-18 0:00:00',
             '2021-06-18 0:00:00', '2021-06-18 0:00:00', '2021-06-18 0:00:00',
             '2021-06-18 0:00:00', '2021-06-18 0:00:00', '2021-06-19 0:00:00',
             '2021-06-19 0:00:00', '2021-06-20 0:00:00', '2021-06-21 0:00:00',
             '2021-06-22 0:00:00'],
    'qty': [45, 60, 1, 3, 7, 1, 3, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 30, 1,
            3, 45, 7]
)

注意cumsumgroupby cumsum 之间的区别:

df['date'] = pd.to_datetime(df['date'])
df.loc[df['action'].eq('sell'), 'qty'] *= -1
df['cs'] = df['qty'].cumsum()  # Standard cumsum
df['gb_cs'] = df.groupby('cod')['qty'].cumsum()  # Groupby cumsum

df:

     cod action       date  qty   cs  gb_cs
0   1746    buy 2021-06-15   45   45     45
1    202    buy 2021-06-15   60  105     60  # cs has total for both cod
2   1746   sell 2021-06-17   -1  104     44
3   1746   sell 2021-06-17   -3  101     41
4   1746   sell 2021-06-17   -7   94     34
5    202   sell 2021-06-17   -1   93     59  # gb_cs has separate totals per  cod
6    202   sell 2021-06-17   -3   90     56

seaborn 的替代方案通过设置 sns.lineplothue 参数来简化此过程,而不是创建一个 groupby 进行迭代:

import pandas as pd
import seaborn as sns
from matplotlib import pyplot as plt


# DataFrame is the same as above #

# Convert to datetime
df['date'] = pd.to_datetime(df['date'])
# Negate sell rows in action column
df.loc[df['action'].eq('sell'), 'qty'] *= -1
# Calculate the total amount (per group)
df['total_amt'] = df.groupby('cod')['qty'].cumsum()
# Plot using seaborn with hue param set to `cod`
ax = sns.lineplot(
    data=df, x='date', y='total_amt',
    hue='cod',  # Separate lines based on hue column `cod`
    ci=None,  # Remove Error Shading
    palette='pastel',  # Set Colour Palette
    estimator=None  # Plot all observations (like matplotlib)
)
ax.set(xlabel='Date', ylabel='Qty')
ax.xaxis.set_tick_params(rotation=45)
plt.tight_layout()
plt.show()

【讨论】:

您好,Henry,非常感谢您的回答。谢谢你。你能告诉我如何为每个cod 绘制子图吗?我正在寻找一种方法,但还没有找到,你能帮帮我吗? 添加子图fig, axes = plt.subplots(ncols=2) 然后把for循环改成for (n, g_df), ax in zip(g, axes):【参考方案2】:

根据您发布的信息,我将其重写为:

df['datetime'] = pd.to_datetime(df['datetime'])
# Negate Sale rows
df.loc[df['action'].eq('Sale'), 'amt'] *= -1
# Calculate the total amount
df['total_amt'] = df['amt'].cumsum()
for key, grp in df.groupby(['cod']):
    
    t=ax.plot(grp['datetime'], grp['total_amt'])
    plt.legend(t, [f'total amt key'],loc='best')

#ax.set(ylim=[0,100]) <----- if u need to setup y limits
ax.set_ylabel("Qty")
ax.set_xlabel("Date")

【讨论】:

我试过你的代码,但它没有编译...你编译你的代码了吗?检查并尝试更改一些内容以使其正常工作,但无法编译

以上是关于如何使用分组绘制连续数据的主要内容,如果未能解决你的问题,请参考以下文章

在多列上分组时如何绘制条形图?

如何在 streamlit 上按周期分组绘制图表?

如何绘制具有数据框的分组 geom_bar 图?

R语言使用ggplot2包geom_jitter()函数绘制分组(strip plot,一维散点图)带状图(颜色配置:连续色彩离散色彩色彩梯度)实战

MATLAB | 如何绘制高端大气的分组矩阵图

如何分组并绘制它