【问题标题】:Count similarity of occurrences across columns R计算列 R 中出现的相似性
【发布时间】:2022-07-20 11:35:49
【问题描述】:

我有以下数据:

df <- data.frame(
  group = c('r1','r2','r3','r4'),
  X1 = c('A','B','C','K'),
  X2 = c('A','C','M','K'),
  X3 = c('D','A','C','K')
)

> df
  group X1 X2 X3
1    r1  A  A  D
2    r2  B  C  A
3    r3  C  M  C
4    r4  K  K  K

我想根据X1X2X3 列估算“相似度得分”。例如,在group r1(或第 1 行)内,3 个元素中有 2 个是相似的,因此得分为 2/3(~67%)。而group r4(或第 4 行),得分为 3/3 (100%)。期望的结果如下:

> df
  group X1 X2 X3 similarity_score
1    r1  A  A  D .67
2    r2  B  C  A .33
3    r3  C  M  C .67
4    r4  K  K  K 1

我怎样才能做到这一点?

【问题讨论】:

  • 这是一个绝妙的问题,有很多绝妙的答案

标签: r dplyr


【解决方案1】:

另一种可能的解决方案:

library(dplyr)

df %>% 
  rowwise %>% 
  mutate(score = max(prop.table(table(c_across(X1:X3))))) %>% 
  ungroup

#> # A tibble: 4 × 5
#>   group X1    X2    X3    score
#>   <chr> <chr> <chr> <chr> <dbl>
#> 1 r1    A     A     D     0.667
#> 2 r2    B     C     A     0.333
#> 3 r3    C     M     C     0.667
#> 4 r4    K     K     K     1

甚至更短:

library(tidyverse)
df %>% mutate(score = pmap_dbl(across(X1:X3), ~ max(prop.table(table(c(...))))))

【讨论】:

  • 不错的答案!不过,如果“3”没有被硬编码,这将更普遍。
  • @jdobres:我可以得到一个更短的替代方案来避免以前硬编码的3
【解决方案2】:

你可以的

df$similarity <- round(apply(df[-1], 1, function(x) max(table(x))/length(x)), 2)

df
#>   group X1 X2 X3 similarity
#> 1    r1  A  A  D       0.67
#> 2    r2  B  C  A       0.33
#> 3    r3  C  M  C       0.67
#> 4    r4  K  K  K       1.00

reprex package (v2.0.1) 于 2022-04-18 创建

【讨论】:

    【解决方案3】:

    tidyverse 解决方案:

    library(tidyverse)
    
    df %>% 
      rowwise() %>% 
      mutate(
        similarity_score = max(colMeans(outer(c_across(-group), c_across(-group), `==`)))
      ) 
    

    或者代替c_across,您可以使用nest 解决方案:

    df %>% 
      group_by(group) %>% 
      nest(data = -group) %>% 
      rowwise() %>% 
      mutate(
        similarity_score = max(colMeans(outer(unlist(data), unlist(data), `==`)))
      ) %>% 
      unnest(data)
    
      group X1    X2    X3    similarity_score
      <chr> <chr> <chr> <chr>            <dbl>
    1 r1    A     A     D                0.667
    2 r2    B     C     A                0.333
    3 r3    C     M     C                0.667
    4 r4    K     K     K                1   
    

    【讨论】:

      【解决方案4】:

      作为另一种选择,我们可以一次存储所有出现的事件(而不是按行操作):

      tab = table(rep(df[, 1], ncol(df) - 1), as.matrix(df[, -1]))
      

      然后,检索每行最多元素的比例:

      tab = tab / rowSums(tab)
      tab[cbind(1:nrow(df), max.col(tab))]
      #[1] 0.6666667 0.3333333 0.6666667 1.0000000
      

      【讨论】:

        【解决方案5】:

        另一种可能的选择是先旋转更长的时间进行汇总,然后再加入数据框。

        library(tidyverse)
        
        df %>%
          left_join(pivot_longer(., -group) %>%
                      group_by(group) %>%
                      summarise(score = round(max(table(value))/length(value), 2)))
        

        输出

          group X1 X2 X3 score
        1    r1  A  A  D  0.67
        2    r2  B  C  A  0.33
        3    r3  C  M  C  0.67
        4    r4  K  K  K  1.00
        

        【讨论】:

          【解决方案6】:

          这是基础 R 中的另一种方式:

          df$score <- round(sapply(apply(df[,c(2:4)], 1, table), first) / 3, 2) 
          
          #   group X1 X2 X3 similarity_score
          # 1    r1  A  A  D             0.67
          # 2    r2  B  C  A             0.33
          # 3    r3  C  M  C             0.67
          # 4    r4  K  K  K             1.00
          

          【讨论】:

            猜你喜欢
            • 2011-02-04
            • 1970-01-01
            • 1970-01-01
            • 2017-12-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-08-12
            • 1970-01-01
            相关资源
            最近更新 更多