【问题标题】:replace subset of vector values with subset average用子集平均值替换向量值的子集
【发布时间】:2017-07-02 05:40:20
【问题描述】:

我有一个有些凌乱的数据框,其中有一些科目排名,但有些排名并列。

    subj<-c("A","B","C,D,E","C,D,E","C,D,E","F","G,H","G,H","I")
    rank<-c(1,2,3,4,5,6,7,8,9)
    df<-data.frame(rank,subj)
    df
       rank  subj
    1    1     A
    2    2     B
    3    3 C,D,E
    4    4 C,D,E
    5    5 C,D,E
    6    6     F
    7    7   G,H
    8    8   G,H
    9    9     I   

当个人被捆绑时,我需要将他们的排名表示为捆绑位置的平均值。类似的东西

    n.rank n.subj
1    1.0      A
2    2.0      B
3    4.0      C
4    4.0      D
5    4.0      E
6    6.0      F
7    7.5      G
8    7.5      H
9    9.0      I

我曾尝试使用 strngsplit() 并按等级命名列表元素,但最终得到的数据框似乎同样难以处理。

 a<-strsplit(as.character(df$subj),",")
 names(a)<-df$rank
 b<-melt(a)
 colnames(b)<-c("n.subj","n.rank")
 b[1:10,]
     n.subj n.rank
 1       A      1
 2       B      2
 3       C      3
 4       D      3
 5       E      3
 6       C      4
 7       D      4
 8       E      4
 9       C      5
 10      D      5

当我使用gregexpr() 和regmatches() 来尝试识别需要平均的排名时,我也走到了死胡同。

    m<-gregexpr(",+",df$subj)
    df$no.avg<-melt(lapply(regmatches(df$subj, m),length))[,1]+1
    df
     rank  subj no.avg
  1    1     A      1
  2    2     B      1
  3    3 C,D,E      3
  4    4 C,D,E      3
  5    5 C,D,E      3
  6    6     F      1
  7    7   G,H      2
  8    8   G,H      2
  9    9     I      1

有什么创造性的解决方案吗?非常感谢。

【问题讨论】:

    标签: r regex subset average


    【解决方案1】:

    这是我的尝试。我首先计算平均排名,然后将相同排名的主题分成几行。

    library(tidyverse)
    options(stringsAsFactors = FALSE)
    subj <- c("A", "B", "C,D,E", "C,D,E", "C,D,E", "F", "G,H", "G,H", "I")
    rank <- c(1, 2, 3, 4, 5, 6, 7, 8, 9)
    df <- data.frame(rank, subj)
    
    df %>% 
      group_by(subj) %>% 
      summarise(rank = mean(rank)) %>% 
      rowwise() %>% 
      do(tibble(subj = unlist(strsplit(.$subj, ",")), rank = .$rank)) %>% 
      ungroup()
    

    输出:

    # A tibble: 9 × 2
       subj  rank
    * <chr> <dbl>
    1     A   1.0
    2     B   2.0
    3     C   4.0
    4     D   4.0
    5     E   4.0
    6     F   6.0
    7     G   7.5
    8     H   7.5
    9     I   9.0
    

    另一种方法:

    m <- aggregate(rank~subj, data=df, mean)
    m <- apply(m, 1, function(x) data.frame(subj = unlist(strsplit(x[1], ",")), rank = x[2]))
    m <- do.call(rbind, m)
    rownames(m) <- NULL
    m
    

    输出:

    subj rank
    1    A  1.0
    2    B  2.0
    3    C  4.0
    4    D  4.0
    5    E  4.0
    6    F  6.0
    7    G  7.5
    8    H  7.5
    9    I  9.0
    

    【讨论】:

    • 最后,我没有使用这个脚本,因为我不住在tidyverse,但是您按主题平均排名的逻辑首先使解决方案变得清晰。非常感谢。
    • @gavago 欢迎您。我添加了另一种不需要tidyverse 或dplyr 的方法。
    【解决方案2】:

    data.table版本:

    #library(data.table) #version 1.9.8
    setDT(df)
    df[, .(subj=unlist(strsplit(subj[1], ",")), rank=mean(rank)), by=subj][,-1]
    
    #   subj rank
    #1:    A  1.0
    #2:    B  2.0
    #3:    C  4.0
    #4:    D  4.0
    #5:    E  4.0
    #6:    F  6.0
    #7:    G  7.5
    #8:    H  7.5
    #9:    I  9.0
    

    【讨论】:

    • 当我在示例脚本上运行data.table 代码时,输​​出只是-1。我对data.table不是很熟悉,所以我不确定问题出在哪里。
    • @user3166232 尝试从末尾删除[,-1]。您可能有不同版本的软件包导致一些细微差别 - 我使用的是 v1.9.8。
    【解决方案3】:

    我的版本带有splitstackshape 和aggregate。逻辑一样,我们用逗号分割字符串,用subj取平均值。

    library(splitstackshape)
    aggregate(rank~subj, cSplit(df, "subj", ",", "long"), mean)
    
    #  subj rank
    #1    A  1.0
    #2    B  2.0
    #3    C  4.0
    #4    D  4.0
    #5    E  4.0
    #6    F  6.0
    #7    G  7.5
    #8    H  7.5
    #9    I  9.0
    

    在哪里

    cSplit(df, "subj", ",", "long")
    

    给予

    #     rank subj
    # 1:    1    A
    # 2:    2    B
    # 3:    3    C
    # 4:    3    D
    # 5:    3    E
    # 6:    4    C
    # 7:    4    D
    # 8:    4    E
    # 9:    5    C
    #10:    5    D
    #11:    5    E
    #12:    6    F
    #13:    7    G
    #14:    7    H
    #15:    8    G
    #16:    8    H
    #17:    9    I
    

    【讨论】:

      【解决方案4】:

      这是使用tidyverse 的另一个选项。通过使用separate_rows拆分'subj'列,将数据集转换为'long'格式,然后按'subj'分组,得到'rank'的mean

      library(tidyverse)
      separate_rows(df, subj) %>% 
               group_by(subj) %>%
               summarise(rank = mean(rank))
      # A tibble: 9 × 2
      #    subj  rank
      #   <chr> <dbl>
      #1     A   1.0
      #2     B   2.0
      #3     C   4.0
      #4     D   4.0
      #5     E   4.0
      #6     F   6.0
      #7     G   7.5
      #8     H   7.5
      #9     I   9.0
      

      【讨论】:

        猜你喜欢
        • 2012-03-08
        • 2019-09-17
        • 2023-03-14
        • 2018-07-21
        • 2015-07-09
        • 2021-10-12
        • 2017-12-10
        • 1970-01-01
        • 2019-01-27
        相关资源
        最近更新 更多