使用Numpy在一些数据集中查找平均值,其中包含一些缺失数据。

5

我有几个(大约10个)以CSV格式排列的数据集。每个数据集的每一列代表运行系统的一个方面(可用内存、CPU使用率、打开的TCP连接等)。每一行包含了这些列在某一时刻的值。

这些数据集是在同一测试的不同运行中捕获的。每个数据集的行数不能保证相同(即:有些测试运行时间比其他测试长)。

我想要生成一个新的CSV文件,它表示给定时间偏移量和给定列的所有数据集的“平均”值。理想情况下,一个数据集中缺失的值将被忽略。如果必要,缺失的值可以被假定为与最后已知的值相同,或者是该行已知值的平均值。

以下是一个简化的例子:

+---------------+    +---------------+       +---------------+
|     Set 1     |    |     Set 2     |       |    Average    |
+---+-----+-----+    +---+-----+-----+       +---+-----+-----+
| t |  A  |  B  |    | t |  A  |  B  |       | t |  A  |  B  |
+---+-----+-----+    +---+-----+-----+       +---+-----+-----+
| 1 | 10  | 50  |    | 1 | 12  | 48  |       | 1 | 11  | 49  |   
| 2 | 13  | 58  |    | 2 |  7  | 60  |       | 2 | 10  | 59  |   
| 3 |  9  | 43  |    | 3 | 17  | 51  |  =>   | 3 | 13  | 47  |   
| 4 | 14  | 61  |    | 4 | 12  | 57  |       | 4 | 13  | 59  |   
| : |  :  |  :  |    | : |  :  |  :  |       | : |  :  |  :  |   
| 7 |  4  | 82  |    | 7 | 10  | 88  |       | 7 |  7  | 86  |   
+---+-----+-----+    | 8 | 15  | 92  |       | 8 | 15  | 92  |
                     | 9 |  6  | 63  |       | 9 |  6  | 63  |
                     +---+-----+-----+       +---+-----+-----+

我是numpy的新手,专门为了这个项目而学习它。最好的方法是什么?对于具有相同行数的数据集(我通过将较长的数据集截短来实现),我只需执行以下操作:

d_avg = sum(dsets) / float(len(dsets))

其中"dsets"是包含每个CSV文件数据的ndarrays列表。这个方法很好,但我不想丢弃长运行时间的数据。

我也可以将较短的运行时间调整为最长运行时间的长度,但所有新字段都填充了"NoneType"。之后的操作会在添加(例如)float和NoneType时出错。

有什么建议吗?


我认为第7行的平均值是错误的。 - John La Rooy
我知道我会错过其中一行!已更新。 - Lemur
3个回答

3
为什么不使用NumPy的ma(掩码数组)模块呢?
maxLen = reduce(lambda a,b : max(a, b.shape[0]),
                dSets, 0)
all = N.ma.zeros((maxLen,)+ dSets[0].shape[1:] + (len(dSets),),
                     dtype=float)      # set the dtype to whatever
all.mask = True
for i, set in enumerate(dSets):
    all.mask[:len(set),...,i] = False
    all[:len(set),...,i] = set

mean = all.mean(axis=-1)

当然,前提是您必须确保所有数组中每一行的时间相同,即对于所有的i和j,set[i,0] == set[j,0]。

即使时间不同,您仍然可以使用掩码数组。您只需更聪明地设置掩码数组,以使每个时间的数据位于同一行。 - AFoglia
这个很好用。谢谢!有一件事:当早期值最高时,reduce/lambda结构可能会失败:'int'没有'method' 'shape'。替换为:maxLen = max([a.shape[0] for a in dSets])。 - Lemur
是的,你说得对,我搞糟了 lambda。已编辑以更正。谢谢! - Rupert Nash

2

编辑:我已经修改了我的方法,放弃使用scipy.nanmean,转而使用掩码数组。

如果代码在任何时候都不清楚在做什么,请先尝试插入打印语句。如果仍然不清楚,请随时询问;我会尽力解释。其中棘手的部分是合并t值。(这是用numpy数组的searchsorted方法完成的。)

玩弄numpy让我相信,它的速度优势可能不存在,直到数据集变得非常大(也许每个数据集至少需要10,000行)。否则,纯python解决方案可能更容易编写并且更快。

这是我使用的玩具数据集:

% cat set1
1, 10, 50
2, 13, 58
3,9,43
4,14,61
7, 4, 82

% cat set2
1, 12, 48
2, 7, 60
3,17,51
4,12,57
7,10,88
8,15,92
9,6,63

以下是代码:

#!/usr/bin/env python
import numpy as np

filenames=('set1','set2')   # change this to list all your csv files
column_names=('t','a','b')

# slurp the csv data files into a list of numpy arrays
data=[np.loadtxt(filename, delimiter=',') for filename in filenames]

# Find the complete list of t-values
# For each elt in data, elt[a,b] is the value in the a_th row and b_th column
t_values=np.array(list(reduce(set.union,(set(elt[:,0]) for elt in data))))
t_values.sort()
# print(t_values)
# [ 1.  2.  3.  4.  7.  8.  9.]

num_rows=len(t_values)
num_columns=len(column_names)
num_datasets=len(filenames)

# For each data set, we compute the indices of the t_values that are used.
idx=[(t_values.searchsorted(data[n][:,0])) for n in range(num_datasets)]

data2=np.ma.zeros((num_rows,num_columns,num_datasets))
for n in range(num_datasets):
    data2[idx[n],:,n]=data[n][:,:]
data2=np.ma.masked_equal(data2, 0)
averages=data2.mean(axis=-1)
print(averages)
# [[1.0 11.0 49.0]
#  [2.0 10.0 59.0]
#  [3.0 13.0 47.0]
#  [4.0 13.0 59.0]
#  [7.0 7.0 85.0]
#  [8.0 15.0 92.0]
#  [9.0 6.0 63.0]]

不错!我不知道有'loadtxt'这个函数。我一直在使用'tabular'模块,结果发现它有点过头了。谢谢。 - Lemur

0

嗯,一种方法是迭代每个数据集的每一行,并将给定列值附加到存储在字典中的数组中,其中时间索引用于其键值。然后,您可以迭代字典并提取存储在其中的每个数组的平均值。

这种方法效率不高--另一种选择是找到最长的数组,迭代它,并查询其他数据集以创建一个临时数组进行平均。这样,您可以节省对字典的二次迭代。


我曾经非常希望numpy以其面向数组的高效性能,提供一种实现这个的方法。不过你说得对,如果没有现有的操作,我就只能回到你建议的方法上了。 - Lemur
如果你真的想留在numpy中,可以看一下这里的掩码数组:http://docs.scipy.org/doc/numpy/reference/maskedarray.generic.html - Marcel Levy
我所追求的并不是numpy本身,而是干净、易于理解的代码!坦白地说,如果这意味着有一个优雅的解决方案,我甚至可以放弃Python去使用R(假设如此)。但是我对R的了解甚至比numpy还要少。感谢您提供关于掩码数组的提示。我会去查看一下。 - Lemur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接