我编写了一个函数,它接受矩阵中列的成对关联(如pdist
中的内置scipy.stats
),但可以处理参数na_values
指定的缺失值。即:
def my_pdist(X, dist_func, na_values=["NA"]):
X = array(X, dtype=object)
num_rows, num_cols = X.shape
dist_matrix = []
for col1 in range(num_cols):
pdist_row = []
for col2 in range(num_cols):
pairs = array([[x, y] for x, y in zip(X[:, col1], X[:, col2]) \
if (x not in na_values) and (y not in na_values)])
if len(pairs) == 0:
continue
dist = dist_func(pairs[:, 0],
pairs[:, 1])
pdist_row.append(dist)
dist_matrix.append(pdist_row)
dist_matrix = array(dist_matrix)
return dist_matrix
其中dist_func
是指定距离度量的函数。有没有办法加快这个功能?使用它的一个例子是:
def spearman_dist(u, v, na_vals=["NA"]):
matrix = [[x, y] for x, y in zip(u, v) \
if (u not in na_vals) and (v not in na_vals)]
matrix = array(matrix)
spearman = scipy.stats.spearmanr(matrix[:, 0], matrix[:, 1])[0]
return 1 - spearman
my_pdist(X, spearman_dist, na_values=["NA"])
如何更快地进行矢量化/制作?
答案 0 :(得分:3)
我有一些建议:
不要使用类型为'object'的数组。这可以防止numpy使用它的任何内置优化,因为它被强制操作python对象而不是原始值。如果使用float数组,则可以使用np.nan而不是'NA'。对于整数数组,最好只在一个单独的数组中存储好/坏值的掩码(你也可以使用掩码数组,但我发现它们有点笨拙)。
我敢打赌,这条线占据了大部分时间:
pairs = array([[x, y] for x, y in zip(X[:, col1], X[:, col2]) \
if (x not in na_values) and (y not in na_values)])
所以你可以像这样加速内循环:
x1 = X[:, col1]
x2 = X[:, col2]
mask = ~np.isnan(x1) * ~np.isnan(x2)
if mask.sum() == 0:
continue
dist = dist_func(x1[mask], x2[mask])
不是使用list.append构建dist_matrix,而是从空数组开始并随时填充元素:
dist_matrix = np.empty((num_cols, num_cols))
for col1 in range(num_cols):
for col2 in range(num_cols):
...
dist_matrix[col1, col2] = dist
由于您在范围(num_cols)上迭代两次,因此您实际上计算了两次距离值。这可以优化:
dist_matrix = np.empty((num_cols, num_cols))
for col1 in range(num_cols):
for col2 in range(col1, num_cols):
...
dist_matrix[col1, col2] = dist
dist_matrix[col2, col1] = dist
可以在没有任何for循环的情况下进行整个计算,但这取决于dist_func的细节。
答案 1 :(得分:0)
你可以尝试用numpy的Masked Arrays替换你的na_vals。