4

[1, 58, 10] などの文字列の列を、separate from tidyr を使用して列に分割したいと思います。私の問題は、列が短い場合があることです(決して長くはありません)。同じデータ フレームに、この問題が発生した列が多数あります。

パッケージの読み込み

require(tidyr)
require(dplyr)
require(stringr)

データ

ここでは、実際のデータからのサンプルを使用してデータ フレームを作成します。「ベクトル」の長さは、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]")
    )

どうなりたいか

すべての「ベクトル」が同じ長さの最初の列では、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)

これにより、

> 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

これは、要素を複数の列に分割できない 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"))

その結果、

> 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

ベクトルが短い場合、最後の要素は NA になるため、これは正しいです。

質問

回避策の代わりに別の (または他の単純な関数) を使用する方法はありますか? これを col1 と col2 に同時に適用する方法はありますか (たとえば、col で始まる列を選択することによって)?

ありがとう!

4

3 に答える 3

4

dplyrとを使用する別の方法を次に示しsplitstackshapeます。データ フレームが必要ない場合は、最後の data.frame(.) は必要ありません。data.table があります。

df %>%
    mutate_each(funs(gsub("\\[(.*)\\]", "\\1", .)), contains("col")) %>%
    cSplit(., c("col1", "col2"), sep = ",") %>%
    mutate_each(funs(as.numeric), -time) %>%
    data.frame(.)


#                 time col1_01 col1_02 col1_03 col1_04 col1_05 col1_06 col1_07 col1_08 col1_09 col1_10 col2_01 col2_02 col2_03 col2_04 col2_05
#1 2014-11-08 00:48:15       0     355       0       0       0    1227       0       0  382059     116       0     355       0       0       0
#2 2014-11-08 00:48:16       0      31       0       0       0       5       0       0     925       1       0     355       0       0       0
#3 2014-11-08 00:48:17       0       1       0       0       0     471       0       0  130339    3946       0       0       0       0       0
#4 2014-11-08 00:48:18       0       0       0       0       0     223       0       0   37666      12       0      19       0       0       0
#5 2014-11-08 00:48:19       0      19       0       0       0     667       0       0  336956      53       0     355       0       0       0

#  col2_06 col2_07 col2_08 col2_09 col2_10
#1    1227       0       0  382059     116
#2    1227       0       0  382059     116
#3     223       0       0   37666      12
#4     667       0       0  336956      NA
#5    1227       0       0  382059     116
于 2014-11-07T16:07:00.440 に答える
4

パッケージなしのソリューション:

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]")
)

df[-1] <- lapply(df[-1], function(x) gsub('\\[|\\]', '', as.character(x)))

df <- read.csv(text = apply(as.matrix(df), 1, 
                            function(x) paste0(x, collapse = ',')),
               check.names = FALSE, header = FALSE,
               colClasses = c('POSIXct', rep('numeric', 20)))
names(df) <- c('time', paste0('col1.', 1:10), paste0('col2.', 1:10))

# time col1.1 col1.2 col1.3 col1.4 col1.5 col1.6 col1.7 col1.8
# 1 2014-11-07 10:53:22      0    355      0      0      0   1227      0      0
# 2 2014-11-07 10:53:23      0     31      0      0      0      5      0      0
# 3 2014-11-07 10:53:24      0      1      0      0      0    471      0      0
# 4 2014-11-07 10:53:25      0      0      0      0      0    223      0      0
# 5 2014-11-07 10:53:26      0     19      0      0      0    667      0      0
# col1.9 col1.10 col2.1 col2.2 col2.3 col2.4 col2.5 col2.6 col2.7 col2.8 col2.9
# 1 382059     116      0    355      0      0      0   1227      0      0 382059
# 2    925       1      0    355      0      0      0   1227      0      0 382059
# 3 130339    3946      0      0      0      0      0    223      0      0  37666
# 4  37666      12      0     19      0      0      0    667      0      0 336956
# 5 336956      53      0    355      0      0      0   1227      0      0 382059
# col2.10
# 1     116
# 2     116
# 3      12
# 4      NA
# 5     116
于 2014-11-07T15:54:07.623 に答える