#r #dplyr #data.table
Вопрос:
У меня есть набор данных с повторяющимися записями. Скорее всего, они были вызваны ошибками в данных. После того, как запись неверна, ее исправляют ДРУГОЙ записью. Как бы можно было использовать эти данные. В качестве игрушечного примера:
dt1 lt;- data.table( id = c('a','','a','b','','b','c','','c'), v1 =c('a','a','a','b','b','','c','','c'), v2 =c('a','a','a','b','','b','','','c'), v3 =c('a','a','a','','b','','','c',''), v4 =c('','a','','b','','','c','','c'), v5 =c('a','','a','','','b','','','c'), v6 =c('','a','','','b','b','c','c','c') )
Чего бы я хотел:
dt1 lt;- data.table( id =c('a','b','c'), v1 =c('a','b','c'), v2 =c('a','b','c'), v3 =c('a','b','c'), v4 =c('a','b','c'), v5 =c('a','b','c'), v6 =c('a','b','c'), )
В приведенном выше примере подумайте об идентификаторе, представляющем переменную id, и v1-v6 заполняются случайной информацией
Комментарии:
1. (1) Пожалуйста, проверьте свой код, прежде чем задавать вопрос, ваш второй блок кода содержит синтаксическую ошибку (дополнительная запятая). (2) Легко попытаться решить эту проблему (
dt1[, lapply(.SD, function(Z) Filter(nzchar, unique(Z)))]
), но это связано с предположением, что все столбцы должны иметь одинаковое количество уникальных значений, что является критическим предположением, которое вы не указали. Кроме того, (3) вы говорите, чтоid
это переменная идентификатора, но она выглядит идентичной (и идентично неверной) столбцам данных. Есть ли в этих данных предпосылка «ID»?
Ответ №1:
Вот решение с использованием tidyverse
. Идея заключается в том , чтобы сначала заменить «» на NA
«, использовать fill
для обозначения id
столбца group_by
, id
каждого столбца и summarize
каждого столбца для хранения информации.
Неясно, как выглядит ваша «случайная информация» и как вы хотите обобщить эту информацию. Здесь я предполагаю, что вы хотите сохранить первое значение, отличное от NA, в каждом id
столбце. Это то, чего ~first(.x[!is.na(.x)]))
мы пытаемся достичь. Если у вас есть другие способы обобщения данных, укажите свою функцию в этом расположении.
library(tidyverse) dt1[dt1 == ""] lt;- NA dt1_2 lt;- dt1 %gt;% fill(id, .direction = "downup") %gt;% group_by(id) %gt;% summarize(across(.fns = ~first(.x[!is.na(.x)]))) %gt;% ungroup() dt1_2 # # A tibble: 3 x 7 # id v1 v2 v3 v4 v5 v6 # lt;chrgt; lt;chrgt; lt;chrgt; lt;chrgt; lt;chrgt; lt;chrgt; lt;chrgt; # 1 a a a a a a a # 2 b b b b b b b # 3 c c c c c c c
Обновить
Ниже приведен код, показывающий, как использовать tow across
для применения различных функций к различным группам столбцов.
dt1_2 lt;- dt1 %gt;% fill(id, .direction = "downup") %gt;% group_by(id) %gt;% summarize(across(v1:v4, .fns = ~first(.x[!is.na(.x)])), across(v5:v6, .fns = ~last(.x[!is.na(.x)]))) %gt;% ungroup()
Обновление 2
Вот обновленное решение, которое имеет дело с ситуацией, когда никакие дубликаты не содержат значений, отличных от NA.
dt2 lt;- data.table( id = c('a','','a','b','','b','c','','c'), v1 =c('a','a','a','b','b','','c','','c'), v2 =c('a','a','a','b','','b','','',''), v3 =c('a','a','a','','b','','','c',''), v4 =c('','a','','b','','','c','','c'), v5 =c('a','','a','','','b','','','c'), v6 =c('','a','','','b','b','c','c','c') ) dt2[dt2 == ""] lt;- NA fill_fun lt;- function(x, fun){ if (all(is.na(x))){ result lt;- NA } else { result lt;- fun(x[!is.na(x)]) } return(result) } dt2_2 lt;- dt2 %gt;% fill(id, .direction = "downup") %gt;% group_by(id) %gt;% summarize(across(v1:v4, .fns = ~fill_fun(.x, fun = first)), across(v5:v6, .fns = ~fill_fun(.x, fun = last))) %gt;% ungroup()
Комментарии:
1. Это было действительно полезно!! У меня есть вопрос относительно сохранения первого значения, отличного от NA, для каждого идентификатора: предположим, что существовали столбцы v7 и v8, которые идентифицировали последнюю версию записи. Давайте предположим, что v7-это год, а v8-месяц, что-то, что имеет некоторый порядок. Хорошо, тогда давайте предположим, что та же проблема с дубликатами даже с заданными v7 и v8-НО теперь есть больше точности, потому что вы знаете, что дубликаты должны быть, по крайней мере, последней записью. Как ваша «первая» функция справляется с этим? Есть ли лучший способ, чем просто «~сначала(.x[!is.na(.x)]))»
2. @econfin Пожалуйста, ознакомьтесь с моим обновлением.
3. спасибо за обновление. И последний вопрос-если какой-то новый идентификатор d просто содержит NA для столбца v2 во всех дубликатах, как ваша функция справится с этим?
4. @econfin вы хотите сказать, что в версии 2 нет значений, отличных от NA?
5. точно, поэтому идентификаторы «a» , » b » и » c » имеют дублирующуюся запись, в которой v2 заполняется некоторым значением, отличным от NA. Но для идентификатора «d» ни один из дубликатов не имеет значения, отличного от NA. Если бы у » d » было пять дубликатов, ни у одного из них не было бы версии 2, отличной от NA. НО похоже, что вы уже сделали обновление!!! ты потрясающая!!