R: объединение столбцов по общему идентификатору без NA в любой строке?

Учитывая данные с пропущенными значениями, вменение — это процесс, в котором пропущенные значения заменяются некоторыми значениями. Цель состоит в том, чтобы игнорировать строки с отсутствующими значениями, обозначенными NA. Такую строку можно рассматривать как компонент данных, поэтому процесс называется вменение элемента.

Ввод

df1 <- data.frame(ID=c(1,2,5,6),V1=c(7,77,777,NA))
df2 <- data.frame(ID=c(1,3,5,6),V2=c(6,66,666,6666))
df3 <- data.frame(ID=c(1,3,5,6),V3=c(9,NA,999,9999))

или, альтернативно, в формате CSV, где значения пропусков отмечены NA

data.csv      data2.csv        data3.csv

ID V1         ID V2            ID V3
1  7          1  6             1  9
2  77         2  NA            2  NA
3  NA         3  66            3  NA
4  NA         4  NA            4  NA
5  777        5  666           5  999
6  NA         6  6666          6  9999

Вывод

Ожидаемый результат

ID V1   V2   V3
1  7    6    9
5  777  666  999

где мы хотели просто строки без какого-либо значения NA.

Как объединить входные данные со столбцами V1, V2, V3 и общим идентификатором столбца без NA в строке?


Пример решения с SQLDF для объединения столбцов с общим идентификатором и без NA

library(sqldf)
# Read in the data: with CSV, you can use read.csv or fread from data.table
df1 <- data.frame(ID=c(1,2,5,6),V1=c(7,77,777,NA))
df2 <- data.frame(ID=c(1,3,5,6),V2=c(6,66,666,6666))
df3 <- data.frame(ID=c(1,3,5,6),V3=c(9,NA,999,9999))
#
sqldf("SELECT a.ID, a.V1, b.V2, c.V3 FROM df1 a, df2 b, df3 c WHERE a.ID=b.ID AND b.ID=c.ID AND V1!='NA'")

в результате

   ID   V1  V2  V3
1   1    7   6   9
2   5  777 666 999

person hhh    schedule 10.08.2011    source источник
comment
Вау, это должно быть один из худших вопросов, которые я когда-либо встречал.   -  person Joshua Ulrich    schedule 10.08.2011
comment
Что с ID = 1? Что ты пытаешься нам сказать? Где ваш воспроизводимый код?   -  person Joris Meys    schedule 10.08.2011
comment
Я предполагаю, что ожидаемый результат - это всего лишь одна строка ожидаемого результата? Что случилось с ID == 1? Должны ли 6 и 3 быть в ожидаемом результате, но с NA, где данные отсутствуют? Код — это здорово, но не ждите, что мы расшифруем смысл вашего вопроса только по нему!   -  person Gavin Simpson    schedule 10.08.2011
comment
@hhh: правда? По какому правилу следует исключить идентификатор 1, поскольку он принадлежит всем 3 кадрам данных, как и идентификатор 5?   -  person Ari B. Friedman    schedule 10.08.2011
comment
@hhh показанные данные и ваша настойчивость в ожидаемом выводе, содержащем только ID 5, несовместимы. Можете ли вы решить, пожалуйста?   -  person Gavin Simpson    schedule 10.08.2011
comment
Нет, почему исключен ID 1 - он присутствует во всех 3 файлах csv   -  person Gavin Simpson    schedule 10.08.2011
comment
Да, это лучше. Обратите внимание, что данные, которые вы показываете, не являются CSV, и нам нелегко работать с этими данными, поскольку они не воспроизводимы или не являются кодом/выводом R.   -  person Gavin Simpson    schedule 10.08.2011


Ответы (2)


Вот базовая версия только для R, которой все равно, сколько слияний. Предполагается, что фреймы данных находятся в списке l — см. редактирование Q для примера данных в этом формате:

for(i in seq_along(l[-1])) {
    if(i == 1) {
        m <- merge(l[[i]], l[[i+1]])
    } else {
        m <- merge(m, l[[i+1]])
    }
}
m <- m[!apply(is.na(m), 1, any), ]

который дает желаемый результат

> m
  ID  V1  V2  V3
1  1   7   6   9
2  5 777 666 999

Чтобы прочитать данные, что-то вроде этого должно работать

l <- lapply(list.files(pattern = glob2rx("data*.csv")), read.table, 
            header = TRUE)

или если они действительно CSV

l <- lapply(list.files(pattern = glob2rx("data*.csv")), read.csv)

то вы можете использовать приведенный выше код для обработки.

person Gavin Simpson    schedule 10.08.2011

Из уважения к художественной форме хайку, прекрасно демонстрируемой в этом вопросе, я собираюсь дать следующий ответ/дикую догадку:

library(reshape)
dats <- lapply( dir(), read.csv )
mgd <- merge_recurse( dats, by="ID" )
na.sel <- apply( mgd, 1, function(x) any(is.na(x)) )
mgd <- mgd[!na.sel,]

Обратите внимание, что это предполагает, что вы действительно хотите ID == 1.

Спасибо @Joris за совет merge_recurse.

person Ari B. Friedman    schedule 10.08.2011
comment
цс тс тс... слияние_рекурсии? : stackoverflow.com/questions/6942662/ - person Joris Meys; 10.08.2011
comment
Ооо, мне нравится! Узнавайте что-то новое каждый день. - person Ari B. Friedman; 10.08.2011
comment
@hhh Это решило вашу проблему? Я бы сам проверил, но без воспроизводимого примера это невозможно. Могу ли я предложить прочитать stackoverflow.com/questions/5963269/? С вашим представителем я удивлен, что это необходимо. - person Ari B. Friedman; 10.08.2011