计算并绘制列表中每(X)项的平均值,总共有(Y)项
我搜索了很久,整整四天才发这个帖子。如果内容太基础,浪费了大家的时间,我先在这里道个歉。我已经成功用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 个回答
我把问题理解为如何从一个文件生成的列表中获取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
填充剩余部分,而 imap
和 izip
则会截断。我可以想象提问者可能想使用 itertools.izip_longest(*iterables[,fillvalue])
来设置可选的填充值,虽然 None
作为“没有值”的标记也是不错的选择。
我希望这能让你明白剩余部分会发生什么。
假设你有一组数据,放在一个叫做 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,这样可以覆盖掉最开始的数据,节省一些内存。
希望这些对你有帮助。