【问题标题】:Histogram with separate list denoting frequency带有表示频率的单独列表的直方图
【发布时间】:2013-09-30 19:46:00
【问题描述】:

假设我有两个列表:

    x1 = [1,2,3,4,5,6,7,8,1,10]
    x2 = [2,4,2,1,1,1,1,1,2,1]

这里,列表的每个索引i 是一个时间点,x2[i] 表示在时间i 观察到比x1[i] 观察到的次数(频率)。另请注意,x1[0] = 1 和 x1[8] = 1,总频率为 4 (= x2[0] + x2[8])。

如何有效地将其转换为直方图?简单的方法如下,但这可能效率低下(创建第三个对象并循环)并且会伤害我,因为我有巨大的数据。

import numpy as np
import matplotlib.pyplot as plt

x3 = []
for i in range(10):
    for j in range(x2[i]):
        x3.append(i)

hist, bins = np.histogram(x1,bins = 10)
width = 0.7*(bins[1]-bins[0])
center = (bins[:-1]+bins[1:])/2
plt.bar(center, hist, align = 'center', width = width)
plt.show()

【问题讨论】:

  • 不是x2已经是直方图吗?
  • @tcaswell 怎么样?如果您建议绘制条形图x2,这对我不起作用,因为x1 具有重复值。
  • 对不起,还没有喝咖啡,快读吧。看我的回答。

标签: python matplotlib plot histogram


【解决方案1】:

看来您的分箱有问题。2 的计数应该是 4。不是吗?这是一个代码。在这里,我们额外创建了一个数组,但它只运行一次,而且是动态的。希望对您有所帮助。

import numpy as np
import matplotlib.pyplot as plt

x1 = [1,2,3,4,5,6,7,8,1,10]
x2 = [2,4,2,1,1,1,1,1,2,1]

#your method
x3 = []
for i in range(10):
    for j in range(x2[i]):
        x3.append(i)
plt.subplot(1,2,1)
hist, bins = np.histogram(x1,bins = 10)
width = 0.7*(bins[1]-bins[0])
center = (bins[:-1]+bins[1:])/2
plt.bar(center, hist, align = 'center', width = width)
plt.title("Posted Method")
#plt.show()

#New Method
new_array=np.zeros(len(x1))
for count,p in enumerate(x1):
    new_array[p-1]+=x2[count]
plt.subplot(1,2,2)  
hist, bins = np.histogram(x1,bins = 10)
width = 0.7*(bins[1]-bins[0])
center = (bins[:-1]+bins[1:])/2
plt.bar(center, new_array, align = 'center', width = width)
plt.title("New Method")
plt.show()

这是输出:

【讨论】:

  • 作为旁注,enumerate 在x1 和x2 之间作为zip 会更好
【解决方案2】:

最好的方法是在np.histogram (doc) 上使用weights kwarg,它还可以处理x1 中的任意bin 大小和非整数值

vals, bins = np.histogram(x1, bins=10, weights=x2)

如果您只需要基于整数值进行累积,您可以一次性创建直方图:

new_array = np.zeros(x2.shape)  # or use a list, but I like numpy and you have it
for ind, w in izip(x1, x2):
     # -1 because your events seem to start at 1, not 0
     new_array[ind-1] += w

如果你真的想用列表来做这个,你可以使用列表推导

[_x for val, w in zip(x1, x2) for _x in [val]*w]

返回

[1, 1, 2, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 1, 1, 10]

附带说明一下,了解如何有效地手动计算直方图是值得的:

from __future__ import division
from itertools import izip

num_new_bins = 5
new_min = 0
new_max = 10
re_binned = np.zeros(num_new_bins)
for v, w in izip(x1, x2):
    # figure out what new bin the value should go into
    ind = int(num_new_bins * (v - new_min) / new_max)
    # make sure the value really falls into the new range
    if ind < 0 or ind >= num_new_bins:
        # over flow
        pass
    # add the weighting to the proper bin
    re_binned[ind] += w

【讨论】:

    【解决方案3】:

    一种方法是使用x3 = np.repeat(x1,x2) 并使用 x3 制作直方图。

    【讨论】:

    • 当计数很大时,这是否又快又高效?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-18
    • 1970-01-01
    • 2017-12-23
    • 2015-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多