def touch(fname):
if os.path.exists(fname):
os.utime(fname, None)
else:
open(fname, 'a').close()
При объединении двух кадров данных с ~ 1 миллионом строк каждый, один с двумя столбцами, а другой с ~ 20, я неожиданно обнаружил, что merge(..., all.x = TRUE, all.y = TRUE)
будет быстрее, чем dplyr::full_join()
. Это с dplyr v0.4
Merge занимает ~ 17 секунд, full_join занимает ~ 65 секунд.
Некоторое питание, хотя, как правило, я использую dplyr для задач манипуляции.
Вы также можете использовать соединения, используя потрясающий пакет dplyr Хэдли Уикхэма].
library(dplyr)
#make sure that CustomerId cols are both type numeric
#they ARE not using the provided code in question and dplyr will complain
df1$CustomerId <- as.numeric(df1$CustomerId)
df2$CustomerId <- as.numeric(df2$CustomerId)
#inner
inner_join(df1, df2)
#left outer
left_join(df1, df2)
#right outer
right_join(df1, df2)
#alternate right outer
left_join(df2, df1)
#full join
full_join(df1, df2)
semi_join(df1, df2) #keep only observations in df1 that match in df2.
anti_join(df1, df2) #drops all observations in df1 that match in df2.
CustomerId
в числовой? Я не вижу упоминания в документации (для обоих plyr
и dplyr
) об этом типе ограничений. Будет ли ваш код работать некорректно, если столбец слияния будет иметь тип character
(особенно заинтересованный в plyr
)? Я что-то упускаю?
– Aleksandr Blekh
11 October 2014 в 04:37
Существует метод data.table для внутреннего соединения, который очень эффективен для времени и памяти (и необходим для некоторых более крупных data.frames):
library(data.table)
dt1 <- data.table(df1, key = "CustomerId")
dt2 <- data.table(df2, key = "CustomerId")
joined.dt1.dt.2 <- dt1[dt2]
merge
также работает с данными .tables (поскольку он является общим и вызывает merge.data.table
)
merge(dt1, dt2)
data.table, зарегистрированный в stackoverflow: Как выполнить операцию слияния данных.table Перевод SQL присоединяется к внешним ключам к синтаксису R data.table . Эффективные альтернативы слиянию для больших данных. Кадры R Как сделать базовое левое внешнее соединение с data.table в R?
Еще одна опция - функция join
, найденная в пакете plyr
library(plyr)
join(df1, df2,
type = "inner")
# CustomerId Product State
# 1 2 Toaster Alabama
# 2 4 Radio Alabama
# 3 6 Radio Ohio
Опции для type
: inner
, left
, right
, full
.
Из ?join
: В отличие от merge
, [join
] сохраняет порядок x независимо от того, какой тип соединения используется.
plyr::join
. Microbenchmarking указывает, что он выполняет примерно в 3 раза быстрее, чем merge
.
– Beasterfield
30 May 2013 в 12:28
data.table
намного быстрее, чем оба. В SO также есть большая поддержка, я не вижу, чтобы многие авторы писем отвечали на вопросы здесь так же часто, как писатель data.table
или авторы.
– marbel
2 January 2014 в 04:36
data.table
для объединения списка фреймов данных i>?
– Aleksandr Blekh
6 August 2014 в 04:45
nomatch = 0L
в этом случае.
– David Arenburg
11 November 2015 в 22:20
Обновление методов data.table для объединения наборов данных. Ниже приведены примеры для каждого типа соединения. Существует два метода: один из [.data.table
при передаче второй data.table в качестве первого аргумента для подмножества, другой способ - использовать функцию merge
, которая отправляется в быстрый метод data.table.
Обновление от 2016-04-01 - и это не шутка в апреле! В версии 1.9.7 версии data.table теперь могут использовать существующий индекс, который значительно сокращает время соединения. Ниже кода и эталона НЕ используются индексы data.table при объединении. Если вы ищете соединение в режиме реального времени, вы должны использовать индексы data.table.
df1 = data.frame(CustomerId = c(1:6), Product = c(rep("Toaster", 3), rep("Radio", 3)))
df2 = data.frame(CustomerId = c(2L, 4L, 7L), State = c(rep("Alabama", 2), rep("Ohio", 1))) # one value changed to show full outer join
library(data.table)
dt1 = as.data.table(df1)
dt2 = as.data.table(df2)
setkey(dt1, CustomerId)
setkey(dt2, CustomerId)
# right outer join keyed data.tables
dt1[dt2]
setkey(dt1, NULL)
setkey(dt2, NULL)
# right outer join unkeyed data.tables - use `on` argument
dt1[dt2, on = "CustomerId"]
# left outer join - swap dt1 with dt2
dt2[dt1, on = "CustomerId"]
# inner join - use `nomatch` argument
dt1[dt2, nomatch=0L, on = "CustomerId"]
# anti join - use `!` operator
dt1[!dt2, on = "CustomerId"]
# inner join
merge(dt1, dt2, by = "CustomerId")
# full outer join
merge(dt1, dt2, by = "CustomerId", all = TRUE)
# see ?merge.data.table arguments for other cases
Ниже контрольных баз тестов R, sqldf, dplyr и data.table. Бенчмарк тестирует неблокированные / неиндексированные наборы данных. Вы можете получить еще лучшую производительность, если используете свои ключи data.tables или индексы с sqldf. Base R и dplyr не имеют индексов или ключей, поэтому я не включил этот сценарий в эталон. Бенчмаркинг выполняется по наборам массивов 5M-1, в столбце соединения есть 5M-2 общих значения, поэтому каждый сценарий (слева, справа, полный, внутренний) может быть протестирован, а объединение все еще не является тривиальным для выполнения.
library(microbenchmark)
library(sqldf)
library(dplyr)
library(data.table)
n = 5e6
set.seed(123)
df1 = data.frame(x=sample(n,n-1L), y1=rnorm(n-1L))
df2 = data.frame(x=sample(n,n-1L), y2=rnorm(n-1L))
dt1 = as.data.table(df1)
dt2 = as.data.table(df2)
# inner join
microbenchmark(times = 10L,
base = merge(df1, df2, by = "x"),
sqldf = sqldf("SELECT * FROM df1 INNER JOIN df2 ON df1.x = df2.x"),
dplyr = inner_join(df1, df2, by = "x"),
data.table = dt1[dt2, nomatch = 0L, on = "x"])
#Unit: milliseconds
# expr min lq mean median uq max neval
# base 15546.0097 16083.4915 16687.117 16539.0148 17388.290 18513.216 10
# sqldf 44392.6685 44709.7128 45096.401 45067.7461 45504.376 45563.472 10
# dplyr 4124.0068 4248.7758 4281.122 4272.3619 4342.829 4411.388 10
# data.table 937.2461 946.0227 1053.411 973.0805 1214.300 1281.958 10
# left outer join
microbenchmark(times = 10L,
base = merge(df1, df2, by = "x", all.x = TRUE),
sqldf = sqldf("SELECT * FROM df1 LEFT OUTER JOIN df2 ON df1.x = df2.x"),
dplyr = left_join(df1, df2, by = c("x"="x")),
data.table = dt2[dt1, on = "x"])
#Unit: milliseconds
# expr min lq mean median uq max neval
# base 16140.791 17107.7366 17441.9538 17414.6263 17821.9035 19453.034 10
# sqldf 43656.633 44141.9186 44777.1872 44498.7191 45288.7406 47108.900 10
# dplyr 4062.153 4352.8021 4780.3221 4409.1186 4450.9301 8385.050 10
# data.table 823.218 823.5557 901.0383 837.9206 883.3292 1277.239 10
# right outer join
microbenchmark(times = 10L,
base = merge(df1, df2, by = "x", all.y = TRUE),
sqldf = sqldf("SELECT * FROM df2 LEFT OUTER JOIN df1 ON df2.x = df1.x"),
dplyr = right_join(df1, df2, by = "x"),
data.table = dt1[dt2, on = "x"])
#Unit: milliseconds
# expr min lq mean median uq max neval
# base 15821.3351 15954.9927 16347.3093 16044.3500 16621.887 17604.794 10
# sqldf 43635.5308 43761.3532 43984.3682 43969.0081 44044.461 44499.891 10
# dplyr 3936.0329 4028.1239 4102.4167 4045.0854 4219.958 4307.350 10
# data.table 820.8535 835.9101 918.5243 887.0207 1005.721 1068.919 10
# full outer join
microbenchmark(times = 10L,
base = merge(df1, df2, by = "x", all = TRUE),
#sqldf = sqldf("SELECT * FROM df1 FULL OUTER JOIN df2 ON df1.x = df2.x"), # not supported
dplyr = full_join(df1, df2, by = "x"),
data.table = merge(dt1, dt2, by = "x", all = TRUE))
#Unit: seconds
# expr min lq mean median uq max neval
# base 16.176423 16.908908 17.485457 17.364857 18.271790 18.626762 10
# dplyr 7.610498 7.666426 7.745850 7.710638 7.832125 7.951426 10
# data.table 2.052590 2.130317 2.352626 2.208913 2.470721 2.951948 10
on =
тоже?
– SymbolixAU
10 May 2016 в 21:52
on
arg
– jangorecki
10 May 2016 в 22:00
merge.data.table
есть аргумент sort = TRUE
по умолчанию, который добавляет ключ во время слияния и оставляет его там в результате. Это то, на что нужно обратить внимание, особенно если вы пытаетесь избежать установки ключей.
– SymbolixAU
16 August 2016 в 03:47
data.table
, что вы имеете в виду? Вы можете быть более конкретным, пожалуйста.
– David Arenburg
11 June 2017 в 07:51
Есть несколько хороших примеров для этого в R Wiki . Я украду пару здесь:
Метод слияния
Поскольку ваши ключи называются одинаковыми, короткий способ сделать внутреннее соединение - merge ():
merge(df1,df2)
полное внутреннее соединение (все записи из обеих таблиц) может быть создано с помощью ключевого слова «все»:
merge(df1,df2, all=TRUE)
левое внешнее соединение df1 и df2:
merge(df1,df2, all.x=TRUE)
правое внешнее объединение df1 и df2:
merge(df1,df2, all.y=TRUE)
вы можете перевернуть их, пощекотать их и протрите их, чтобы получить другие два внешних соединения, о которых вы спрашивали:)
Метод подстроки
Левое внешнее соединение с df1 слева с использованием метода подстроки будет:
df1[,"State"]<-df2[df1[ ,"Product"], "State"]
Можно создать и другую комбинацию внешних соединений путем макетирования примера нижнего нижнего соединения. (да, я знаю, что это эквивалент слова «Я оставлю это как упражнение для читателя ...»)
Новое в 2014 году:
Особенно, если вы также заинтересованы в манипулировании данными в целом (включая сортировку, фильтрацию, подмножество, подведение итогов и т. д.), вам обязательно нужно взглянуть на dplyr
, который поставляется с множеством функций, которые предназначены для облегчения вашей работы с кадрами данных и некоторыми другими типами баз данных. Он даже предлагает довольно сложный SQL-интерфейс и даже функцию для преобразования (большинства) SQL-кода непосредственно в R.
. Четыре функции, связанные с соединением в пакете dplyr, (цитата):
inner_join(x, y, by = NULL, copy = FALSE, ...)
: вернуть все строки из x, где в y есть соответствующие значения, а все столбцы из x и y left_join(x, y, by = NULL, copy = FALSE, ...)
: вернуть все строки из x и все столбцы от x и y semi_join(x, y, by = NULL, copy = FALSE, ...)
: вернуть все строки из x, где в y есть соответствующие значения, сохраняя только столбцы из x. anti_join(x, y, by = NULL, copy = FALSE, ...)
: вернуть все строки из x, где в y нет совпадающих значений, сохраняя только столбцы из x Здесь все здесь
Выбор столбцов может выполняться с помощью select(df,"column")
. Если для вас недостаточно SQL-ish, то есть функция sql()
, в которую вы можете ввести код SQL как есть, и он будет выполнять указанную вами операцию так же, как вы писали в R все время (для получения дополнительной информации , обратитесь к dplyr / database vignette ). Например, если применить правильно, sql("SELECT * FROM hflights")
выберет все столбцы из таблицы dplyr «hflights» («tbl»).
Для внутреннего соединения во всех столбцах вы также можете использовать fintersect
из data.table -пакет или intersect
из dplyr -пакета в качестве альтернатив merge
без указания by
-колонков. это даст строки, которые равны между двумя кадрами данных:
merge(df1, df2)
# V1 V2
# 1 B 2
# 2 C 3
dplyr::intersect(df1, df2)
# V1 V2
# 1 B 2
# 2 C 3
data.table::fintersect(setDT(df1), setDT(df2))
# V1 V2
# 1: B 2
# 2: C 3
Пример данных:
df1 <- data.frame(V1 = LETTERS[1:4], V2 = 1:4)
df2 <- data.frame(V1 = LETTERS[2:3], V2 = 2:3)
merge
, мы можем выбрать переменную левой таблицы или правой таблицы, так же, как мы все знакомы с оператором select в SQL (EX: выберите a. * ... или выберите b. * из .....) select a.* from df1 a inner join df2 b on a.CustomerId=b.CustomerId
R: - merge(df1, df2, by.x = "CustomerId", by.y = "CustomerId")[,names(df1)]
То же самое
select b.* from df1 a inner join df2 b on a.CustomerId=b.CustomerId
merge(df1, df2, by.x = "CustomerId", by.y =
"CustomerId")[,names(df2)]
dplyr с 0,4 реализовал все те объединения, в том числе external_join, но стоит отметить, что для первых нескольких релизов он использовал не для того, чтобы предлагать внешний_join, и в результате было много действительно плохой взломанный обходной код пользователя, плавающий вокруг (вы все еще можете найти это в ответах SO и Kaggle с того периода).
Основные моменты выделения :
v0.1.3 (4/2014)
Обходные решения для комментариев хайли в этой проблеме:
full_join
и right_join
были частью dplyr
в течение почти двух лет и разделяли имена столбцов x и y еще дольше. Ответы Майя и Эндрю Барра, похоже, хорошо освещают методы dplyr
...
– Gregor
22 December 2016 в 19:30
dplyr
, изменение от lazyeval
до rlang
backends разбило мне кучу кода, что заставило меня узнать больше data.table
, а теперь В основном я использую data.table
.)
– Gregor
31 May 2018 в 14:02
Я бы рекомендовал проверить пакет sqldf Gabor Grothendieck , который позволяет вам выражать эти операции в SQL.
library(sqldf)
## inner join
df3 <- sqldf("SELECT CustomerId, Product, State
FROM df1
JOIN df2 USING(CustomerID)")
## left join (substitute 'right' for right join)
df4 <- sqldf("SELECT CustomerId, Product, State
FROM df1
LEFT JOIN df2 USING(CustomerID)")
Я нахожу синтаксис SQL более простым и более естественным, чем его эквивалент R (но это может просто отражать смещение RDBMS).
Для получения дополнительной информации о объединениях см. Gabor's sqldf GitHub .
data.table
- это совершенно новый набор синтаксиса соединения, но он радикально быстрее, чем все, о чем мы говорим здесь. – Matt Parker 12 February 2013 в 18:22merge(x=df1,y=df2, by.x=c("x_col1","x_col2"), by.y=c("y_col1","y_col2"))
– Dileep Kumar Patchigolla 1 December 2016 в 11:40data.table
, причем такая же функция выполняется быстрее. – marbel 2 December 2016 в 20:44