首页 文章

R - 生成动态列数和子串列值

提问于
浏览
2

在R中寻找数据操作的帮助 . 我有以下格式的数据;

ID  L1  L2  L3
1   BBCBCACCBCB CBCBBBB BEBBBAAB
2   BBCBCCCCBCB CBCCCBC BBAACCCB
3   BBCBCACCBCB CBCBBBB BEBBBAAB
4   BBCBCACCBCB CBCBBBB BEBBBAAB
5   BBCBACBCCCB BBCCCBC BBCBAAAAB
6   BBCBBCCBBCB BBCBCEB BBBBCAACB
7   BBCBBCCBBCB BBCBCEB BBBBCAACB
8           
9   BBCBCACCBCB CBCBBBB BEBBBAAB
10  BBCBBCCBBCB BBCBCEB BBBBCAACB
11  BBCBBCCBBCB BBCBCEB BBBBCAACB

每列中的值将是不同长度的字符串 . 我想要一个R函数,对于上面的每一列,都会

1)基于列中任何字符串的最大长度生成动态数量的列,例如, L1最大长度= 11,因此11个新列各自标记为L1_1:L1_11

2)然后将字符串分成三元组,例如

ID  L1  L2  L3  L1_1    L1_2    L1_3    L1_4    L1_5    L1_6    L1_7    L1_8    L1_9
1   BBCBCACCBCB CBCBBBB BEBBBAAB    BBC BCB CBC BCA CAC ACC CCB CBC BCB

3)对三元组中的三元组进行计算,即('a'* 1的数量)('b'* 3的数量)('c'* 7的数量) .

4)在新列中返回此计算的值 .

我发现建议的代码完全符合我在运行列L1,L2时所需的功能,但不适用于L3 . 我收到的错误是'as.data.frame.matrix中的错误(passed.args [[i]],stringsAsFactors = st:缺少值,其中需要TRUE / FALSE'

有任何想法吗?非常感谢 .

编辑

dput(DF):

structure(list(ID = 1:11, L1 = structure(c(4L, 5L, 4L, 4L, 2L, 3L, 3L, 1L, 4L, 3L, 3L), .Label = c("", "BBCBACBCCCB","BBCBBCCBBCB","BBCBCACCBCB", "BBCBCCCCBCB"), class = "factor"), L2 = structure(c(4L, 5L, 4L, 4L, 3L, 2L, 2L, 1L, 4L, 2L, 2L), .Label = c("","BBCBCEB","BBCCCBC", "CBCBBBB", "CBCCCBC"), class = "factor"), L3 = structure(c(5L,2L, 5L, 5L, 4L, 3L, 3L, 1L, 5L, 3L, 3L), .Label = c("", "BBAACCCB", "BBBBCAACB", "BBCBAAAAB", "BEBBBAAB"), class = "factor")), .Names = c("ID", "L1", "L2", "L3"), class = "data.frame", row.names = c(NA,-11L))

结构(列表(ID = 1:11,L1 =结构(c(4L,5L,4L,4L,2L,3L,3L,1L,4L,3L,3L),. Label = c(“”,“BBCBACBCCCB” ,“BBCBBCCBBCB”,“BBCBCACCBCB”,“BBCBCCCCBCB”),类=“因子”),L2 =结构(c(4L,5L,4L,4L,3L,2L,2L,1L,4L,2L,2L), .Label = c(“”,“BBCBCEB”,“BBCCCBC”,“CBCBBBB”,“CBCCCBC”),class =“factor”),L3 =结构(c(5L,2L,5L,5L,4L,3L, 3L,1L,5L,3L,3L), . Label = c(“”,“BBAACCCB”,“BBBBCAACB”,“BBCBAAAAB”,“BEBBBAAB”),class =“factor”)), . Name = c(“ ID“,”L1“,”L2“,”L3“),class =”data.frame“,row.names = c(NA,-11L))

2 回答

  • 2
    #DATA
    df = structure(list(ID = 1:4, L1 = c("abbbcc", "aabacd", "abbda", 
    "bbad")), .Names = c("ID", "L1"), class = "data.frame", row.names = c(NA, 
    -4L))
    
    #Go through the strings and split into subgroups of 3 characters.
    #Put the substrings in a list
    temp = lapply(df$L1, function(x) sapply(3:nchar(x), function(i) substr(x, i-2, i)))
    
    #Obtain the length of the subgroup with the most triplets
    temp_l = max(lengths(temp))
    
    #Subset the subgroups from 1 to temp_l so that remianing values are NA
    cbind(df, setNames(data.frame(do.call(rbind, lapply(temp, function(a)
        a[1:temp_l]))), nm = paste0("L1_",1:temp_l)))
    #  ID     L1 L1_1 L1_2 L1_3 L1_4
    #1  1 abbbcc  abb  bbb  bbc  bcc
    #2  2 aabacd  aab  aba  bac  acd
    #3  3  abbda  abb  bbd  bda <NA>
    #4  4   bbad  bba  bad <NA> <NA>
    

    如果要基于三元组进行计算,请在执行 cbind 步骤之前运行以下命令

    temp_L1 = lapply(df$L1, function(x) sapply(3:nchar(x), function(i) substr(x, i-2, i)))
    temp_L1_length = max(lengths(temp_L1))
    temp_L1 = lapply(temp_L1, function(x)
                 sapply(x, function(y){
                         num_a = unlist(gregexpr(pattern = "a", text = y))
                         num_a = sum(num_a > 0)  #length of positive match
                         num_b = unlist(gregexpr(pattern = "b", text = y))
                         num_b = sum(num_b > 0)
                         num_c = unlist(gregexpr(pattern = "c", text = y))
                         num_c = sum(num_c > 0)
                         num_a * 1 + num_b * 3 + num_c * 7
                     })
             )
    temp_L1 = setNames(data.frame(do.call(rbind, lapply(temp_L1, function(a)
                  a[1:temp_L1_length]))), nm = paste0("L1_",1:temp_L1_length))
    
    #REPEAT FOR L2, L3, ...
    
    cbind(df, temp_L1)   #Run cbind(df, temp_L1, temp_L2, ...)
    #  ID     L1 L1_1 L1_2 L1_3 L1_4
    #1  1 abbbcc    7    9   13   17
    #2  2 aabacd    5    5   11    8
    #3  3  abbda    7    6    4   NA
    #4  4   bbad    7    4   NA   NA
    

    UPDATE

    您可以创建一个函数并使用它,如下所示

    #FUNCTION
    foo = function(data, column){
        temp_L1 = lapply(as.character(data[[column]]), function(x) sapply(3:nchar(x), function(i) substr(x, i-2, i)))
        temp_L1_length = max(lengths(temp_L1))
        temp_L1 = lapply(temp_L1, function(x)
            sapply(x, function(y){
                num_a = unlist(gregexpr(pattern = "a", text = y, ignore.case = TRUE))
                num_a = sum(num_a > 0)  #length of positive match
                num_b = unlist(gregexpr(pattern = "b", text = y, ignore.case = TRUE))
                num_b = sum(num_b > 0)
                num_c = unlist(gregexpr(pattern = "c", text = y, ignore.case = TRUE))
                num_c = sum(num_c > 0)
                num_a * 1 + num_b * 3 + num_c * 7
            })
        )
        temp_L1 = setNames(data.frame(do.call(rbind, lapply(temp_L1, function(a)
            a[1:temp_L1_length]))), nm = paste0(column,"_",1:temp_L1_length))
        return(temp_L1)
    }
    
    #USING ON NEW DATA
    cbind(df, do.call(cbind, lapply(colnames(df)[-1], function(x) foo(data = df, column = x))))
    
  • 0

    如果你想使用 tidyverse 动词

    library(tidyverse)
    df1 <- df %>%
          mutate(L2=L1) %>%              # copies L1
          nest(L2) %>%                   # nest L1
          mutate(data=map(data,~sapply(1:(nchar(.x)-2), function(y) substr(.x, y, y+2)))) %>%       # makes triplets
          unnest(data) %>%        # unnest triplets
          group_by(ID) %>%        # perform next operations group wise
          mutate(rn=letters[row_number()]) %>%        # make future column names
          spread(rn,data)         # spread long format into wide format (columns)
    
         ID     L1     a     b     c     d
    1     1 abbbcc   abb   bbb   bbc   bcc
    2     2 aabacd   aab   aba   bac   acd
    3     3  abbda   abb   bbd   bda  <NA>
    4     4   bbad   bba   bad  <NA>  <NA>
    

相关问题