#r
#r
Вопрос:
У меня есть фрейм данных с одной строкой на идентификатор. Я пытаюсь создать несколько строк для каждого идентификатора с той же информацией, кроме start
и stop
.
Если возраст> = 36, этот идентификатор должен иметь в общей сложности 9 строк. start
должно быть 27, 28, …, 35. stop
должно быть 28, 29, …, 36.
Если 27> возраст < 36, у этого идентификатора должно быть ( age
— 27) всего строк. Например, если age
равно 30, то этот идентификатор должен иметь в общей сложности 3 строки.
Если возраст = 27, у этого идентификатора должно быть всего 1 строка. Самый младший возраст в моем наборе данных — 27 лет, поэтому каждый идентификатор должен содержать не менее 1 строки.
Некоторые данные:
df$id <- c(1, 2, 3)
df$age <- c(27, 40, 30)
time.columns <- c("start", "stop")
df[, time.columns] <- NA
Я хочу, чтобы это выглядело так:
id age start stop
1 27 27 28
2 40 27 28
2 40 28 29
2 40 29 30
2 .. .. ..
2 40 35 36
3 30 27 28
3 30 28 29
3 30 29 30
Комментарии:
1. @akrun Это выглядит так
stop <- start 1
.2. Да, это верно.
stop
должно бытьstart
13. Исходя из ожидаемого результата, я думаю, что это 13 строк?
Ответ №1:
Вы могли бы написать базовую if
… else
функцию для значений «age» и использовать ее для вычисления столбцов «start». Что-то вроде этого должно помочь вам начать:
expander <- function(value) {
if (value >= 36) {
start = 27:35
} else if (value == 27) {
start = 27
} else if (value > 27 amp; value < 36) {
start = 27 sequence(value - 27) - 1
}
}
Вот как вы можете это использовать:
# Sample data
df <- data.frame(id = c(1, 2, 3, 4),
age = c(27, 40, 30, 29))
library(dplyr)
library(tidyr)
df %>%
group_by(id) %>%
mutate(start = list(expander(age))) %>%
unnest(cols = c(start)) %>%
mutate(stop = start 1)
# # A tibble: 15 x 4
# # Groups: id [4]
# id age start stop
# <dbl> <dbl> <dbl> <dbl>
# 1 1 27 27 28
# 2 2 40 27 28
# 3 2 40 28 29
# 4 2 40 29 30
# 5 2 40 30 31
# 6 2 40 31 32
# 7 2 40 32 33
# 8 2 40 33 34
# 9 2 40 34 35
# 10 2 40 35 36
# 11 3 30 27 28
# 12 3 30 28 29
# 13 3 30 29 30
# 14 4 29 27 28
# 15 4 29 28 29
Если вы хотите полностью придерживаться базы R, вы можете сделать:
x <- with(df, sapply(age, expander))
within(df[rep(1:nrow(df), lengths(x)), ], {
start = unlist(x)
stop = start 1
})
## id age stop start
## 1 1 27 28 27
## 2 2 40 28 27
## 2.1 2 40 29 28
## 2.2 2 40 30 29
## 2.3 2 40 31 30
## 2.4 2 40 32 31
## 2.5 2 40 33 32
## 2.6 2 40 34 33
## 2.7 2 40 35 34
## 2.8 2 40 36 35
## 3 3 30 28 27
## 3.1 3 30 29 28
## 3.2 3 30 30 29
## 4 4 29 28 27
## 4.1 4 29 29 28
Комментарии:
1. Спасибо — почему нам нужно использовать
list()
функцию расширения?2. @user12310746, он создает
list
столбец, который можноunnest
отредактировать позже.mutate
ожидается, что результирующее количество строк будет таким же, как и входные данные, но это не относится к этой функции.
Ответ №2:
Вот data.table
вариант
setDT(df)[
,
.(start = 27:pmin(pmax(age - 1, 27), 35)),
.(id, age)
][
,
stop := start 1
][]
что дает
id age start stop
1: 1 27 27 28
2: 2 40 27 28
3: 2 40 28 29
4: 2 40 29 30
5: 2 40 30 31
6: 2 40 31 32
7: 2 40 32 33
8: 2 40 33 34
9: 2 40 34 35
10: 2 40 35 36
11: 3 30 27 28
12: 3 30 28 29
13: 3 30 29 30
Ответ №3:
Поскольку «начало» остается фиксированным, мы создаем «остановку» на основе минимального значения 36 и «возраста», создаем последовательность из «start» и «stop», затем unnest
list
столбец
library(dplyr)
library(purrr)
df %>%
mutate(start = 27, stop = map2(start 1, pmin(36, age),
~ if(.y > .x) seq(.x, .y) else .x)) %>%
unnest(c(stop)) %>%
group_by(id) %>%
mutate(start = first(start) row_number() - 1)
-вывод
# A tibble: 13 x 4
# Groups: id [3]
# id age start stop
# <int> <dbl> <dbl> <dbl>
# 1 1 27 27 28
# 2 2 40 27 28
# 3 2 40 28 29
# 4 2 40 29 30
# 5 2 40 30 31
# 6 2 40 31 32
# 7 2 40 32 33
# 8 2 40 33 34
# 9 2 40 34 35
#10 2 40 35 36
#11 3 30 27 28
#12 3 30 28 29
#13 3 30 29 30
данные
df <- structure(list(id = 1:3, age = c(27, 40, 30)), class = "data.frame",
row.names = c(NA,
-3L))