我正在使用Numpy并尝试计算大型矩阵(300000 x 70000)的均值和协方差。 我有32GB的可用内存。就计算效率和实现的简便性而言,此任务的最佳实践是什么?
我当前的实现如下:
def compute_mean_variance(mat, chunk_size):
row_count = mat.row_count
col_count = mat.col_count
# maintain the `x_sum`, `x2_sum` array
# mean(x) = x_sum / row_count
# var(x) = x2_sum / row_count - mean(x)**2
x_sum = np.zeros([1, col_count])
x2_sum = np.zeros([1, col_count])
for i in range(0, row_count, chunk_size):
sub_mat = mat[i:i+chunk_size, :]
# in-memory sub_mat of size chunk_size x num_cols
sub_mat = sub_mat.read().val
x_sum += np.sum(sub_mat, 0)
x2_sum += x2_sum + np.sum(sub_mat**2, 0)
x_mean = x_sum / row_count
x_var = x2_sum / row_count - x_mean ** 2
return x_mean, x_var
有什么改进建议吗?
我发现以下实现应该更容易理解。它还使用numpy来计算列块的均值和标准差。因此它应该更有效并且在数值上稳定。
def compute_mean_std(mat, chunk_size):
row_count = mat.row_count
col_count = mat.col_count
mean = np.zeros(col_count)
std = np.zeros(col_count)
for i in xrange(0, col_count, chunk_size):
sub_mat = mat[:, i : i + chunk_size]
# num_samples x chunk_size
sub_mat = sub_mat.read().val
mean[i : i + chunk_size] = np.mean(sub_mat, axis=0)
std[i : i + chunk_size] = np.std(sub_mat, axis=0)
return mean, std
答案 0 :(得分:2)
我假设为了计算方差,您正在使用Wiki称为Naïve algorithm。但是,可能会在这里找到
由于
x2_sum / row_count
和x_mean ** 2
可以是非常相似的数字, 取消可能导致结果的精度大大降低 比浮点算法固有的精度 执行计算。因此,不应将这种算法用于 实践。如果标准偏差为 相对于均值而言较小。
作为替代,您可以使用two-pass algorithm,即先计算均值,然后在计算方差时使用它。原则上,这似乎是浪费的,因为必须对数据进行两次迭代。然而,在方差的计算中使用的“均值”不必是真实的均值,合理的估计值(也许仅从第一个块计算得出)就足够了。然后,这将简化为assumed mean的方法。
此外,一种可能性是将每个块的均值/方差的计算直接委派给numpy,然后将它们组合起来,以便使用parallel algorithm获得总体均值/方差。
答案 1 :(得分:2)
因此,我在大学里有一个项目,涉及不同矩阵乘法算法的时间复杂度测试。
我已经上传了源代码here。
我发现的一项优化是,您可以通过更改for循环的结构来优化数组访问,以一次专注于行,而不是遍历列。这是由于缓存的行为具有空间局部性(例如,您的计算机尝试针对2D数组中并排而不是逐行的数组元素进行优化)
如果这些是“稀疏”矩阵(很多零元素),则可以更改数据结构以仅记录非零元素。
很显然,如果给定一个普通矩阵,那么将它们转换为稀疏矩阵的计算可能不值得,但我只是认为这些值得分享:)