代码之家  ›  专栏  ›  技术社区  ›  DTYK

获取字符串中的最小数字

  •  1
  • DTYK  · 技术社区  · 7 年前

    我有一个数据框架,由捕捉不同事件的列组成。受访者填写他们经历这些事件的年龄。对于他们经历过多次的任何给定事件,他们用一个分号来分隔经历过的年龄(例如,如果他们在5、6、7岁时经历过,他们将在该特定列中输入5、6、7)。对于他们没有经历过的事件,受访者会将其留空。

    因为有20多列,所以我将所有列连接在一起,形成一个单列,形成一个字符列。我想提取那个字符串中最小的数字。我无法将列强制为数字数据类型,因为某些事件将被受访者多次经历,并且被R解释为字符串(例如“5;6;7”)。

    我的数据如下所示:

    df <- data.frame(ID = c("001", "002", "003", "004"),
                 concatenated = c("NA_NA_NA_NA_5; 6_NA_4_NA_NA_NA",
                                  "3_3_NA_NA_NA_3; 4; 5; 6_NA_NA_NA_NA",
                                  "NA_5_4_2_NA_NA_NA_NA_6; 7; 8; 9; 10_NA",
                                  "NA_NA_11_12_11_NA_4; 5; 6_NA_NA_9"))
    
    df$concatenated <- as.character(df$concatenated)
    

    我想要得到的最终结果是:

    ID                           concatenated smallest_number
    1 001         NA_NA_NA_NA_5; 6_NA_4_NA_NA_NA               4
    2 002    3_3_NA_NA_NA_3; 4; 5; 6_NA_NA_NA_NA               3
    3 003 NA_5_4_2_NA_NA_NA_NA_6; 7; 8; 9; 10_NA               2
    4 004      NA_NA_11_12_11_NA_4; 5; 6_NA_NA_9               4
    

    谢谢!非常感谢!

    4 回复  |  直到 7 年前
        1
  •  1
  •   Hugh    7 年前

    假设您的数据结构如下:

    DF <- data.frame(ID = 1:4,
                     age = c("5", "5;6;7", "20;15;12", "2;4"),
                     stringsAsFactors = FALSE)
    

    你可以使用 strsplit 将每个年龄段划分为一个数字,然后按照通常的方式取最小值:

    DF$min_age <- vapply(strsplit(DF$age, split = "[^0-9]"),
                         function(x) min(as.numeric(x), na.rm = TRUE),
                         double(1))
    

    如果数字有时不出现,只需排除这些行

    i <- grep("[0-9]", DF$age)  # rows with numbers somewhere
    DF$min_age <- NA_character_
    DF$min_age[i] <- vapply(strsplit(DF$age[i], split = "[^0-9]"),
                            function(x) min(as.numeric(x), na.rm = TRUE),
                            double(1))
    
        2
  •  1
  •   moodymudskipper    7 年前

    我们可以用 gsub 为每个项使用一个下划线分隔的字符串,然后使用 scan 和 min 在他们身上。

    df$smallest_number <- sapply(df$concatenated, function(x){
      min(scan(text=gsub("; ","_",x), what = numeric(), sep="_"),na.rm=TRUE)})
    df
    #    ID                           concatenated smallest_number
    # 1 001         NA_NA_NA_NA_5; 6_NA_4_NA_NA_NA               4
    # 2 002    3_3_NA_NA_NA_3; 4; 5; 6_NA_NA_NA_NA               3
    # 3 003 NA_5_4_2_NA_NA_NA_NA_6; 7; 8; 9; 10_NA               2
    # 4 004      NA_NA_11_12_11_NA_4; 5; 6_NA_NA_9               4
    
        3
  •  1
  •   s_baldur    7 年前
    library(stringr)
    df$smallest_number <- sapply(
      str_extract_all(df$concatenated, "[0-9]+"),
      function(x) min(as.integer(x))
    )
    df
       ID                           concatenated smallest_number
    1 001         NA_NA_NA_NA_5; 6_NA_4_NA_NA_NA               4
    2 002    3_3_NA_NA_NA_3; 4; 5; 6_NA_NA_NA_NA               3
    3 003 NA_5_4_2_NA_NA_NA_NA_6; 7; 8; 9; 10_NA               2
    4 004      NA_NA_11_12_11_NA_4; 5; 6_NA_NA_9               4
    
        4
  •  1
  •   tmfmnk    7 年前

    用 tidyverse 和 splitstackshape 你可以做到:

    df %>%
     mutate(temp = gsub(";", "_", concatenated),
            temp = gsub(" ", "", temp)) %>%
     cSplit("temp", sep = "_") %>%
     gather(var, val, -c(concatenated, ID)) %>%
     group_by(ID) %>%
     mutate(res = min(val, na.rm = TRUE)) %>%
     spread(var, val) %>%
     select(ID, concatenated, res)
    
      ID    concatenated                             res
      <fct> <chr>                                  <dbl>
    1 001   NA_NA_NA_NA_5; 6_NA_4_NA_NA_NA            4.
    2 002   3_3_NA_NA_NA_3; 4; 5; 6_NA_NA_NA_NA       3.
    3 003   NA_5_4_2_NA_NA_NA_NA_6; 7; 8; 9; 10_NA    2.
    4 004   NA_NA_11_12_11_NA_4; 5; 6_NA_NA_9         4.
    

    首先,它取代了 ; 具有 _ 并根据 γ . 其次,它将数据从宽格式转换为长格式,并按“id”列分组。最后,它评估最小值并将数据返回到宽格式。

    或者只是 时髦诗 :

    df %>% 
     mutate(temp = gsub(";", "_", concatenated),
            temp = gsub(" ", "", temp),
            temp = strsplit(temp, "_")) %>%
     unnest(temp) %>%
     group_by(ID) %>%
     mutate_if(is.character, as.numeric) %>%
     mutate(res = min(temp, na.rm = TRUE),
            rowid = row_number()) %>%
     spread(rowid, temp) %>%
     select(ID, concatenated , res)
    
      ID    concatenated                             res
      <fct> <fct>                                  <dbl>
    1 001   NA_NA_NA_NA_5; 6_NA_4_NA_NA_NA            4.
    2 002   3_3_NA_NA_NA_3; 4; 5; 6_NA_NA_NA_NA       3.
    3 003   NA_5_4_2_NA_NA_NA_NA_6; 7; 8; 9; 10_NA    2.
    4 004   NA_NA_11_12_11_NA_4; 5; 6_NA_NA_9         4.