R: Объединить дублирующиеся строки и порядок даты последовательности - PullRequest
0 голосов
/ 11 мая 2018

Первое сообщение после того, как копаться, пытаясь найти ответ. Мой вопрос касается сглаживания дубликатов и сохранения данных в порядке дат.

В этом проекте участники пришли на последующие оценки и записали свой вес в течение 20 недель. Поскольку участники прибыли в разные дни для оценки, у нас есть 20 столбцов с номером посещаемости, который содержит дату этого посещения, а затем 20 столбцов с их весом при данном посещении. Каким-то образом участники были продублированы, а их меры разрознены.

РЕДАКТИРОВАТЬ : я забыл упомянуть, что у каждого участника есть уникальный идентификатор, поэтому в приведенном ниже примере p01 является одним участником, но ошибка при вводе означает, что они появляются дважды.

Кроме того, под «выравниванием» я имел в виду, есть ли способ объединить эти повторяющиеся записи, чтобы у каждого участника было только одно наблюдение / строка. Что вызвало немного горя, так это выяснить, как упорядочить еженедельные данные, а затем сохранить их записанные значения веса

Более простой вымышленный пример, показанный ниже:

**What actually happened**
id  attendance_1  attendance_2   attendance_3  attendance 4  attendance 5    
p01  2018-05-01    2018-05-08     2018-05-15    NA            2018-05-28

     Weight_1   Weight_2  Weight_3  Weight_4  Weight_5
     179        176       178       NA        173

**What is recorded in dataset**
df
------
   id  attendance_1  attendance_2   attendance_3  attendance 4  attendance 5    
1 p01  2018-05-01    2018-05-08     2018-05-15    NA            NA
2 p01  2018-05-28    NA             NA            NA            NA

   Weight_1   Weight_2  Weight_3  Weight_4  Weight_5
1  179        176       178       NA        NA
2  173        NA        NA        NA        NA

Таким образом, участник "p01" посетил 4 из 5 оценок, но их запись была дублирована, и их "пятая" посещаемость отображается как "первая" в их дублирующей записи. Есть ли способ "сгладить" их записи, чтобы правильно расположить даты их посещаемости и записи веса в порядке?

В этом примере я думал о создании столбца «дата окончания» на основе 5 недель от даты их начала с использованием пакета lubridate, но я не знаю, как кодировать перемещение значений в их «правильном» пространстве или, если это возможно.

Ранее я использовал этот код в других анализах;

df_merged = aggregate(x = df, by = list(df$participants_ID), FUN = function(x) na.omit(x)[1])[,-1]

, чтобы сгладить дублирующихся участников на основе их ID, но в этом случае данные будут перезаписаны и не будут работать.

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

Ответы [ 2 ]

0 голосов
/ 14 мая 2018

К сожалению, ОП не показал ожидаемого результата.Поэтому я покажу три разных подхода.

Первый "сгладит" запись , чтобы правильно разместить даты посещаемости и записи веса в порядке в соответствии с запросом 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
0 голосов
/ 11 мая 2018

Чтобы справиться с проблемами очистки данных этого типа, вы можете взглянуть на tidyverse пакеты, особенно tidyr и dplyr.

Я воссоздал несколько примеров записей на основе ваших данных и описания и добавил второго пациента, чтобы помочь проверить решение. При таком макете записи данные appearance помещаются в формат значения ключа, а затем данные weight. Используя номера записей, сгенерированные для записей и идентификаторов пациентов, две части объединяются, а строки NA опускаются.

Код следует:

   library(tidyverse)
#
# assume that data for 2 patients would have following format
#

df <- read.table(header=TRUE, stringsAsFactors = FALSE, strip.white = TRUE,
             colClasses = c("character", rep("Date",5), rep("numeric",5)), 
text =  "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
p02  2018-05-01    2018-05-08     2018-05-16  2018-05-22      NA           209        206       208      205        NA
p01  2018-05-28    NA             NA            NA            NA           173        NA        NA        NA        NA
p02  2018-05-28    NA             NA            NA            NA           203        NA        NA        NA        NA")

#
#  put attendance records in key-value format with record number and att_no
#
  df_att <- df %>%  select(id,attendance_1:attendance_5) %>% 
              gather(key = attendance, value = Date,  attendance_1:attendance_5) %>%
              mutate( rec_no = 1:n()) %>% 
              select(-attendance) %>% arrange(id, Date) %>% 
              group_by(id) %>% na.omit() %>% mutate(att_no = 1:n())
#
#  put weight records in key-value format with record number
#
  df_wt <- df %>%  select(id, Weight_1:Weight_5) %>% 
              gather(key = Weighing, value = weight, Weight_1:Weight_5) %>%
              mutate( rec_no = 1:n()) %>%
              select(-Weighing) %>% arrange(id, rec_no) %>% 
              group_by(id) %>% na.omit() 
#
#  join attendance and weight records by id and rec_no
#
   df_tot <- left_join(df_att, df_wt, by = c("id", "rec_no")) %>% 
      arrange( id, Date)
#
#  use spread to transform back to original format forming column names from att_no
#
  df_att_spd <- df_tot %>% mutate(attendance = paste0("attendance_",att_no)) %>%
            select(id, Date,attendance) %>% 
            spread(key = attendance, value = Date)
  df_wt_spd <- df_tot %>% mutate(weighing = paste0("Weight_",att_no)) %>%
           select(id, weight, weighing ) %>%
           spread(key = weighing, value = weight)
 df_tot_spd <- left_join(df_att_spd, df_wt_spd, by = "id")

Это дает результат:

   id    attendance_1 attendance_2 attendance_3 attendance_4 attendance_5 Weight_1 Weight_2 Weight_3 Weight_4 Weight_5
  <chr> <date>       <date>       <date>       <date>       <date>          <dbl>    <dbl>    <dbl>    <dbl>    <dbl>
  p01   2018-05-01   2018-05-08   2018-05-15   2018-05-28   NA                179      176      178      173       NA
  p02   2018-05-01   2018-05-08   2018-05-16   2018-05-22   2018-05-28        209      206      208      205      203

Пожалуйста, уточните, правильно ли я понял ваши данные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...