【问题标题】:Find columns with same data in one data.frame在一个 data.frame 中查找具有相同数据的列
【发布时间】:2012-04-21 12:47:59
【问题描述】:

我有 1 个名为 A 的 data.frame,其中有 5000 列。如何在此 data.frame 中找到彼此相等的列。

【问题讨论】:

    标签: r dataframe


    【解决方案1】:

    正如@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)
    

    【讨论】:

    • 我的支持。感谢您提供比我更详尽的答案。
    • 我喜欢这里使用集群。这里还有更多潜在答案的空间,因为这个问题没有解决浮点值差异问题,即使这些值基本相同。
    • 从 same.mat 中提取信息的另一种方法可能是...which(identical.mat, arr.ind = TRUE)(仅使用 lower.tri() 会更好)
    • 谢谢@John。如果用户想要显示每对重复数据,which 是一个很好的选择。此外,如果将上面的 identical() 替换为 isTRUE(all.equal()),则可以解决(即忽略)浮点差异。
    【解决方案2】:

    这个问题与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))
    

    【讨论】:

    • +1 - 很好,非常简洁。我不知道digest,谢谢你的建议。
    • 使用match 可能比which 更快。这似乎有效:split(colnames(df), vapply(dfDig, match, 1L, dfDig))
    • @flodel,这是一个很好的建议。我会在上面添加。
    【解决方案3】:

    转置数据帧并使用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]
    

    【讨论】:

    • @David Kakauridze:我认为我添加的最后一行应该解决这个问题。
    • duplicated() 命令会将每个值视为文本。某些值在某些情况下可能被认为是相等的,但不是文本(甚至不是它们的自然形式)。例如,许多为 0 的值不会被表示为这样,(例如 tan(pi))。浮点数在这里可能是一个严重的问题。对于提问者的情况可能很好,但应该警告未来的读者,这不是一个通用的解决方案。 (没有更复杂的功能就没有通用的解决方案)
    • @John:谢谢你的警告。我提出的答案无疑是“快速而肮脏的”,并且正如您所指出的那样,对于特殊情况来说已经成熟了。
    猜你喜欢
    • 2014-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多