Найти дополнение фрейма данных (анти-объединение)

У меня есть два кадра данных (df и df1). df1 является подмножеством df. Я хочу получить фрейм данных, который является дополнением к df1 в df, т.е. вернуть строки первого набора данных, которые не совпадают во втором. Например, пусть

фрейм данных df:

heads
row1
row2
row3
row4
row5

фрейм данных df1:

heads
row3
row5

Тогда желаемый вывод df2 будет:

heads
row1
row2
row4

7 ответов

Решение

Пытаться anti_join от dplyr

library(dplyr)
anti_join(df, df1, by='heads')

Вы также можете сделать какой-то тип анти-соединения с data.tableбинарное соединение

library(data.table)
setkey(setDT(df), heads)[!df1]
#    heads
# 1:  row1
# 2:  row2
# 3:  row4

РЕДАКТИРОВАТЬ: начиная с data.table v1.9.6 + мы можем присоединиться к data.tables без установки ключей при использовании on

setDT(df)[!df1, on = "heads"]

EDIT2: начиная с data.table v1.9.8 + fsetdiff был представлен, который в основном является вариантом решения выше, только для всех имен столбцов x таблица данных, например x[!y, on = names(x)], Если all установлен в FALSE (поведение по умолчанию), затем только уникальные строки в x будет возвращен. Для случая только одного столбца в каждой таблице данных следующее будет эквивалентно предыдущим решениям

fsetdiff(df, df1, all = TRUE)

Попробуйте %in% команда и повернуть его с !

df[!df$heads %in% df1$heads,]

Другой вариант, используя базу R и setdiff функция:

df2 <- data.frame(heads = setdiff(df$heads, df1$heads))

setdiff функционирует именно так, как вы себе представляете; принять оба аргумента как наборы и удалить все элементы второго из первого.

я нахожу setdiff более читабельный тахтн %in% и я предпочитаю не требовать дополнительных библиотек, когда они мне не нужны, но какой ответ вы используете, во многом вопрос личного вкуса.

dplyr также имеет setdiff() который даст вам

введите описание изображения здесь

setdiff(bigFrame, smallFrame) дает вам дополнительные записи в первой таблице.

так что для примера ОП код будет читать setdiff(df, df1)

У dplyr много замечательных функций: краткое руководство смотрите здесь.

Поздний ответ, но для другого варианта мы можем попробовать сделать формальное анти-объединение SQL, используя sqldf пакет:

library(sqldf)
sql <- "SELECT t1.heads
        FROM df t1 LEFT JOIN df1 t2
            ON t1.heads = t2.heads
        WHERE t2.heads IS NULL"
df2 <- sqldf(sql)

sqldf Пакет может быть полезен для тех задач, которые легко формулируются с использованием логики SQL, но, возможно, менее легко формулируются с использованием базового R или другого пакета R.

Еще один вариант, создав функцию negate_match_df манипулируя кодом match_df из plyr пакет.

library(plyr)
negate_match_df <- function (x, y, on = NULL) 
{
if (is.null(on)) {
    on <- intersect(names(x), names(y))
    message("Matching on: ", paste(on, collapse = ", "))
}
keys <- join.keys(x, y, on)
x[!keys$x %in% keys$y, , drop = FALSE]
}

Данные

df <- read.table(text ="heads
row1
row2
row3
row4
row5",header=TRUE)

df1 <- read.table(text ="heads
row3
row5",header=TRUE)

Выход

negate_match_df(df,df1)
Другие вопросы по тегам