【问题标题】:Matplotlib: y-axis normalisedMatplotlib:y 轴归一化
【发布时间】:2021-05-27 08:20:26
【问题描述】:

我有以下数据集

Date              Type        Label
2020-03-20         A            1
2020-03-20         A            0
2020-03-19         B            1
2020-03-17         A            1
2020-03-15         C            0
2020-03-19         A            0
2020-03-20         D            1
2020-03-20         A            1

我想在多线图中使用标准化值进行绘制。 下面的代码绘制了不同的时间线

import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, figsize=[10,6])

(df.loc[df.Label.eq(1),].groupby(["Date","Type"]).agg({"Type":"count"})
 .unstack(1).droplevel(0,axis=1)
 .fillna(method="ffill")
 .plot(ax=ax, kind="line")
)

但是当我尝试应用规范化时

column_norm=['Type']
df[column_norm] = df[column_norm].apply(lambda x: (x - x.min()) / (x.max() - x.min()))

失败,返回错误:

TypeError: 不支持的操作数类型 -: 'str' 和 'str'

当我计算最小值和最大值时。

你能告诉我如何得到一个 y 轴归一化为 1 的图吗?

【问题讨论】:

  • 究竟是什么失败了?
  • 当我计算最小值和最大值时出现错误:TypeError: unsupported operand type(s) for -: 'str' and 'str'
  • df['Type'] 是一个字符串列。从字符串中减去字符串的预期结果是什么?
  • @G.Anderson,我相信他上面的groupby() 应该产生整数计数。
  • 但无论如何,只要尝试将任何列显式转换为数字,例如df = df.astype({'column_norm': int}),看看效果如何。

标签: python pandas matplotlib


【解决方案1】:

根据小数据样本以及您在共享代码中使用countfillna 的方式,我认为您想要计算计数标签的标准化/重新缩放cumulative sum通过时间等于一。以下是如何使用更大的样本数据集执行此操作的分步示例:

import numpy as np   # v 1.19.2
import pandas as pd  # v 1.1.3

# Create sample dataset
rng = np.random.default_rng(seed=1)  # random number generator
dti = pd.date_range('2020-01-01', '2020-01-31', freq='D')
size = 2*dti.size
dfraw = pd.DataFrame(data=dict(Type = rng.choice(list('ABCD'), size=size),
                               Label = rng.choice([0,1], size=size),
                               Date = rng.choice(dti, size=size)))
dfraw.head()


您可以使用pivot_table 方法简化数据框的整形。请注意 df.Label.eq(1) 掩码和聚合函数 count 在此处如何被 aggfunc='sum' 替换,这利用了 Label 是数字的事实:

dfp = dfraw.pivot_table(values='Label', index='Date', columns='Type', aggfunc='sum')
dfp.head()


然后可以使用apply 方法为每个变量计算归一化/重新缩放的累积和:

dfcs = dfp.apply(lambda x: x.cumsum()/x.sum(), axis=0)
dfcs.head()


最后,可以填充 NaN 值,使图中的线条连续:

df = dfcs.fillna(method='ffill').fillna(value=0)
df.head()


ax = df.plot(figsize=(10,6))

# Format the tick labels using the default tick locations and format legend
ticks = ax.get_xticks()
ticklabels = pd.to_datetime(ticks, unit='D').strftime('%d-%b')
ax.set_xticks(ticks)
ax.set_xticklabels(ticklabels, rotation=0, ha='center')
ax.legend(title='Type', frameon=False);

【讨论】:

  • "ax = df.plot(figsize=(10,6))" 的最后一部分并没有打印出图...我该怎么办?
  • @just_learning 我在 Jupyter Notebook 中运行了这段代码,由于IPython(默认设置为 v7.21.0),它会自动显示绘图。如果您不使用 IPython,请尝试在代码末尾添加 ax.figure.show()plt.show(),如图所示 here
  • “ax.figure.show()”和“plt.show()”都不起作用!我使用 Ubuntu 20.04.1 LTS
  • @just_learning 我使用的是 Windows 10,我可以像使用 IPython 一样在常规 Python 中打印绘图,因此我无法在此问题上提供进一步的帮助,因为我无法重现该问题。也许here(或链接的问题中)的答案之一可能会有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-01
  • 2015-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多