2013-04-23 2 views
3

Мне нужно объединить два кадра данных. Первый из них выглядит следующим образом:Слияние кадров данных с предсказуемыми опечатками

> df1 <- data.frame(Artist = c("Vincent van ", "Vincent van ", "Theo van Gogh", "Alexandre", "Alexandre"), Location = c("a","a","a","b","c"), time = c(1,2,1,1,1)) 
> df1 
     Artist Location time 
1 Vincent van   a 1 
2 Vincent van   a 2 
3 Theo van Gogh  a 1 
4  Alexandre  b 1 
5  Alexandre  c 1 

И второе:

> df2 <- data.frame(Artist = c("Vincent van Gogh", "Theo van Gogh", "Alexandre Dumas", "Alexandre Dumas"), HomeNumber = c(123,234,456,789), Location = c("a","a","b","c")) 
> df2 
      Artist HomeNumber Location 
1 Vincent van Gogh  123  a 
2 Theo van Gogh  234  a 
3 Alexandre Dumas  456  b 
4 Alexandre Dumas  789  c 

И я хочу этот кадр данных:

> df3 <- data.frame(Artist = c("Vincent van ", "Vincent van ", "Theo van Gogh", "Alexandre", "Alexandre"), Location = c("a","a","a","b","c"), time = c(1,2,1,1,1), HomeNumber = c(123,123,234,456,789)) 
> df3 
     Artist Location time HomeNumber 
1 Vincent van   a 1  123 
2 Vincent van   a 2  123 
3 Theo van Gogh  a 1  234 
4  Alexandre  b 1  456 
5  Alexandre  c 1  789 
> 

Объединение будет работать только для Тео:

> df3 <- merge(df1, df2, by.x = "Artist", by.y = "Artist", all.x =TRUE) 
> df3 
     Artist Location.x time HomeNumber Location.y 
1  Alexandre   b 1   NA  <NA> 
2  Alexandre   c 1   NA  <NA> 
3 Theo van Gogh   a 1  234   a 
4 Vincent van   a 1   NA  <NA> 
5 Vincent van   a 2   NA  <NA> 

Причина двоякая: (a) У Винсента отсутствует его фамилия в df1. (b) Александр - имя Александра Дюма старший и младший Александр Дюма.

Я могу решить (а) с df1$Artist <- gsub("Vincent van $","Vincent van Gogh", df1$Artist), но мои данные на самом деле очень большие, и перед выполнением gsub Я должен сначала узнать полное имя Винсента. Одним из возможных решений могло бы быть использование grep("Vincent van "... в df2, построить функцию, которая, если длина результирующего вектора равна 1, я бы использовал gsub для использования возвращаемого df2$Artist в df1. Я не знаю, как это сделать.

(b) немного сложнее для меня. Одно из решений, которое я могу придумать (но не могу кодировать), - это использовать функцию if, чтобы сначала выбрать Alexandre из одного места, а затем использовать решение для (a) до gsub имени.

Я думаю, что решение (a) и (b) вернет мой желаемый df3. Вы, ребята, знаете, как я могу эффективно объединить эти данные? Благодаря!

EDIT: Обратите внимание, что Alexandre фактически представляет собой два разных устройства. Таким образом, при слиянии двух из них должны быть связанные с ними HomeNumber и Location. Vincent - это единое целое, но с двумя наблюдениями во времени.

+0

вы можете попробовать с 'матчем()' функцией, где вы можете поместить 'location' в качестве аргумента матча и остальных столбцов, чтобы показать в новом data.frame – Duck

+0

Функция 'agrep' выполняет нечеткое соответствие строк. Вы также можете выполнить несколько шагов, таких как «tolower» и удаление знаков препинания, чтобы помочь ... Но самый короткий ответ заключается в том, что обработка данных утомительна! – Justin

+0

@ Duck: Это может помочь, но я не вижу, как это решит проблему. Благодаря! @Justin: Я знаю! Чрезвычайно утомительный. Я уже использовал 'tolower',' chartr' и некоторые другие функции. – Lucarno

ответ

2

Вы надеетесь, что этот результат саботируется тем фактом, что вам необходимо иметь две строки в каждом кадре данных, которые вы хотите рассматривать как имеющие hte одинаковый идентификатор, а именно строки Alexandre. Процесс РЕГИСТРИРУЙТЕСЬ сделает, что в 2 х 2 матча:

df2$short <- substr(df2$Artist, 1,7) 
df1$short <- substr(df1$Artist, 1,7) 
(dfmer <- merge(df1, df2, by="short")) 
#----- 
    short  Artist.x Location.x time   Artist.y HomeNumber Location.y 
1 Alexand  Alexandre   b 1 Alexandre Dumas  456   b 
2 Alexand  Alexandre   b 1 Alexandre Dumas  789   c 
3 Alexand  Alexandre   c 1 Alexandre Dumas  456   b 
4 Alexand  Alexandre   c 1 Alexandre Dumas  789   c 
5 Theo va Theo van Gogh   a 1 Theo van Gogh  234   a 
6 Vincent Vincent van   a 1 Vincent van Gogh  123   a 
7 Vincent Vincent van   a 2 Vincent van Gogh  123   a 

Вы можете использовать дублируется на место и время, если вы хотите, чтобы выбрать первые экземпляры:

> dfmer[!duplicated(dfmer[, c("Location.x", "time")]), ] 
    short  Artist.x Location.x time   Artist.y HomeNumber Location.y 
1 Alexand  Alexandre   b 1 Alexandre Dumas  456   b 
3 Alexand  Alexandre   c 1 Alexandre Dumas  456   b 
5 Theo va Theo van Gogh   a 1 Theo van Gogh  234   a 
7 Vincent Vincent van   a 2 Vincent van Gogh  123   a 

В ответ на озабоченность (ранее не воскресает, что Место должно быть добавлено в качестве связующего переменного:

> (dfmer <- merge(df1, df2, by=c("short", "Location"))) 
    short Location  Artist.x time   Artist.y HomeNumber 
1 Alexand  b  Alexandre 1 Alexandre Dumas  456 
2 Alexand  c  Alexandre 1 Alexandre Dumas  789 
3 Theo va  a Theo van Gogh 1 Theo van Gogh  234 
4 Vincent  a Vincent van  1 Vincent van Gogh  123 
5 Vincent  a Vincent van  2 Vincent van Gogh  123 
+0

Спасибо, @Dwin.Однако обратите внимание, что 'Alexandre' из' Location' 'c' имеет неправильный HomeNumber – Lucarno

+0

Если HomeNumber связан с общим идентификатором, так как я полагаю, что это с Location, тогда вы должны добавить идентификатор к переменным 'by'. –

+0

Извините, я не прояснил это. – Lucarno

Смежные вопросы