Python 3.x Python中的缺失值插补

Python 3.x Python中的缺失值插补,python-3.x,numpy,scipy,missing-data,Python 3.x,Numpy,Scipy,Missing Data,我有两个巨大的向量项_簇和β。元素项\u clusters[i]是项i所属的集群id。元素beta[i]是对项目i的评分。分数是{-1,0,1,2,3} 每当某个项目的得分为0时,我就必须用属于同一类的其他项目的平均非零分来计算。最快的方法是什么 这就是我迄今为止所尝试的。我将项目\u集群转换为矩阵集群\u到\u项目,这样如果集群I包含项目j,元素集群\u到\u项目[I][j]=1,否则为0。之后,我运行以下代码 # beta (1x1.3M) csr matrix # num_clusters

我有两个巨大的向量项_簇β。元素项\u clusters[i]是项i所属的集群id。元素beta[i]是对项目i的评分。分数是{-1,0,1,2,3}

每当某个项目的得分为0时,我就必须用属于同一类的其他项目的平均非零分来计算。最快的方法是什么

这就是我迄今为止所尝试的。我将项目\u集群转换为矩阵集群\u到\u项目,这样如果集群I包含项目j,元素集群\u到\u项目[I][j]=1,否则为0。之后,我运行以下代码

# beta (1x1.3M) csr matrix
# num_clusters = 1000
# item_clusters (1x1.3M) numpy.array
# clust_to_items (1000x1.3M) csr_matrix

alpha_z = []
for clust in range(0, num_clusters):
    alpha = clust_to_items[clust, :]
    alpha_beta = beta.multiply(alpha)
    sum_row = alpha_beta.sum(1)[0, 0]
    num_nonzero = alpha_beta.nonzero()[1].__len__() + 0.001
    to_impute = sum_row / num_nonzero
    Z = np.repeat(to_impute, beta.shape[1])
    alpha_z = alpha.multiply(Z)
    idx = beta.nonzero()
    alpha_z[idx] = beta.data
interact_score = alpha_z.tolist()[0]

# The interact_score is the required modified beta 
# This is used to do some work that is very fast
问题是这段代码必须运行15万次,而且速度非常慢。根据我的估计,运行需要12天

编辑:我相信,我需要一些非常不同的想法,我可以直接使用item_集群,而不需要分别遍历每个集群。

我的怀疑是

alpha_beta = beta.multiply(alpha)
这是一个糟糕的想法,因为您只需要行和的第一个元素,所以如果我没有弄错的话,您做了数百万次乘法和运算是徒劳的:

sum_row = alpha_beta.sum(1)[0, 0]

因此,写下beta*alpha的离散公式,然后选择所需的行,并导出其总和的公式

我不知道这是否意味着我是这里最受欢迎的孩子,但我认为你可以通过以下方式将你的操作矢量化:

def fast_impute(num_clusters, item_clusters, beta):

    # get counts
    cluster_counts = np.zeros(num_clusters)
    np.add.at(cluster_counts, item_clusters, 1)

    # get complete totals
    totals = np.zeros(num_clusters)
    np.add.at(totals, item_clusters, beta)

    # get number of zeros
    zero_counts = np.zeros(num_clusters)
    z = beta == 0
    np.add.at(zero_counts, item_clusters, z)

    # non-zero means
    cluster_means = totals / (cluster_counts - zero_counts)

    # perform imputations
    imputed_beta = np.where(beta != 0, beta, cluster_means[item_clusters])

    return imputed_beta
这让我

>>> N = 10**6
>>> num_clusters = 1000
>>> item_clusters = np.random.randint(0, num_clusters, N)
>>> beta = np.random.choice([-1, 0, 1, 2, 3], size=len(item_clusters))
>>> %time imputed = fast_impute(num_clusters, item_clusters, beta)
CPU times: user 652 ms, sys: 28 ms, total: 680 ms
Wall time: 679 ms


请注意,我是手动执行上述操作的。如果您使用的是更高级别的工具,例如以下提供的工具,则会容易得多:


好吧,我将是这里不受欢迎的孩子:Python是一种很棒的语言,但是如果性能和这里一样令人担忧,尤其是如果你处理大量原始数据,这是你的热点,大部分时间都花在这里,用C实现它。你能找出哪一行代码占用的时间最多吗?提示:看看numpy的
ufunc
。其思想是alpha和beta都是向量。只有当beta元素属于集群clust(即alpha值为1)时,我才需要获取beta元素的总和。这就是为什么我要将alpha和beta元素相乘。alpha_beta sum是一个元素的矩阵。为了得到实际的浮点值,我必须明确提到[0][0]。@SonuKMishra提示:sum(元素乘积)可以一步计算出来,即dot product,但我不需要只求sum。我需要一个平均值,我也需要这样的元素的数量。另外,我还使用了一个乘法,所以去掉一个将使我的速度提高2倍。我需要的远不止这些。请看我在问题中的编辑注释。我相信,如果我能以某种方式摆脱for循环,那将非常棒!
>>> imputed[:5]
array([ 1.27582017, -1.        , -1.        ,  1.        ,  3.        ])
>>> item_clusters[:5]
array([506, 968, 873, 179, 269])
>>> np.mean([b for b, i in zip(beta, item_clusters) if i == 506 and b != 0])
1.2758201701093561
>>> df = pd.DataFrame({"beta": beta, "cluster": item_clusters})
>>> df.head()
   beta  cluster
0     0      506
1    -1      968
2    -1      873
3     1      179
4     3      269
>>> df["beta"] = df["beta"].replace(0, np.nan)
>>> df["beta"] = df["beta"].fillna(df["beta"].groupby(df["cluster"]).transform("mean"))
>>> df.head()
      beta  cluster
0  1.27582      506
1 -1.00000      968
2 -1.00000      873
3  1.00000      179
4  3.00000      269