#r #time #rstudio #rows #missing-data
#r #время #rstudio #строки #отсутствует -данные
Вопрос:
Допустим, у меня есть продольный набор данных, как показано ниже
ID <- c(1, 1, 2, 2, 3, 3, 4, 4)
time <- c(1, 2, 1, 2, 1, 2, 1, 2)
value <- c(7, 5, 9, 2, NA, 3, 7, NA)
mydata <- data.frame(ID, time, value)
ID time value
1 1 1 7
2 1 2 5
3 2 1 9
4 2 2 2
5 3 1 NA
6 3 2 3
7 4 1 7
8 4 2 NA
В этом наборе данных у нас есть 4 обращения с данными в два момента времени (скажем, до и после обработки)
Что-то, что я хочу сделать, это установить критерии для удаления любого обращения, которое не завершено для обоих временных точек. В этом примере я хотел бы удалить ID3 (у которого отсутствует временная точка 1) и ID4 (у которого отсутствует временная точка 2). Как показано ниже:
ID time value
1 1 1 7
2 1 2 5
3 2 1 9
4 2 2 2
Мне не очень повезло. Я пробовал варианты complete.cases() или which() безрезультатно
Я все еще новичок в R и был бы очень признателен, если бы кто-нибудь мог мне помочь
Редактировать: Спасибо, Ронак, за ответ на мой вопрос. После анализа моих реальных данных я столкнулся со второй проблемой. Мои фактические данные в большей степени отражены в приведенном ниже:
ID <- c(1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8)
time <- c(1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 1, 1)
value <- c(7, 5, 9, 2, NA, 3, 7, NA, 8, 9, 7, 6)
mydata <- data.frame(ID, time, value)
ID time value
1 1 1 7
2 1 2 5
3 2 1 9
4 2 2 2
5 3 1 NA
6 3 2 3
7 4 1 7
8 4 2 NA
9 5 1 8
10 6 1 9
11 7 1 7
12 8 1 6
Где я также хотел бы удалить обращения 5, 6, 7 и 8. Эти идентификаторы содержат запись для времени 1, но не для времени 2. Надеюсь, это имеет смысл
Большое спасибо
Комментарии:
1.
library(dplyr) ; mydata %>% group_by(ID) %>% filter(!any(is.na(c(time, value))))
Ответ №1:
Если вы переведете свои данные в широкий формат (где каждый момент времени представлен в виде отдельного столбца), тогда вы можете использовать na.omit
. Использование dplyr
и tidyr
функции:
library(dplyr)
mydata <- mydata %>%
tidyr::spread(key=time, value=value) %>% # reformat to wide
na.omit() %>% # delete cases with missingness on any variable (i.e. any time point)
tidyr::gather(key="time", value="value", -ID) # put it back in long format
> mydata
ID time value
1 1 1 7
2 2 1 9
3 1 2 5
4 2 2 2
Обратите внимание, что это будет работать (будут сохранены только обращения с полными данными как для времени 1, так и для времени 2), даже если у вас отсутствует момент времени без явного NA, присутствующего в данных, например:
> mydata
ID time value
1 1 1 7
2 1 2 5
3 2 1 9
4 2 2 2
5 3 1 NA
6 3 2 3
7 4 1 7
8 4 2 NA
9 5 1 8
10 6 1 9
11 7 1 7
12 8 1 6
Комментарии:
1. Большое вам спасибо, Роуз, — это отлично ответило на мой запрос. Я бы никогда не понял этого самостоятельно. Спасибо всем за их ответы
2. Рад помочь! Мне нравятся
dplyr
tidyr
пакеты и для обычных манипуляций с фреймами данных, подобных этому.3. Спасибо, Роуз, если вы меня порадуете, у меня есть еще один вопрос… скажем, я должен был добавить третий момент времени. Когда я пытаюсь переформатировать в wide с помощью tidyr::spread(ключ = время, значение = значение) , он выдает ошибку повторяющиеся идентификаторы для строк . Я не совсем уверен, как настроить код для трех временных точек. Был бы признателен, если у вас есть какие-либо предложения
4. Эта ошибка не связана с добавлением третьей временной точки. Что-то еще идет не так. Возможно, у вас есть какие-либо случаи, когда один и тот же идентификатор имеет одинаковое время более одного раза? Быстрый способ проверить — получить количество уникальных строк, используя только ID и time, и сравнить это с количеством строк во всем наборе данных. Они должны быть одинаковыми:
nrow(unique(dplyr::select(my_data, ID, time))); nrow(my_data)
5. Еще раз спасибо, Роуз, вы совершенно правы. Ваш код продемонстрировал явное несоответствие. Я думал, что это может быть так, но ранее отфильтровал свой набор данных, означающий, что номера строк не синхронизированы. Я искал дубликат не в том месте. Действительно ценю, что вы нашли время, чтобы помочь 🙂
Ответ №2:
Вы можете сделать это легко с sqldf
помощью .
library(sqldf)
sqldf(' select * from (select ID, count(*) as cnt from mydata where value is not null group by id having cnt >1 ) t1 inner join mydata t2 on t1.ID=t2.ID')
Вы должны выбрать те идентификаторы, число которых больше 1 и в значениях которых нет NA, а затем снова присоединиться к исходным данным.
Ответ №3:
@Ronak уже предоставил
mydata[!mydata$ID %in% mydata$ID[is.na(mydata$value)], ]
Для второй части вы можете просто группировать по каждому идентификатору и фильтровать по их частоте
k2 <- data.frame(table(mydata$ID))
k2$Var1[k2$Freq > 1]
а затем сделайте что-то вроде
mydata[mydata$ID %in% k2$Var1[k2$Freq > 1],]
Ответ №4:
Смотрите Обновленный ответ
# Eliminates ID cases with NA
mydata = mydata[!mydata$ID %in% mydata[!complete.cases(mydata) ,]$ID, ]
library(plyr)
# counts all the IDs
cnt = count(mydata, "ID")
# Eliminates any ID that doesn't have 2 observations
mydata[mydata$ID %in% cnt[cnt$freq == 2, ]$ID, ]
ID time value
1 1 1 7
2 1 2 5
3 2 1 9
4 2 2 2
Комментарии:
1. Спасибо за предложение @Ash
2. @perkot смотрите Обновленный ответ на ваш обновленный вопрос
3. Спасибо всем за ваши предложения — мне сейчас нужно бежать с работы, но я проверю все предложения сегодня вечером
4. Привет @Ash — у меня только что была возможность попробовать ваше решение, оно отлично сработало. Спасибо, что нашли время помочь. Более того, это решение позволяет мне изменять код для дополнительных временных точек