【问题标题】:R - splitting column with different length of rowsR - 具有不同行长的拆分列
【发布时间】:2019-02-25 21:28:50
【问题描述】:

我有如下的data.frame

ID  age location
1   83  country=X;province=A;city=J
2   15  country=X;city=K
3   2   country=Y;province=B;city=I
4   12  country=X;city=L
5   2   country=Y;city=J
6   2   country=Y;province=A;city=M
7   18  country=X;province=B;city=J
8   85  country=X;province=A;city=I

描述它:第三列(位置),其中记录包含用“;”分隔的字符串并且有不同的长度。

因此,我需要这样获取data.frame:

ID  age country city
1   83  X       J
2   15  X       K
3   2   Y       I
4   12  X       L
5   2   Y       J
6   2   Y       M
7   18  X       J
8   85  X       I

要描述 - 我需要分隔列并仅选择有关国家和城市的记录(不包括省)。与 dplyr 分开只允许除以“;”但是“;”的数量不同在行中。我该怎么办?

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    你可以用tidyr::extract函数做到这一点:

    library(tidyverse)
    
    extract(
      data  = dat,
      col   = location,
      into  = c('country', 'city'),
      regex = "^country=([[:alpha:]]+).*city=([[:alpha:]]+)$"
      )
    
      ID age country city
    1  1  83       X    J
    2  2  15       X    K
    3  3   2       Y    I
    4  4  12       X    L
    5  5   2       Y    J
    6  6   2       Y    M
    7  7  18       X    J
    8  8  85       X    I
    

    数据

    dat <- read.table(
      text = "ID  age location
    1   83  country=X;province=A;city=J
    2   15  country=X;city=K
    3   2   country=Y;province=B;city=I
    4   12  country=X;city=L
    5   2   country=Y;city=J
    6   2   country=Y;province=A;city=M
    7   18  country=X;province=B;city=J
    8   85  country=X;province=A;city=I",
      header = T, stringsAsFactors = F
    )
    

    【讨论】:

    • 我认为这是最好的答案。
    【解决方案2】:

    您可以使用separate_rows 和随后的一些重塑来做到这一点。 separate_rows 把东西变成长格式,所以我们可以做一些过滤然后spread 得到想要的结果:

    library(tidyverse)
    tbl <- read_table2(
      "ID  age location
    1   83  country=X;province=A;city=J
    2   15  country=X;city=K
    3   2   country=Y;province=B;city=I
    4   12  country=X;city=L
    5   2   country=Y;city=J
    6   2   country=Y;province=A;city=M
    7   18  country=X;province=B;city=J
    8   85  country=X;province=A;city=I"
    )
    
    tbl %>%
      separate_rows(location, sep = ";") %>%
      separate(location, c("location_type", "value")) %>%
      filter(location_type %in% c("country", "city")) %>%
      spread(location_type, value)
    #> # A tibble: 8 x 4
    #>      ID   age city  country
    #>   <dbl> <dbl> <chr> <chr>  
    #> 1     1    83 J     X      
    #> 2     2    15 K     X      
    #> 3     3     2 I     Y      
    #> 4     4    12 L     X      
    #> 5     5     2 J     Y      
    #> 6     6     2 M     Y      
    #> 7     7    18 J     X      
    #> 8     8    85 I     X
    

    因为您只需要处理两种情况,您可能会发现使用正则表达式直接提取感兴趣的值会更快或更容易:

    tbl %>%
      mutate(
        country = str_extract(location, "(?<=country\\=)."),
        city = str_extract(location, "(?<=city\\=).")
      )
    #> # A tibble: 8 x 5
    #>      ID   age location                    country city 
    #>   <dbl> <dbl> <chr>                       <chr>   <chr>
    #> 1     1    83 country=X;province=A;city=J X       J    
    #> 2     2    15 country=X;city=K            X       K    
    #> 3     3     2 country=Y;province=B;city=I Y       I    
    #> 4     4    12 country=X;city=L            X       L    
    #> 5     5     2 country=Y;city=J            Y       J    
    #> 6     6     2 country=Y;province=A;city=M Y       M    
    #> 7     7    18 country=X;province=B;city=J X       J    
    #> 8     8    85 country=X;province=A;city=I X       I
    

    reprex package (v0.2.1) 于 2019 年 2 月 25 日创建

    【讨论】:

      【解决方案3】:
      df <- read.table(text='ID  age location
                       1   83  country=X;province=A;city=J
                       2   15  country=X;city=K
                       3   2   country=Y;province=B;city=I
                       4   12  country=X;city=L
                       5   2   country=Y;city=J
                       6   2   country=Y;province=A;city=M
                       7   18  country=X;province=B;city=J
                       8   85  country=X;province=A;city=I
                       ', header= T)
      
      
      
      
      my_fun <- function(x){
        y <- as.data.frame(strsplit(x,'='))
        names(y) <- as.character(unlist(y[1,]))
        y <- y[-1,]
      }
      
      f <- strsplit(as.character(df$location), ";")
      s <- data.table::rbindlist(lapply(f,my_fun), fill=T)
      
      df$location <- NULL
      df <- cbind(df, s)
      df
        ID age country province city
      1  1  83       X        A    J
      2  2  15       X     <NA>    K
      3  3   2       Y        B    I
      4  4  12       X     <NA>    L
      5  5   2       Y     <NA>    J
      6  6   2       Y        A    M
      7  7  18       X        B    J
      8  8  85       X        A    I
      

      【讨论】:

        【解决方案4】:

        tidyverse 的另一种可能性可能是:

        df %>%
         separate(location, c("country", "city"), sep = ";") %>%
         mutate_at(3:4, funs(sub(".*=", "", .)))
        
          ID age country city
        1  1  83       X    A
        2  2  15       X    K
        3  3   2       Y    B
        4  4  12       X    L
        5  5   2       Y    J
        6  6   2       Y    A
        7  7  18       X    B
        8  8  85       X    A
        

        在第一步中,它根据; 将“位置”分为“国家”和“城市”。然后,它从新创建的列中提取= 之后的元素。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-14
          • 2021-09-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-12-09
          相关资源
          最近更新 更多