[R] Разделить вектор символов на строки фрейма данных по заданному количеству столбцов - PullRequest
0 голосов
/ 06 июля 2018

Я не могу найти это специально (я посмотрел здесь: Как разделить вектор символов на фрейм данных? ) и в некоторых других местах.

Я пытаюсь разделить вектор символов в R на фрейм данных с заданным количеством столбцов, заполняя NA для любых дополнительных или отсутствующих. Как показано ниже (воспроизводимо):

###Reproduce column vector
cv <- c("a1", "b1", "c1", "d1", "e1", "f1", "aa2", "bb2", "cc2", "dd2", "ee2", "ff2", "x1", "x2", "x3", "x4", "x5", "x6", "rr2", "tt3", "bb4")

###Desired data frame separating 6 columns
df.desired <- data.frame(col1=c("a1","aa2","x1","rr2"),col2=c("b1","bb2","x2","tt3"),col3=c("c1","cc2","x3","bb4"),col4=c("d1","dd2","x4",NA),col5=c("e1","ee2","x5",NA),col6=c("f1","ff2","x6",NA),stringsAsFactors = F)

Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 06 июля 2018

1) base Создайте матрицу значений NA необходимых размеров и затем заполните ее cv до его длины. Перенесите это и преобразуйте во фрейм данных.

mat <- t(replace(matrix(NA, 6, ceiling(length(cv) / 6)), seq_along(cv), cv))
as.data.frame(mat, stringsAsFactors = FALSE)

2) другое базовое решение Используя cv2 копию cv, увеличьте ее длину до требуемой, а затем преобразуйте в матрицу. Мы использовали cv2, чтобы сохранить исходный cv, но если вы не возражаете добавить NA к концу cv, вы можете просто использовать его вместо создания cv2, сокращая код на одну строку (два линии, если мы можем использовать mat вместо того, чтобы нуждаться во фрейме данных). Это решение избавляет от необходимости использовать транспонирование, используя аргумент byrow matrix.

cv2 <- cv
length(cv2) <- 6 * ceiling(length(cv) / 6)
mat <- matrix(cv2,, 6, byrow = TRUE)
as.data.frame(mat, stringsAsFactors = FALSE)

3) базовое решение с использованием ts Этот метод получает индексы строк и столбцов, извлекая их из времен объекта ts, а не вычисляя измерения с помощью числовых вычислений. Для этого создайте tt объекта ts из cv. tt сам по себе является ts объектом, для которого as.integer(tt) является индексными номерами строк, а cycle(tt) является индексными номерами столбцов. Наконец, используйте tapply с этим:

tt <- time(ts(cv, frequency = 6))
mat <- tapply(cv, list(as.integer(tt), cycle(tt)), c)
as.data.frame(mat, stringsAsFactors = FALSE)

4) rollapply Как и (3), этот явно не вычисляет размеры mat. Он использует rollapply в пакете zoo с простой функцией, Fill r, чтобы избежать этого. Функция Fill возвращает аргумент x, дополненный символами NA справа, до длины 6.

library(zoo)

Fill <- function(x) { length(x) <- 6; x }
mat <- rollapplyr(cv, 6, by = 6, Fill, align = "left", partial = TRUE)
as.data.frame(mat, stringsAsFactors = FALSE)

Во всех приведенных выше альтернативах пропустите последнюю строку, если в качестве матрицы достаточно 10 * *.

0 голосов
/ 06 июля 2018

1) основание R - split vector с использованием группирующей переменной, созданной с помощью gl, а затем добавьте NA в конце с length<-

lst <- split(cv, as.integer(gl(length(cv), 6, length(cv))))
as.data.frame(do.call(rbind, lapply(lst, `length<-`, max(lengths(lst)))))
#  V1  V2  V3   V4   V5   V6
#1  a1  b1  c1   d1   e1   f1
#2 aa2 bb2 cc2  dd2  ee2  ff2
#3  x1  x2  x3   x4   x5   x6
#4 rr2 tt3 bb4 <NA> <NA> <NA>
...