R-拆分具有不同行长的列

时间:2019-02-25 21:28:50

标签: r dplyr

我有下面这样的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分开仅允许除以“;”但是“;”的数量不同成行。我该怎么办?

4 个答案:

答案 0 :(得分:2)

您可以使用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
)

答案 1 :(得分:1)

您可以使用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-02-25创建

答案 2 :(得分:1)

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

答案 3 :(得分:1)

另一种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

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