Найти дополнение фрейма данных (анти-объединение)
У меня есть два кадра данных (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)