使用与tidyr分开的不同长度向量

byt*_*ght 4 r stringr dplyr tidyr

我想将一列字符串(例如[1,58,10])与tidyr分开使用.我的问题是有时候列更短(永远不会更长).我在同一数据框中有很多列有此问题.

加载包

require(tidyr)
require(dplyr)
require(stringr)
Run Code Online (Sandbox Code Playgroud)

数据

在这里,我使用来自真实数据的样本制作数据框."载体"在col1中长度为10,在col2中为9或10.有一个时间列只是为了显示还有其他列.

df <- data.frame(
        time = as.POSIXct(1:5, origin=Sys.time()),
        col1 = c("[0,355,0,0,0,1227,0,0,382059,116]", "[0,31,0,0,0,5,0,0,925,1]", "[0,1,0,0,0,471,0,0,130339,3946]", "[0,0,0,0,0,223,0,0,37666,12]", "[0,19,0,0,0,667,0,0,336956,53]"),
        col2 = c("[0,355,0,0,0,1227,0,0,382059,116]", "[0,355,0,0,0,1227,0,0,382059,116]", "[0,0,0,0,0,223,0,0,37666,12]", "[0,19,0,0,0,667,0,0,336956]","[0,355,0,0,0,1227,0,0,382059,116]")
    )
Run Code Online (Sandbox Code Playgroud)

我多么想要它

对于所有"向量"长度相等的第一列,我可以使用separate()来获得我想要的.

a1 <- df %>% 
    mutate(col1 = str_sub(col1,2,-2)) %>%
    separate(col1, paste("col1",1:10,sep="."),",")

# Making sure the numbers are numeric
a1 <- as.data.frame(sapply(a1, as.numeric)) %>%
    mutate(time = as.POSIXct(time, origin="1970-01-01")) %>% select(-col2)
Run Code Online (Sandbox Code Playgroud)

这导致了

> a1
                 time col1.1 col1.2 col1.3 col1.4 col1.5 col1.6 col1.7 col1.8
1 2014-11-07 12:21:45      0    355      0      0      0   1227      0      0
2 2014-11-07 12:21:46      0     31      0      0      0      5      0      0
3 2014-11-07 12:21:47      0      1      0      0      0    471      0      0
4 2014-11-07 12:21:48      0      0      0      0      0    223      0      0
5 2014-11-07 12:21:49      0     19      0      0      0    667      0      0
  col1.9 col1.10
1 382059     116
2    925       1
3 130339    3946
4  37666      12
5 336956      53
Run Code Online (Sandbox Code Playgroud)

这不适用于col2,其中元素不能拆分为多个列

解决方法

# Does not work
#b1 <- df %>% 
#   mutate(col2 = str_sub(col1,2,-2)) %>%
#   separate(col2, paste("col2",1:10,sep="."),",")

b2 <- sapply(as.data.frame(str_split_fixed(str_sub(df$col2,2,-2),',',n=10), stringsAsFactors=F), as.numeric) 
colnames(b2) <- paste("col2",1:10,sep=".")
b2 <- as.data.frame(cbind(time=df$time, b2)) %>%
    mutate(time = as.POSIXct(time, origin="1970-01-01"))
Run Code Online (Sandbox Code Playgroud)

结果如何

> b2
                 time col2.1 col2.2 col2.3 col2.4 col2.5 col2.6 col2.7 col2.8
1 2014-11-07 12:21:45      0    355      0      0      0   1227      0      0
2 2014-11-07 12:21:46      0    355      0      0      0   1227      0      0
3 2014-11-07 12:21:47      0      0      0      0      0    223      0      0
4 2014-11-07 12:21:48      0     19      0      0      0    667      0      0
5 2014-11-07 12:21:49      0    355      0      0      0   1227      0      0
  col2.9 col2.10
1 382059     116
2 382059     116
3  37666      12
4 336956      NA
5 382059     116
Run Code Online (Sandbox Code Playgroud)

如果向量较短,则最后的元素应为NA,因此这是正确的.

问题

有没有办法使用单独的(或其他一些更简单的功能)而不是解决方法?有没有办法同时将它应用于col1和col2(通过选择以col开头的列为例)?

谢谢!

aos*_*ith 6

这只回答了你问题的第一部分separate.有一个extra在争论separate(至少在开发版本tidyr),让你做你想要什么,如果你设置extra"merge".

df %>% 
    mutate(col2 = str_sub(col2,2,-2)) %>%
    separate(col2, paste("col2",1:10,sep="."), ",", extra = "merge")

                 time                              col1
1 2014-11-07 08:00:59 [0,355,0,0,0,1227,0,0,382059,116]
2 2014-11-07 08:01:00          [0,31,0,0,0,5,0,0,925,1]
3 2014-11-07 08:01:01   [0,1,0,0,0,471,0,0,130339,3946]
4 2014-11-07 08:01:02      [0,0,0,0,0,223,0,0,37666,12]
5 2014-11-07 08:01:03    [0,19,0,0,0,667,0,0,336956,53]
  col2.1 col2.2 col2.3 col2.4 col2.5 col2.6 col2.7 col2.8
1      0    355      0      0      0   1227      0      0
2      0    355      0      0      0   1227      0      0
3      0      0      0      0      0    223      0      0
4      0     19      0      0      0    667      0      0
5      0    355      0      0      0   1227      0      0
  col2.9 col2.10
1 382059     116
2 382059     116
3  37666      12
4 336956    <NA>
5 382059     116
Run Code Online (Sandbox Code Playgroud)