У меня есть фрейм данных, который выглядит так:
d = data.frame(obs = 1:4, comp = c("7_10","5","6_9","1_2_6_9"))
obs comp
1 1 7_10
2 2 5
3 3 6_9
4 4 1_2_6_9
Столбец comp содержит информацию об элементах, которые можно найти в каждом наблюдении (строке). Итак, первое наблюдение содержит элементы 7 и 10, второе — элемент 5 и так далее. Каждое наблюдение может содержать один, два или четыре из возможных 10 элементов.
Я могу разделить их на отдельные столбцы:
library(tidyverse)
d %>%
separate_wider_delim(comp,
delim = "_",
names = c("e1", "e2", "e3", "e4"),
too_few = "align_start")
obs e1 e2 e3 e4
1 1 7 10 NA NA
2 2 5 NA NA NA
3 3 6 9 NA NA
4 4 1 2 6 9
Однако вместо NA мне нужно, чтобы информация повторялась, например:
obs e1 e2 e3 e4
1 1 7 10 7 10 # elements 7 and 10 repeat
2 2 5 5 5 5 # element 5 repeats
3 3 6 9 6 9
4 4 1 2 6 9
Я знаю, как использовать pivot_longer
и fill
, чтобы заполнить NA предыдущим значением:
d %>%
separate_wider_delim(comp,
delim = "_",
names = c("e1", "e2", "e3", "e4"),
too_few = "align_start") %>%
pivot_longer(2:5,
names_to = "e",
values_to = "code") %>%
fill(code, .direction = "down") %>%
pivot_wider(names_from = e,
values_from = code)
obs e1 e2 e3 e4
1 1 7 10 10 10
2 2 5 5 5 5
3 3 6 9 9 9
4 4 1 2 6 9
Есть ли способ вместо этого заполнить NA набором предыдущих значений, а не только последним значением?
Как вы хотите, чтобы замена работала, если у вас есть три значения?
@IRTFM справедливый вопрос. У меня никогда не бывает трех ценностей. это 1,2 или 4 элемента. Я обновил основной текст
Если вы знаете, что последовательности комп состоят из 1, 2 или 4 элементов (если 1, то повторяется 4 раза, если 2, повторяется дважды, если 4 не повторяются), то вы можете использовать rep
и указать целевую длину для каждого obs
из 4. Добавлен знак row_number
для отображения данных в широком формате, как показано в примере выше.
library(tidyverse)
d %>%
separate_longer_delim(comp, delim = "_") %>%
reframe(value = rep_len(comp, length.out = 4), .by = obs) %>%
mutate(name = row_number(), .by = obs) %>%
pivot_wider(id_cols = obs, names_from = name, values_from = value, names_prefix = "e")
Выход
obs e1 e2 e3 e4
<int> <chr> <chr> <chr> <chr>
1 1 7 10 7 10
2 2 5 5 5 5
3 3 6 9 6 9
4 4 1 2 6 9
В основе мы могли бы начать с
> f = \(l) {
+ stopifnot(is.list(l))
+ nc = max(lengths(l))
+ do.call(rbind, lapply(l, rep, length.out=nc))
+ }
> d[-1L] = f(strsplit(d$comp, "_", fixed = TRUE))
> d
obs comp.1 comp.2 comp.3 comp.4
1 1 7 10 7 10
2 2 5 5 5 5
3 3 6 9 6 9
4 4 1 2 6 9
Входные данные
d = data.frame(obs = 1:4, comp = c("7_10","5","6_9","1_2_6_9"))
С базой R вы можете попробовать read.table
+ `[<-`
, как показано ниже.
cbind(
d,
t(
apply(
read.table(text = d$comp, sep = "_", fill = TRUE),
1,
\(x) `[<-`(x, na.omit(x))
)
)
)
такой, что вы получите
obs comp V1 V2 V3 V4
1 1 7_10 7 10 7 10
2 2 5 5 5 5 5
3 3 6_9 6 9 6 9
4 4 1_2_6_9 1 2 6 9
Вы можете воспользоваться правилом переработки data.frame
:
f <- function(data) {
newdata <- data.frame(t(data.frame(strsplit(data$comp, split = "_"))))
data[names(newdata)] <- newdata
data
}
f(d)
obs comp X1 X2 X3 X4
1 1 7_10 7 10 7 10
2 2 5 5 5 5 5
3 3 6_9 6 9 6 9
4 4 1_2_6_9 1 2 6 9
help(data.frame)
Объекты, передаваемые в data.frame, должны иметь одинаковое количество строк, но атомные векторы (см. is.vector), факторы и векторы символов защищено Я буду переработано целое число раз при необходимости (в том числе как элементы аргументов списка).
Текущее название основано на том, как я пытаюсь этого добиться, однако может быть совсем другой способ получить то, что у меня есть, к тому, что я хочу. Предложения по более подходящему названию приветствуются.