计算并绘制列表中每(X)项的平均值,总共有(Y)项

3 投票
2 回答
3944 浏览
提问于 2025-04-17 15:31

我搜索了很久,整整四天才发这个帖子。如果内容太基础,浪费了大家的时间,我先在这里道个歉。我已经成功用pyplot和matplotlib生成了一些基本的图表,都是按照教程的例子做的,但对于我想要实现的目标却没有帮助。

简单来说:

  • 我有一个数字列表,这些数字都在一个文件里。
  • 每一行都包含一个数字,这个数字表示完成某个重复任务所需的毫秒数。
  • 这个文件里有超过一百万条记录,而且还可能会增加。

比如说,文件里有20个数字:

173
1685
1152
253
1623
390
84
40
319
86
54
991
1012
721
3074
4227
4927
181
4856
1415

最终我需要做的是计算一系列的总和(这些总和要平均分配到所有的记录上)——然后用Python的绘图库来绘制这些平均值。我考虑使用pyplot,因为它比较简单易用。

  • X轴将表示完成的任务总数,而Y轴则表示完成任务所需的毫秒数(在这个例子中,是每完成5个任务的平均时间)。

也就是说:

Entries 1-5 = (plottedTotalA)
Entries 6-10 = (plottedTotalB)
Entries 11-15 = (plottedTotalC)
Entries 16-20 = (plottedTotalD)

根据我的理解,我不需要无限期地存储变量的值,只需要在处理时按顺序将它们传递给绘图工具。我尝试了一个例子,来计算上面20个数字中每5个的总和(这个是可以的),但我不知道怎么动态地每次传递5个数字,直到完成,同时又能保留计算出的平均值,最终传递给pyplot。

例如:

Python 2.7.3 (default, Jul 24 2012, 10:05:38) 
[GCC 4.7.0 20120507 (Red Hat 4.7.0-5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> plottedTotalA = ['173', '1685', '1152', '253', '1623']
>>> sum(float(t) for t in plottedTotalA)
4886.0

2 个回答

1

我把问题理解为如何从一个文件生成的列表中获取5个项目。正如你所说:

我不知道如何动态地每次传递5个,直到完成。

我使用了 /dev/random,因为它是无尽的随机数据,模拟了一个大文件,并且展示了如何处理一个大文件,而不需要把数据读入列表或类似的方式。

################################################################################
def bigfile():
    """Never ending list of random numbers"""
    import struct
    with open('/dev/random') as f:
        while True:
            yield  struct.unpack("H",f.read(2))[0]
################################################################################
def avg(l):
    """Noddy version"""
    return sum(l)/len(l)
################################################################################

bigfile_i = bigfile()

import itertools
## Grouper recipe @ itertools
by_5  = itertools.imap(None, *[iter(bigfile_i)]*5)

# Only take 5, 10 times.
for x in range(10):
    l = by_5.next()
    a = avg(l)
    print l, a ## PLOT ?

编辑

关于剩余部分的详细说明。

假设文件有11行,每次取5行:

In [591]: list(itertools.izip_longest(*[iter(range(11))]*5))
Out[591]: [(0, 1, 2, 3, 4), (5, 6, 7, 8, 9), (10, None, None, None, None)]

In [592]: list(itertools.imap(None, *[iter(range(11))]*5))
Out[592]: [(0, 1, 2, 3, 4), (5, 6, 7, 8, 9)]

In [593]: list(itertools.izip(*[iter(range(11))]*5))
Out[593]: [(0, 1, 2, 3, 4), (5, 6, 7, 8, 9)]

在一种情况下,izip_longest 会用 None 填充剩余部分,而 imapizip 则会截断。我可以想象提问者可能想使用 itertools.izip_longest(*iterables[,fillvalue]) 来设置可选的填充值,虽然 None 作为“没有值”的标记也是不错的选择。

我希望这能让你明白剩余部分会发生什么。

4

假设你有一组数据,放在一个叫做 x 的列表里。接下来,把 x 变成一个有 5 列的数组 A,然后计算每一行的平均值。最后,你可以很简单地把得到的结果画出来。

x = np.array(x)
n = x.size
A = x[:(n // 5) * 5].reshape(5, -1)
y = A.mean(axis = 0)
plot(y)

补充说明:根据 tacaswell 的建议,我修改了我的代码。

不过,如果你的数据量超过一百万条,可能会遇到内存问题。你也可以直接用 x 这个名字来代替 A 和 y,这样可以覆盖掉最开始的数据,节省一些内存。

希望这些对你有帮助。

撰写回答