К сожалению, ОП не показал ожидаемого результата.Поэтому я покажу три разных подхода.
Первый "сгладит" запись , чтобы правильно разместить даты посещаемости и записи веса в порядке в соответствии с запросом OP.
второй перемещает значения в правильном интервале в соответствии с обычной недельной последовательностью с 7-дневными интервалами между посещениями.
третий - это вариант, который обрабатывает ситуациигде есть отклонения от обычной схемы, т. е. если разница в посещаемости составляет 6 или 8 дней.
1.Сгладьте запись без пропусков
library(data.table)
# read data
df1 <- fread(
"id attendance_1 attendance_2 attendance_3 attendance_4 attendance_5 Weight_1 Weight_2 Weight_3 Weight_4 Weight_5
p01 2018-05-01 2018-05-08 2018-05-15 NA NA 179 176 178 NA NA
p01 2018-05-28 NA NA NA NA 173 NA NA NA NA")
cols <- c("attendance", "Weight")
# reshape from wide to long format with 2 measure vars simultaneously
long <- melt(setDT(df1), measure.vars = patterns(cols), value.name = cols, na.rm = TRUE)
# reshape to long format in order of attendance witout gaps
dcast(long[order(attendance)], id ~ rowid(id), value.var = cols)
id attendance_1 attendance_2 attendance_3 attendance_4 Weight_1 Weight_2 Weight_3 Weight_4
1: p01 2018-05-01 2018-05-08 2018-05-15 2018-05-28 179 176 178 173
Обратите внимание, что функции melt()
и dcast()
из пакета data.table
позволяют одновременно преобразовывать несколько столбцов меры / значения.
Это эквивалентно решению WaltS , но намного короче.
2.Сгладьте запись в соответствии с недельным шаблоном
library(data.table)
# read data
df1 <- fread(
"id attendance_1 attendance_2 attendance_3 attendance_4 attendance_5 Weight_1 Weight_2 Weight_3 Weight_4 Weight_5
p01 2018-05-01 2018-05-08 2018-05-15 NA NA 179 176 178 NA NA
p01 2018-05-29 NA NA NA NA 173 NA NA NA NA")
Обратите внимание, что 2018-05-28
был заменен на 2018-05-29
, чтобы соответствовать недельному шаблону.
cols <- c("attendance", "Weight")
# reshape from wide to long format with 2 measure vars simultaneously
long <- melt(setDT(df1), measure.vars = patterns(cols), value.name = cols, na.rm = TRUE)
# coerce attendance from class character to class Date
long[, attendance := as.Date(attendance)]
# create date sequences for each id
date_seq <- long[, .(attendance = seq(min(attendance, na.rm = TRUE),
by = "week", length.out = 5L)), by = id]
# right join with date_seq to fill in gaps
long2 <- long[date_seq, on = .(id, attendance)]
Если все идентификаторы имеют одинаковые идентификаторыНачальная дата. Существует упрощенный способ изменения формы в широкоформатный:
dcast(long2[order(attendance)], id ~ attendance)
id 2018-05-01 2018-05-08 2018-05-15 2018-05-22 2018-05-29
1: p01 179 176 178 NA 173
Если идентификаторы имеют отдельные даты начала, мы должны иметь «нейтральные» заголовки столбцов:
dcast(long2[order(attendance)], id ~ rowid(id), value.var = cols)
id attendance_1 attendance_2 attendance_3 attendance_4 attendance_5 Weight_1 Weight_2 Weight_3 Weight_4 Weight_5
1: p01 2018-05-01 2018-05-08 2018-05-15 2018-05-22 2018-05-29 179 176 178 NA 173
3.Сгладить с пробелами и приблизительными датами
library(data.table)
# read data
df1 <- fread(
"id attendance_1 attendance_2 attendance_3 attendance_4 attendance_5 Weight_1 Weight_2 Weight_3 Weight_4 Weight_5
p01 2018-05-01 2018-05-08 2018-05-15 NA NA 179 176 178 NA NA
p01 2018-05-28 NA NA NA NA 173 NA NA NA NA")
Обратите внимание, что 2018-05-28
используется снова, что составляет 13 дней от предыдущего посещения
cols <- c("attendance", "Weight")
# reshape from wide to long format with 2 measure vars simultaneously
long <- melt(setDT(df1), measure.vars = patterns(cols), value.name = cols, na.rm = TRUE)
# coerce attendance from class character to class Date
long[, attendance := as.Date(attendance)]
# create date sequences for each id
date_seq <- long[, .(date = seq(min(attendance, na.rm = TRUE),
by = "week", length.out = 5L)), by = id]
# creat helper column for rolling join
long2 <- long[, date := attendance][
# rolling join to nearest date
date_seq, on = .(id, date), roll = "nearest"]
# set data of dates which are more than 1 day off of the regular weekly pattern to NA
long2[abs(attendance - date) > 1, (cols) := NA]
long2
id variable attendance Weight date
1: p01 1 2018-05-01 179 2018-05-01
2: p01 2 2018-05-08 176 2018-05-08
3: p01 3 2018-05-15 178 2018-05-15
4: p01 1 <NA> NA 2018-05-22
5: p01 1 2018-05-28 173 2018-05-29
# reshape to wide format
dcast(long2[order(date)], id ~ rowid(id), value.var = cols)
id attendance_1 attendance_2 attendance_3 attendance_4 attendance_5 Weight_1 Weight_2 Weight_3 Weight_4 Weight_5
1: p01 2018-05-01 2018-05-08 2018-05-15 <NA> 2018-05-28 179 176 178 NA 173