Как добавить один столбец данных в другой фрейм данных, когда идентификатор доступен в обоих кадрах данных? [Дубликат]

Может показаться логичным создать строку с требуемыми переменными и передать ее в os.system:

touch = 'touch ' + dir + '/' + fileName
os.system(touch)

Это неадекватно несколькими способами (например, он не обрабатывает пробелы), так что не делайте этого.

Более надежным методом является использование подпроцесса:

subprocess.call(['touch', os.path.join(dirname, fileName)])

Хотя это намного лучше, чем использование подоболочки (с os.system), это по-прежнему подходит только для быстрого и грязного сценариев; используйте принятый ответ для кросс-платформенных программ.

936
задан Taryn 22 March 2017 в 17:14
поделиться

11 ответов

При объединении двух кадров данных с ~ 1 миллионом строк каждый, один с двумя столбцами, а другой с ~ 20, я неожиданно обнаружил, что merge(..., all.x = TRUE, all.y = TRUE) будет быстрее, чем dplyr::full_join(). Это с dplyr v0.4

Merge занимает ~ 17 секунд, full_join занимает ~ 65 секунд.

Некоторое питание, хотя, как правило, я использую dplyr для задач манипуляции.

1036
ответ дан Gregor 16 August 2018 в 10:25
поделиться
  • 1
    @MattParker Я использую sqldf-пакет для целого множества сложных запросов по отношению к фреймворкам данных, действительно нужно, чтобы он выполнял самопересечение (например, перекрестное соединение данных.frame). Интересно, как он сравнивается с точки зрения производительности ... . ??? – Nicholas Hamilton 12 February 2013 в 06:42
  • 2
    @ADP Я никогда не использовал sqldf, поэтому я не уверен в скорости. Если производительность является для вас серьезной проблемой, вы также должны заглянуть в пакет data.table - это совершенно новый набор синтаксиса соединения, но он радикально быстрее, чем все, о чем мы говорим здесь. – Matt Parker 12 February 2013 в 18:22
  • 3
    С большей ясностью и объяснением ..... mkmanu.wordpress.com/2016/04/08/… – Manoj Kumar 7 April 2016 в 20:08
  • 4
    Небольшое дополнение, которое мне было полезно - если вы хотите объединить несколько столбцов: merge(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:40
  • 5
    Теперь это работает в data.table, причем такая же функция выполняется быстрее. – marbel 2 December 2016 в 20:44

Вы также можете использовать соединения, используя потрясающий пакет 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)

Мутирующие соединения: добавьте столбцы в df1 с помощью совпадений в df2

#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)

Фильтрация соединений: отфильтровать строки в df1, не изменять столбцы

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.
139
ответ дан Andrew Barr 16 August 2018 в 10:25
поделиться
  • 1
    Зачем вам нужно преобразовать CustomerId в числовой? Я не вижу упоминания в документации (для обоих plyr и dplyr) об этом типе ограничений. Будет ли ваш код работать некорректно, если столбец слияния будет иметь тип character (особенно заинтересованный в plyr)? Я что-то упускаю? – Aleksandr Blekh 11 October 2014 в 04:37
17
ответ дан Community 16 August 2018 в 10:25
поделиться

Существует метод 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 независимо от того, какой тип соединения используется.

166
ответ дан David Arenburg 16 August 2018 в 10:25
поделиться
  • 1
    +1 для упоминания plyr::join. Microbenchmarking указывает, что он выполняет примерно в 3 раза быстрее, чем merge. – Beasterfield 30 May 2013 в 12:28
  • 2
    Однако data.table намного быстрее, чем оба. В SO также есть большая поддержка, я не вижу, чтобы многие авторы писем отвечали на вопросы здесь так же часто, как писатель data.table или авторы. – marbel 2 January 2014 в 04:36
  • 3
    Что такое синтаксис data.table для объединения списка фреймов данных ? – Aleksandr Blekh 6 August 2014 в 04:45
  • 4
    Обратите внимание: dt1 [dt2] является правым внешним соединением (а не «чистым» внутренним соединением) , так что ВСЕ строки из dt2 будут частью результата, даже если в dt1 нет соответствующей строки , Воздействие: В результате у вас есть потенциально нежелательные строки , если у вас есть значения ключей в dt2, которые не соответствуют значениям ключа dt1. – R Yoda 11 November 2015 в 08:24
  • 5
    @RYoda вы можете просто указать 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
55
ответ дан jangorecki 16 August 2018 в 10:25
поделиться
  • 1
    Стоит ли добавить пример, показывающий, как использовать разные имена столбцов в on = тоже? – SymbolixAU 10 May 2016 в 21:52
  • 2
    @Symbolix мы можем дождаться версии 1.9.8, так как она добавит не equi-объединения операторов в on arg – jangorecki 10 May 2016 в 22:00
  • 3
    Другая мысль; стоит ли добавить примечание, что с merge.data.table есть аргумент sort = TRUE по умолчанию, который добавляет ключ во время слияния и оставляет его там в результате. Это то, на что нужно обратить внимание, особенно если вы пытаетесь избежать установки ключей. – SymbolixAU 16 August 2016 в 03:47
  • 4
    Я удивлен, что никто не упомянул, что большинство из них не работают, если есть дубликаты ... – statquant 7 November 2016 в 10:44
  • 5
    @statquant. Вы можете сделать декартовое соединение с 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"]

Можно создать и другую комбинацию внешних соединений путем макетирования примера нижнего нижнего соединения. (да, я знаю, что это эквивалент слова «Я оставлю это как упражнение для читателя ...»)

71
ответ дан JD Long 16 August 2018 в 10:25
поделиться

Новое в 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»).

63
ответ дан maj 16 August 2018 в 10:25
поделиться
  • 1
    Определенно лучшее решение, учитывая важность, которую пакет dplyr приобрел за последние два года. – Marco Fumagalli 25 June 2018 в 08:44

Для внутреннего соединения во всех столбцах вы также можете использовать 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)
5
ответ дан MichaelChirico 16 August 2018 в 10:25
поделиться
  1. Используя функцию merge, мы можем выбрать переменную левой таблицы или правой таблицы, так же, как мы все знакомы с оператором select в SQL (EX: выберите a. * ... или выберите b. * из .....)
  2. Мы должны добавить дополнительный код, который будет подмножаться из недавно объединенной таблицы. SQL: - 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)]

То же самое

  • SQL: - select b.* from df1 a inner join df2 b on a.CustomerId=b.CustomerId
  • R: - merge(df1, df2, by.x = "CustomerId", by.y = "CustomerId")[,names(df2)]
6
ответ дан samadhi 16 August 2018 в 10:25
поделиться

dplyr с 0,4 реализовал все те объединения, в том числе external_join, но стоит отметить, что для первых нескольких релизов он использовал не для того, чтобы предлагать внешний_join, и в результате было много действительно плохой взломанный обходной код пользователя, плавающий вокруг (вы все еще можете найти это в ответах SO и Kaggle с того периода).

Основные моменты выделения :

v0.5 (6/2016)

  • Обработка для типа POSIXct, часовых поясов, дубликатов, разных уровней факторов. Более эффективные ошибки и предупреждения.
  • Новый аргумент суффикса для управления тем, какие суффиксные имена дублированных переменных получают (# 1296)

v0.4.0 (1/2015)

  • Внедрить правое соединение и внешнее соединение (# 96)
  • Мутирующие объединения, которые добавляют новые переменные в одну таблицу из совпадающих строк в другой. Фильтрация соединений, которые фильтруют наблюдения из одной таблицы на основе того, соответствуют ли они наблюдению в другой таблице.

v0.3 (10/2014)

  • Теперь можно оставить left_join разными переменными в каждой таблице: df1%>% left_join (df2, c ("var1" = "var2"))

v0.2 (5/2014)

  • * _ join () больше не переупорядочивает имена колонок (# 324)

v0.1.3 (4/2014)

Обходные решения для комментариев хайли в этой проблеме:

  • right_join (x, y) совпадает с left_join (y, x) в терминов строк, только столбцы будут разными порядками.
  • external_join - это в основном union (left_join (x, y), right_join (x, y)) - то есть сохранить все строки в обоих кадрах данных.
24
ответ дан smci 16 August 2018 в 10:25
поделиться
  • 1
    Этот ответ должен быть обновлен или удален. full_join и right_join были частью dplyr в течение почти двух лет и разделяли имена столбцов x и y еще дольше. Ответы Майя и Эндрю Барра, похоже, хорошо освещают методы dplyr ... – Gregor 22 December 2016 в 19:30
  • 2
    @Gregor: нет, его не следует удалять. Для пользователей R важно знать, что в течение многих лет функции объединения отсутствовали, так как большая часть кода там содержит обходные пути или временные ручные реализации или ad-hocery с векторами индексов или, что еще хуже, позволяет избежать использования этих пакетов или операции вообще. Каждую неделю я вижу такие вопросы на SO. Мы будем уничтожать путаницу на долгие годы. – smci 23 December 2016 в 14:33
  • 3
    Да, он должен быть обновлен в какой-то момент, но все меняется так часто, что это движущаяся цель, так что это произойдет, когда я обернусь к ней. – smci 23 December 2016 в 14:55
  • 4
    @ Грегор и другие, которые спрашивали: обновлялись, суммировали исторические изменения и то, что отсутствовало в течение нескольких лет, когда этот вопрос задавали. Это иллюстрирует, почему код с этого периода был сильно взломан или избегал использования соединений dplyr и отпал на слияние. Если вы проверите исторические кодовые базы на SO и Kaggle, вы все равно увидите задержку принятия и серьезно запутанный код пользователя. Это дало мне знать, если вы все еще не найдете этого ответа. – smci 31 May 2018 в 11:18
  • 5
    Да, я понимаю, и я думаю, вы хорошо справляетесь с этим. (Я тоже был ранним усыновителем, и, хотя мне все еще нравится синтаксис 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 .

183
ответ дан zx8754 16 August 2018 в 10:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: