根据 R 中的行列相似性修剪数据框
Prune a dataframe based on row-wise column similarity in R
我有一个非常大的基因组位点数据框,基因型评分为 0、1 或 2。这是我认为解决问题的一个非常小的样本:
x1 x2 x3 x4
0 0 1 0
0 0 1 0
1 1 2 1
1 1 1 1
2 2 0 1
2 2 1 2
基因座 x1 和 x2 相同,而 x4 高度相似。我希望实现的是创建一个函数,或者使用一个已经存在的函数,为我的每个基因座按行分配相似性分数,然后根据我设置的阈值相似性修剪数据集。
例如,如果我将阈值设置为 1 (100%),它只会修剪 x1 和 x2,因为它们是重复的——我知道该怎么做。但是,如果我将阈值设置为 0.8,即相似度为 80%,那么除了 x1 和 x2 之外,它还会修剪 x4。
重要的是,该函数作用于逐行相似性,而不仅仅是比较具有相似分布的 0、1 和 2 的列。
以下是我的处理方法。
首先,获取列名称的所有唯一配对的列表:
pairs <- expand.grid(names(df), names(df))
pairs <- pairs[lower.tri(replicate(length(df), names(df))),]
pairs
#> Var1 Var2
#> 2 x2 x1
#> 3 x3 x1
#> 4 x4 x1
#> 7 x3 x2
#> 8 x4 x2
#> 12 x4 x3
现在遍历它以比较原始数据集中每对唯一列中相同行的比例。这为每对列提供了 0 到 1 之间的相似性分数:
pairs$similarity <- apply(pairs, 1, function(x) sum(df[x[1]] == df[x[2]])/nrow(df))
pairs
#> Var1 Var2 similarity
#> 2 x2 x1 1.0000000
#> 3 x3 x1 0.1666667
#> 4 x4 x1 0.8333333
#> 7 x3 x2 0.1666667
#> 8 x4 x2 0.8333333
#> 12 x4 x3 0.1666667
现在删除此列表中相似度分数低于您选择的阈值的所有行(我们将在此处设为 0.8)
pairs <- pairs[which(pairs$similarity > 0.8),]
pairs
#> Var1 Var2 similarity
#> 2 x2 x1 1.0000000
#> 4 x4 x1 0.8333333
#> 8 x4 x2 0.8333333
现在我们提取 Var1
和 Var2
中的所有唯一列名称,因为这些列与至少一个其他列相似:
keep_cols <- as.character(sort(unique(c(pairs$Var1, pairs$Var2))))
#> [1] "x1" "x2" "x4"
然后我们使用它对原始数据框进行子集化以获得我们想要的结果:
df[match(keep_cols, names(df))]
#> x1 x2 x4
#> 1 0 0 0
#> 2 0 0 0
#> 3 1 1 1
#> 4 1 1 1
#> 5 2 2 1
#> 6 2 2 2
当然,您可以将所有这些放在一个函数中,以便更轻松地调整阈值并迭代应用:
remove_dissimilar <- function(df, threshold = 0.8) {
pairs <- expand.grid(names(df), names(df))
pairs <- pairs[lower.tri(replicate(length(df), names(df))),]
pairs$similarity <- apply(pairs, 1, function(x) {
sum(df[x[1]] == df[x[2]])/nrow(df)})
pairs <- pairs[which(pairs$similarity > threshold),]
keep_cols <- as.character(sort(unique(c(pairs$Var1, pairs$Var2))))
df[match(keep_cols, names(df))]
}
所以现在你可以这样做:
remove_dissimilar(df, 0.8)
#> x1 x2 x4
#> 1 0 0 0
#> 2 0 0 0
#> 3 1 1 1
#> 4 1 1 1
#> 5 2 2 1
#> 6 2 2 2
remove_dissimilar(df, 0.9)
#> x1 x2
#> 1 0 0
#> 2 0 0
#> 3 1 1
#> 4 1 1
#> 5 2 2
#> 6 2 2
我有一个非常大的基因组位点数据框,基因型评分为 0、1 或 2。这是我认为解决问题的一个非常小的样本:
x1 x2 x3 x4
0 0 1 0
0 0 1 0
1 1 2 1
1 1 1 1
2 2 0 1
2 2 1 2
基因座 x1 和 x2 相同,而 x4 高度相似。我希望实现的是创建一个函数,或者使用一个已经存在的函数,为我的每个基因座按行分配相似性分数,然后根据我设置的阈值相似性修剪数据集。
例如,如果我将阈值设置为 1 (100%),它只会修剪 x1 和 x2,因为它们是重复的——我知道该怎么做。但是,如果我将阈值设置为 0.8,即相似度为 80%,那么除了 x1 和 x2 之外,它还会修剪 x4。
重要的是,该函数作用于逐行相似性,而不仅仅是比较具有相似分布的 0、1 和 2 的列。
以下是我的处理方法。
首先,获取列名称的所有唯一配对的列表:
pairs <- expand.grid(names(df), names(df))
pairs <- pairs[lower.tri(replicate(length(df), names(df))),]
pairs
#> Var1 Var2
#> 2 x2 x1
#> 3 x3 x1
#> 4 x4 x1
#> 7 x3 x2
#> 8 x4 x2
#> 12 x4 x3
现在遍历它以比较原始数据集中每对唯一列中相同行的比例。这为每对列提供了 0 到 1 之间的相似性分数:
pairs$similarity <- apply(pairs, 1, function(x) sum(df[x[1]] == df[x[2]])/nrow(df))
pairs
#> Var1 Var2 similarity
#> 2 x2 x1 1.0000000
#> 3 x3 x1 0.1666667
#> 4 x4 x1 0.8333333
#> 7 x3 x2 0.1666667
#> 8 x4 x2 0.8333333
#> 12 x4 x3 0.1666667
现在删除此列表中相似度分数低于您选择的阈值的所有行(我们将在此处设为 0.8)
pairs <- pairs[which(pairs$similarity > 0.8),]
pairs
#> Var1 Var2 similarity
#> 2 x2 x1 1.0000000
#> 4 x4 x1 0.8333333
#> 8 x4 x2 0.8333333
现在我们提取 Var1
和 Var2
中的所有唯一列名称,因为这些列与至少一个其他列相似:
keep_cols <- as.character(sort(unique(c(pairs$Var1, pairs$Var2))))
#> [1] "x1" "x2" "x4"
然后我们使用它对原始数据框进行子集化以获得我们想要的结果:
df[match(keep_cols, names(df))]
#> x1 x2 x4
#> 1 0 0 0
#> 2 0 0 0
#> 3 1 1 1
#> 4 1 1 1
#> 5 2 2 1
#> 6 2 2 2
当然,您可以将所有这些放在一个函数中,以便更轻松地调整阈值并迭代应用:
remove_dissimilar <- function(df, threshold = 0.8) {
pairs <- expand.grid(names(df), names(df))
pairs <- pairs[lower.tri(replicate(length(df), names(df))),]
pairs$similarity <- apply(pairs, 1, function(x) {
sum(df[x[1]] == df[x[2]])/nrow(df)})
pairs <- pairs[which(pairs$similarity > threshold),]
keep_cols <- as.character(sort(unique(c(pairs$Var1, pairs$Var2))))
df[match(keep_cols, names(df))]
}
所以现在你可以这样做:
remove_dissimilar(df, 0.8)
#> x1 x2 x4
#> 1 0 0 0
#> 2 0 0 0
#> 3 1 1 1
#> 4 1 1 1
#> 5 2 2 1
#> 6 2 2 2
remove_dissimilar(df, 0.9)
#> x1 x2
#> 1 0 0
#> 2 0 0
#> 3 1 1
#> 4 1 1
#> 5 2 2
#> 6 2 2