【问题标题】:count how many times a row appears in a different dataset计算一行在不同数据集中出现的次数
【发布时间】:2022-01-18 13:58:07
【问题描述】:

我有两个数据集 df1 和 df2

P1 <- c('A', 'A', 'B', NA)
P2 <- c('B', NA, 'B', 'B')
P3 <- c('A', 'B', 'B', 'A')
P4 <- c('A', 'B', NA, 'B')
P5 <- c(NA, NA, NA, 'B')

df1 <- data.frame(P1, P2, P3, P4, P5, row.names = NULL)

[![enter image description here][2]][2]P1 <- c('A', 'A', 'B', 'B', 'A', 'B', 'B', 'A')
P2 <- c('B', 'B', 'B', 'B', 'B', 'B', 'A', 'B')
P3 <- c('A', 'B', 'B', 'A', 'A', 'B', 'B', 'A')
P4 <- c('A', 'B', 'B', 'B', 'A', 'B', 'A', 'B')
P5 <- c('B', 'B','B', 'B', 'B', 'B', 'A', 'B')

df2 <- data.frame(P1, P2, P3, P4, P5, row.names = NULL)

我需要计算 df1 中的每一行在 df2 中出现的次数。如果 df1 中的值为 NA,则可以是 df2 中的 A 和 B。例如,df1 中的第 4 行将计为 df2 中的第 4 行和第 8 行。

【问题讨论】:

    标签: r


    【解决方案1】:

    你可以试试

    row_appears <- c()
    for (i in 1:nrow(df1)){
      x <- df1[i,]
      y <- df1[i,]
      x[is.na(x)] <- "A"
      y[is.na(y)] <- "B"
      z <- sum(apply(df2, 1, function(t) all(x == t)) + apply(df2, 1, function(t) all(y == t)))
      row_appears <- c(row_appears, z)
    }
    row_appears
    
    [1] 2 1 2 2
    

    【讨论】:

    • 我已经有一段时间没有问这个问题了。但我只是注意到应用于真实数据的这个循环并没有给出正确的结果。该算法将所有 NA 值分配给所有 A 或所有 B 的原因。所以,如果我有这样一行“A,A,B,NA,NA”,这个算法会将它转换成“A,A,B,A,A”和“A,A,B,B,B” .但是,最后两个 NA 可以具有不同的值,如下所示:“A, A, B, A, B”和“A, A, B, B, A”。因此,这些模式仍未计算在内。
    【解决方案2】:

    或者,我们可以将 is 视为字符匹配问题,将两个数据帧都转换为字符向量,并将 NA 视为 A 或 B。

    df1[is.na(df1)] <- "(A|B)" # regex talk for "might be A or B"
    
    x <- do.call(paste, c(df1, sep = ""))
    y <- do.call(paste, c(df2, sep = ""))
    
    x |>
      lapply(\(.) stringi::stri_count_regex(y, .)) |>
      lapply(sum) |>
      unlist(use.names = F)
    
    #> [1] 2 1 2 2
    

    或者对于早于 4.1.0 的 R 版本:

    vapply(x, function(o) sum(stringi::stri_count_regex(y, o)), 1, USE.NAMES = F)
    

    【讨论】:

    • 我认为这个答案可以比第一个更好。有没有办法替换 |> 管道,因为 R 4.0.3 似乎不支持它?我试过 %>% 但我猜它的工作方式不同。
    • @YuliaKentieva |&gt; 管道和函数简写是在 R 4.1.0 中引入的,请参阅 this post 以了解与 magrittr 的 %&gt;% 的差异。 |&gt; 纯粹是语法转换——这意味着可以通过重写方法来获得相同的结果。我使用vapply 在原始帖子中添加了一种方法,它返回一个向量而不是一个列表。
    【解决方案3】:

    您也可以使用 {tidyverse} 或 {data.table}。

    library(tidyverse)
    df3 <- bind_rows(
      df1 |> mutate(across(everything(), replace_na, "A")),
      df1 |> mutate(across(everything(), replace_na, "B"))
    )
    
    df2 |> 
      group_by_all() |> 
      summarise(N = n(), .groups = "drop") |> 
      right_join(df3, by = paste0("P", 1:5)) |> 
      mutate(N = replace_na(N, 0))
    
    # # A tibble: 8 x 6
    # P1    P2    P3    P4    P5        N
    # <chr> <chr> <chr> <chr> <chr> <dbl>
    # 1 A     B     A     A     B         2
    # 2 A     B     A     B     B         1
    # 3 A     B     B     B     B         1
    # 4 B     B     A     B     B         1
    # 5 B     B     B     B     B         2
    # 6 A     B     A     A     A         0
    # 7 A     A     B     B     A         0
    # 8 B     B     B     A     A         0
    
    library(data.table)
    setDT(df1)
    setDT(df2)
    
    df1_a <- df1_b <- copy(df1)
    df1_a[is.na(df1_a)] <- "A"
    df1_b[is.na(df1_b)] <- "B"
    df3 <- rbindlist(list(df1_a, df1_b))
    
    df4 <- 
      df2[, .N, by = eval(paste0("P", 1:5))
      ][df3, on = paste0("P", 1:5)]
    
    df4[, N := fifelse(is.na(N), 0, N)][]
    
    
    #    P1 P2 P3 P4 P5 N
    # 1:  A  B  A  A  A 0
    # 2:  A  A  B  B  A 0
    # 3:  B  B  B  A  A 0
    # 4:  A  B  A  B  B 1
    # 5:  A  B  A  A  B 2
    # 6:  A  B  B  B  B 1
    # 7:  B  B  B  B  B 2
    # 8:  B  B  A  B  B 1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-20
      • 1970-01-01
      相关资源
      最近更新 更多