r (stats) 中用于聚类的 dist 函数:我应该将我的 ID 变量放在 row.names 中吗?

dist function in r (stats) for clustering: Should I put my ID variable in row.names?

我有一个包含一些数字列和一个字符 ID 列的数据框。当我在 dist 函数中传递整个数据帧时,它会计算距离矩阵,但是当我删除 ID 列并将其传递给距离函数时,我不会得到相同的结果。
1) 为什么会出现这种奇怪的行为?
2) 在 R 中如何处理 "ID" 列?我应该删除 ID 列还是应该将它们放入 row.names.

PS 我通常使用 tibbles 和 tidyverse 中的工具。

当我们将包含 factor/character 个变量的数据帧传递给 dist 时会发生什么并不明显。

首先,如果是数字数据的字符,比如c("1", "2"),那么它会被强制转换回数字数据。在那种情况下,除非 ID 之间的差异有意义,否则您显然不应包含此变量。

现在让我们考虑一个问题,如果我们有一个不是上述类型的字符因子会发生什么。在 C source code 中,我们找到了一些重要的行:

static double R_euclidean(double *x, int nr, int nc, int i1, int i2)
{
    double dev, dist;
    int count, j;

    count= 0;
    dist = 0;
    for(j = 0 ; j < nc ; j++) {
    if(both_non_NA(x[i1], x[i2])) {
        dev = (x[i1] - x[i2]);
        if(!ISNAN(dev)) {
        dist += dev * dev;
        count++;
        }
    }
    i1 += nr;
    i2 += nr;
    }
    if(count == 0) return NA_REAL;
    if(count != nc) dist /= ((double)count/nc);
    return sqrt(dist);
}

首先(不在此函数中),factor/character 变量在尝试将它们转换为整数时被强制转换为 NA。 (警告消息也这么说。)结果,正如我们在 R_euclidean 的代码中看到的,我们进行了一些重新缩放:

if(count != nc) dist /= ((double)count/nc);
return sqrt(dist);

其中 nc 是总列数,count 是数值列数。我们可以验证这一点:

k <- 20
df <- data.frame(a = sample(letters, k, replace = TRUE), 
                 b = sample(letters, k, replace = TRUE), 
                 c = rnorm(k), d = rnorm(k))

max(abs(as.matrix(dist(df)) * sqrt(2 / ncol(df)) - as.matrix(dist(df[, 3:4]))))
# [1] 7.467696e-09

也就是说,我们比较了 df 没有重新缩放(乘以 sqrt(2 / ncol(df)))的距离矩阵和没有两个因子变量的距离矩阵。好像有一些数值上的错误但是矩阵基本一样

因此,这解释了为什么结果不同。如果您打算使用单个矩阵进行聚类,则保留 factors/characters 似乎没问题,因为比例无关紧要。但是,在比例很重要的情况下,您应该先删除 factor/character 列。 (是将您的 ID 变量用作行名称还是用作单独的向量并不重要,这取决于您。)