【问题标题】:Rank correlation with weights for frequencies, in PythonPython中与频率权重的排名相关性
【发布时间】:2018-02-25 20:45:04
【问题描述】:

我的数据是一组 n 观察到的对及其频率,即每对 (xi, yi)里面对应一些ki,次数(xi,yi) 被观察到。理想情况下,我想为这些对的所有副本的集合计算 Kendall 的 tau 和 Spearman 的 rho,其中包括 k1 + k2 + ... + kn 对。问题是k1 + k2 + ... + kn,观察的总数, 是巨大的,这样的数据结构不适合内存。

当然,我考虑分配第i对的频率,ki/(k1 + k2 + ... + kn),作为其权重,并计算加权集的等级相关性——但我找不到任何工具.在我遇到的各种加权等级相关性(例如,scipy.stats.weightedtau)中,权重代表等级而不是对的重要性,这与我的事业无关。 Pearson 的 r 似乎正好有我需要的加权选项,但它不符合我的目的,因为 xy 没有线性相关。我想知道我是否遗漏了一些关于加权数据点的广义相关性的概念。

到目前为止我唯一的想法是缩小 k1, k2, ..., kn sub> 乘以某个公因子 c,因此第 i 对的缩放副本数为 [ki/c] (这里 [.] 是舍入运算符,因为我们需要每对有整数个副本)。通过选择 c 使得 [k1/c] + [k2/c] + ... + [kn/c] 对可以放入内存,然后我们可以计算结果集的相关系数 tau 和 rho。但是,kikj 可以相差多个数量级,因此 c i> 对于某些 ki 可能非常大,因此四舍五入 ki/c 会导致信息丢失。

UPD:可以在具有指定频率权重的数据集上计算 Spearman 的 rho 和 p 值,如下所示:

def frequency_pearsonr(data, frequencies):
    """
    Calculates Pearson's r between columns (variables), given the
    frequencies of the rows (observations).

    :param data: 2-D array with data
    :param frequencies: 1-D array with frequencies
    :return: 2-D array with pairwise correlations,
        2-D array with pairwise p-values
    """
    df = frequencies.sum() - 2
    Sigma = np.cov(data.T, fweights=frequencies)
    sigma_diag = Sigma.diagonal()
    Sigma_diag_pairwise_products = np.multiply.outer(sigma_diag, sigma_diag)
    # Calculate matrix with pairwise correlations.
    R = Sigma / np.sqrt(Sigma_diag_pairwise_products)
    # Calculate matrix with pairwise t-statistics. Main diagonal should
    # get 1 / 0 = inf.
    with np.errstate(divide='ignore'):
        T = R / np.sqrt((1 - R * R) / df)
    # Calculate matrix with pairwise p-values.
    P = 2 * stats.t.sf(np.abs(T), df)

    return R, P


def frequency_rank(data, frequencies):
    """
    Ranks 1-D data array, given the frequency of each value. Same
    values get same "averaged" ranks. Array with ranks is shaped to
    match the input data array.

    :param data: 1-D array with data
    :param frequencies: 1-D array with frequencies
    :return: 1-D array with ranks
    """
    s = 0
    ranks = np.empty_like(data)
    # Compute rank for each unique value.
    for value in sorted(set(data)):
        index_grid = np.ix_(data == value)
        # Find total frequency of the value.
        frequency = frequencies[index_grid].sum()
        ranks[index_grid] = s + 0.5 * (frequency + 1)
        s += frequency    

    return ranks


def frequency_spearmanrho(data, frequencies):
    """
    Calculates Spearman's rho between columns (variables), given the
    frequencies of the rows (observations).

    :param data: 2-D array with data
    :param frequencies: 1-D array with frequencies
    :return: 2-D array with pairwise correlations,
        2-D array with pairwise p-values
    """
    # Rank the columns.
    ranks = np.empty_like(data)
    for i, data_column in enumerate(data.T):
        ranks[:, i] = frequency_rank(data_column, frequencies)
    # Compute Pearson's r correlation and p-values on the ranks.
    return frequency_pearsonr(ranks, frequencies)


# Columns are variables and rows are observations, whose frequencies
# are specified.
data_col1 = np.array([1, 0, 1, 0, 1])
data_col2 = np.array([.67, .25, .75, .2, .6])
data_col3 = np.array([.1, .3, .8, .3, .2])
data = np.array([data_col1, data_col2, data_col3]).T
frequencies = np.array([2, 4, 1, 3, 2])

# Same data, but with observations (rows) actually repeated instead of
# their frequencies being specified.
expanded_data_col1 = np.array([1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1])
expanded_data_col2 = np.array([.67, .67, .25, .25, .25, .25, .75, .2, .2, .2, .6, .6])
expanded_data_col3 = np.array([.1, .1, .3, .3, .3, .3, .8, .3, .3, .3, .2, .2])
expanded_data = np.array([expanded_data_col1, expanded_data_col2, expanded_data_col3]).T

# Compute Spearman's rho for data in both formats, and compare.
frequency_Rho, frequency_P = frequency_spearmanrho(data, frequencies)
Rho, P = stats.spearmanr(expanded_data)
print(frequency_Rho - Rho)
print(frequency_P - P)

上面的特定示例表明两种方法产生相同的相关性和相同的 p 值:

[[  0.00000000e+00   0.00000000e+00   0.00000000e+00]
 [  1.11022302e-16   0.00000000e+00  -5.55111512e-17]
 [  0.00000000e+00  -5.55111512e-17   0.00000000e+00]]
[[  0.00000000e+00  -1.35525272e-19   4.16333634e-17]
 [ -9.21571847e-19   0.00000000e+00  -5.55111512e-17]
 [  4.16333634e-17  -5.55111512e-17   0.00000000e+00]]

【问题讨论】:

  • 要计算加权 Spearman 等级相关系数,您可以简单地预先排列您的 x 和 y 值,然后将它们推入 pearsonr(连同您的权重)以获得加权 Spearman 的 rho .
  • 不确定以下方法的统计有效性,但从技术角度来看,您可以简单地将(预先计算的)字典映射等级封装到函数中的归一化频率并将其作为 @ 987654325@到weightedtau
  • 让我直接回答你的问题,k1 + k2 + ... + kn 对观测值太大而无法放入 RAM。你能在随机样本上计算秩相关,增加样本量,重复这个过程,直到估计的秩相关低于某个阈值水平吗?
  • @Paul,您能否澄清一下您所说的“pre-rank”是什么意思?我认为您的第二个建议是有道理的,如果排名有任何不同(例如指数)并且交换权重是权重的乘积而不是总和(“additive = False”)。确实,如果 (x1, y1) 发生了 5 次, (x2, y2) 发生了 10 次,那么它们的交换权重∝ 50,也就是这次交换的次数,(x1, y1) (x2 , y2),如果在具有 5 个 (x1, y1) 实例和 10 个 (x2, y2) 实例的“扩展”数据集上计算常规 tau 相关性,将会发生。我会对此进行测试并报告。
  • @CTZhu 是的,你没看错,k1 + k2 + ... + kn 观察无法放入内存。事实上,它可能比内存容量大很多数量级。我不确定你在说什么阈值,因为我没有任何关于相关性应该是什么的先验。如果对于每个样本量,相关性都显着不同(这可能是因为任何内存可行的样本量都几乎没有足够的代表性),那么我们该怎么办?

标签: python algorithm scipy statistics correlation


【解决方案1】:

Paul 建议的计算 Kendall tau 的方法很有效。但是,您不必将排序数组的索引分配为等级,未排序的索引同样可以正常工作(如加权 tau 示例中所示)。权重也不需要归一化。

常规(未加权)Kendall 的 tau(在“扩展”数据集上):

stats.kendalltau([0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1],
                 [.25, .25, .25, .25, .2, .2, .2, .667, .667, .75, .6, .6])
KendalltauResult(correlation=0.7977240352174656, pvalue=0.0034446936330652677)

加权 Kendall 的 tau(在以出现次数为权重的数据集上):

stats.weightedtau([1, 0, 1, 0, 1],
                  [.667, .25, .75, .2, .6],
                  rank=False,
                  weigher=lambda r: [2, 4, 1, 3, 2][r],
                  additive=False)
WeightedTauResult(correlation=0.7977240352174656, pvalue=nan)

现在,由于 weightedtau 实现的特殊性,永远不会计算 p 值。我们可以使用最初提供的缩小出现次数的技巧来近似 p 值,但我非常感谢其他方法。根据可用内存量来决定算法行为对我来说似乎很痛苦。

【讨论】:

    猜你喜欢
    • 2011-04-11
    • 2014-08-26
    • 1970-01-01
    • 2014-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多