【问题标题】:Compare rows by different columns in a dataframe按数据框中的不同列比较行
【发布时间】:2016-02-17 14:08:53
【问题描述】:

我有一个如下所示的数据框:

id   value1  value2   value3   value4
A      14       24       22        9
B      51       25       29       33
C       4       16        8       10
D       1        4        2        4       

现在我想将该行的每一列与其他行进行比较,以确定每个值都较高的行。

因此,例如对于 id D,这将是 A、B 和 C。 对于 C,它将是 B,对于 A,它是 B,对于 B,没有行。

我试图通过遍历行并比较每一列来做到这一点,但这需要很多时间。原始数据集有大约 5000 行和 20 列要比较。 我确信有一种方法可以更有效地做到这一点。感谢您的帮助!

【问题讨论】:

  • 订购矩阵有帮助吗?无论哪种方式都需要很多时间......
  • 你能显示预期的输出吗?
  • 我不太关心输出,一般来说我只需要一个列表——不管是数据框还是文本。
  • 我刚刚尝试了答案。我认为 Kota Mori 的答案是最好的,所以我检查了一下。我也从 DMC 的回答中学到了很多,所以也谢谢你!

标签: r dataframe compare


【解决方案1】:

我不知道执行此任务的简单函数。 这就是我会怎么做。

library(dplyr)

DF <- data.frame(
  id = c("A", "B", "C", "D"),
  value1 = c(14, 51, 4, 1),
  value2 = c(24, 25, 16, 4),
  value3 = c(22, 29, 8, 2),
  value4 = c(9, 33, 10, 4),
  stringsAsFactors = FALSE)

# get the order for each value
tmp <- lapply(select(DF, -id), function(x) DF$id[order(x)]) 

# find a set of "biggers" for each id 
tmp <- lapply(tmp, function(x) data.frame(
    id = rep(x, rev(seq_along(x))-1), 
    bigger = x[lapply(seq_along(x), function(i)
      which(seq_along(x) > i)) %>% unlist()],
    stringsAsFactors = FALSE)) 

# inner_join all, this keeps "biggers" in all columns
out <- NULL
for (v in tmp) {
  if (is.null(out)) {
    out <- v
  } else {
    out <- inner_join(out, v, by = c("id", "bigger"))
  }
}

这让你:

out
#  id bigger
#1  D      C
#2  D      A
#3  D      B
#4  C      B
#5  A      B

【讨论】:

    【解决方案2】:

    这是一种以数据框格式返回结果的方法。

    library(tidyr)
    library(dplyr)
    
    # reshape data to long format
    td <- d %>% gather(key, value, value1:value4)
    
    # create a copy w/ different names for merging
    td2 <- td %>% select(id2 = id, key, value2 = value)
    
    # full outer join to produce one row per pair of IDs
    dd <- merge(td, td2, by = "key", all = TRUE)
    
    # the result
    dd %>%
      filter(id != id2) %>% 
      group_by(id, id2) %>%
      summarise(all_less = !any(value >= value2)) %>%
      filter(all_less)
    

    结果(id小于id2)

         id    id2 all_less
      (fctr) (fctr)    (lgl)
    1      A      B     TRUE
    2      C      B     TRUE
    3      D      A     TRUE
    4      D      B     TRUE
    5      D      C     TRUE
    

    数据

    d <- structure(list(
      id = structure(1:4, .Label = c("A", "B", "C", "D"), class = "factor"), 
      value1 = c(14L, 51L, 4L, 1L), 
      value2 = c(24L, 25L, 16L, 4L), 
      value3 = c(22L, 29L, 8L, 2L), value4 = c(9L, 33L, 10L, 4L)
    ), 
    .Names = c("id", "value1", "value2", "value3", "value4"), 
    class = "data.frame", row.names = c(NA, -4L)
    )
    

    【讨论】:

      【解决方案3】:

      我认为这很好用:

      ind <- which(names(df) == "id")
      apply(df[,-ind],1,function(x) df$id[!rowSums(!t(x < t(df[,-ind])))] )
      # [[1]]
      # [1] "B"
      # 
      # [[2]]
      # character(0)
      # 
      # [[3]]
      # [1] "B"
      # 
      # [[4]]
      # [1] "A" "B" "C"
      

      【讨论】:

        猜你喜欢
        • 2022-11-16
        • 1970-01-01
        • 2018-01-25
        • 1970-01-01
        • 2021-05-01
        • 2017-03-28
        • 1970-01-01
        • 2022-11-17
        • 2021-07-17
        相关资源
        最近更新 更多