【发布时间】:2012-04-21 12:47:59
【问题描述】:
我有 1 个名为 A 的 data.frame,其中有 5000 列。如何在此 data.frame 中找到彼此相等的列。
【问题讨论】:
我有 1 个名为 A 的 data.frame,其中有 5000 列。如何在此 data.frame 中找到彼此相等的列。
【问题讨论】:
正如@John 提到的,使用duplicated 存在问题。我要补充一点,在与duplicated 进行比较之前,转置 data.frame 会强制将所有数据转换为相同的数据类型。举个例子,这里是一个data.frame:
df <- data.frame( a = LETTERS[1:3],
b = 1:3,
c = as.character(1:3),
d = LETTERS[1:3],
e = 1:3,
f = 1:3)
df
# a b c d e f
# 1 A 1 1 A 1 1
# 2 B 2 2 B 2 2
# 3 C 3 3 C 3 3
请注意,c 列与b、e 和f 列非常相似,但由于类型不同(字符与数字)而不相同。 @Jubbles 建议的解决方案将忽略这些差异。
相反,在 data.frame 的列上使用 identical 函数似乎更合适。您可以使用outer 两两比较列:
are.cols.identical <- function(col1, col2) identical(df[,col1], df[,col2])
identical.mat <- outer(colnames(df), colnames(df),
FUN = Vectorize(are.cols.identical))
identical.mat
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] TRUE FALSE FALSE TRUE FALSE FALSE
# [2,] FALSE TRUE FALSE FALSE TRUE TRUE
# [3,] FALSE FALSE TRUE FALSE FALSE FALSE
# [4,] TRUE FALSE FALSE TRUE FALSE FALSE
# [5,] FALSE TRUE FALSE FALSE TRUE TRUE
# [6,] FALSE TRUE FALSE FALSE TRUE TRUE
从这里,您可以使用聚类来识别相同列的组(可能有更好的方法,所以如果您知道,请随时评论甚至编辑我的答案。)
library(cluster)
distances <- as.dist(!identical.mat)
tree <- hclust(distances)
cut <- cutree(tree, h = 0.5)
cut
# [1] 1 2 3 1 2 2
split(colnames(df), cut)
# $`1`
# [1] "a" "d"
#
# $`2`
# [1] "b" "e" "f"
#
# $`3`
# [1] "c"
编辑1:忽略浮点值的差异,可以使用
are.cols.identical <- function(col1,col2) isTRUE(all.equal((df[,col1],df[,col2]))
编辑 2: 一种比聚类更有效的方法来对相同列的名称进行分组是
cut <- apply(identical.mat, 1, function(x)match(TRUE, x))
split(colnames(df), cut)
【讨论】:
which(identical.mat, arr.ind = TRUE)(仅使用 lower.tri() 会更好)
which 是一个很好的选择。此外,如果将上面的 identical() 替换为 isTRUE(all.equal()),则可以解决(即忽略)浮点差异。
这个问题与here 的问题非常相似,有细微的差别,但有相同的注意事项。
我再次建议使用digest(),如下所示(感谢@flodel 提供的data.frame 以及上面的非常好的建议)
df <- data.frame( a = LETTERS[1:3],
b = 1:3,
c = as.character(1:3),
d = LETTERS[1:3],
e = 1:3,
f = 1:3)
dfDig <- sapply(df, digest)
ansL <- lapply(seq_along(dfDig), function(x) names(which(dfDig == dfDig[x])))
unique(ansL)
# [[1]]
# [1] "a" "d"
# [[2]]
# [1] "b" "e" "f"
# [[3]]
# [1] "c"
不过,这仍然无法区分 1.0 和 1。
编辑
正如@flodel 在 cmets 中所建议的,在创建 dfDig 之后可以使用以下替代方法
split(colnames(df), vapply(dfDig, match, 1L, dfDig))
【讨论】:
digest,谢谢你的建议。
match 可能比which 更快。这似乎有效:split(colnames(df), vapply(dfDig, match, 1L, dfDig))
转置数据帧并使用duplicated()怎么样?
B <- as.data.frame(t(A))
dup1 <- duplicated(B)
# if you want to identify all duplicated rows
dup2 <- duplicated(B, fromLast = TRUE)
dup_final <- dup1 * dup2
saved_colnames <- colnames(A)[dup_final]
【讨论】: