2012-04-23 2 views
2

У меня есть код, который работает. Но он медленный, и я надеюсь его ускорить, поэтому я могу масштабировать до набора данных из наблюдений за парами-00 000.Более быстрый способ найти совпадения и добавить к data.frame?

У меня есть два кадра данных, один из которых я конвертирую в data.table, используя пакет data.table для быстрого поиска и объединения. Я хочу записывать записи из одного набора данных, когда 3 поля соответствуют записи во втором наборе данных.

Original.df (data frame) и LookHereForMatches.dt (data.table с ключом на a1, a2, a3). Original.df будет иметь от 100 000 до 300 000 наблюдений, а LookHereForMatches.dt, вероятно, будет 2x.

Проведите каждое наблюдение в Original.df и найдите наблюдения в LookHereForMatches.dt, которые соответствуют определенным критериям. Я хочу несколько полей из LookHereForMatches.dt и нескольких полей из Original.df. Я использую subset(), чтобы получить только нужные столбцы.

Возможно, кто-то может сказать мне, какая часть моего кода является наихудшей/самой медленной. Я должен поверить, что это часть rbind (cbind()). Не похоже, что это правильный способ сделать это.

matched_data.df <- data.frame() 
for(i in 1:nrow(Original.df)){ 
    a1 <- Original.df$col1 
    a2 <- Original.df$col2 
    a3 <- Original.df$col3 
    # Use data.table library "join" functionality to get matches (will find at least 1 and up to 4 matches, usually only 1 or 2) 
    match.df <- data.frame(LookHereForMatches.dt[J(a1, a2, a3)], stringsAsFactors=FALSE) 

    # combine matches with original data and add to data.frame to create big list of data with matches 
    matched_data.df <- rbind(cbind(match.df, Original.df[i,], stringsAsFactors=FALSE), matched_data.df) 
} 

UPDATE

Вот примерно то, что выглядит как данные. (Ясно, новичок в R и StackExchange. Я пойму, как сделать таблицы красивее и вернуться, чтобы исправить это тоже. Спасибо @joran за исправление моих таблиц.) Таблицы - довольно простые вещи. Я просто хочу найти каждую строку из первой таблицы и сопоставить ее со всеми соответствующими строками во второй таблице на a1, a2 и a3. В примере первая строка из Original.df должна быть соединена с строками 1, 2 и 3 из таблицы LookHereForMatches.dt, возвращающей 3 строки.

Original.df <- read.table(textConnection(' 
a1 a2 a3 text.field numeric.field 
123 abc 2011-12-01 "some text" 1.0 
124 abc 2011-11-12 "some other text" 0.1 
125 bcd 2011-12-01 "more text" 1.2 
'), header=TRUE) 

LookHereForMatches.df <- read.table(textConnection(' 
a1 a2 a3 text.field numeric.field Status_Ind 
123 abc 2011-12-01 "some text" 10.5 0 
123 abc 2011-12-01 "different text" 0.1 1 
123 abc 2011-12-01 "more text" 0.1 1 
125 bcd 2011-12-01 "other text" 4.3 0 
125 bcd 2011-12-01 "text"  2.2 0 
'), header=TRUE) 

LookHereForMatches.dt <- data.table(LookHereForMatches.df, key=c("a1","a2","a3")) 
+1

Поскольку я не знаю, как выглядят ваши данные, простите меня, если это не поможет ... Если вы можете предоставить небольшой образец своих данных, вы получите гораздо лучшие ответы. Но разве вы не можете использовать что-то вроде условного соответствия? 'Origional.df [Origional.df $ a1% in% LookHereForMatchers.dt $ a1 & Origional.df $ a2% в% LookHereForMatches.dt $ a2,]'. 'For loop' медленный, но' rbind (cbind (...)) 'намного медленнее. В идеале вы можете выделить полный размер 'matched_data.df' перед назначением. Если вы не можете, использование чего-то вроде написанного выше должно помочь некоторым ... – Justin

+0

Я не понимаю (может быть, потому, что вы не представили воспроизводимый пример?), Почему вы не можете просто сделать одно соединение между data.table. – joran

+0

Обновлено для добавления некоторых примерных данных. Я посмотрю% в%. По причине я не могу сделать соединение между data.tables ...Я новичок в R. Я тоже буду участвовать в объединении. – user791770

ответ

3

Это звучит как merge будет делать то, что вы ищете; см. ?merge для деталей.

> merge(Original.df, LookHereForMatches.df, by=c("a1","a2","a3")) 
    a1 a2   a3 text.field.x numeric.field.x text.field.y 
1 123 abc 2011-12-01 some text    1.0  some text 
2 123 abc 2011-12-01 some text    1.0 different text 
3 123 abc 2011-12-01 some text    1.0  more text 
4 125 bcd 2011-12-01 more text    1.2  other text 
5 125 bcd 2011-12-01 more text    1.2   text 
    numeric.field.y Status_Ind 
1   10.5   0 
2    0.1   1 
3    0.1   1 
4    4.3   0 
5    2.2   0 

Если вы хотите больше контроля, то с помощью match за кулисами, что-то вроде этого:

a <- with(Original.df, paste(a1, a2, a3, sep="\b")) 
b <- with(LookHereForMatches.df, paste(a1, a2, a3, sep="\b")) 
m <- match(b, a) 
cbind(Original.df[m,], LookHereForMatches.df) 

Кроме просмотра all вариантов контролировать то, что он делает, когда вещи не появляются в обоих наборы данных.

merge(Original.df, LookHereForMatches.df, by=c("a1","a2","a3"), all=TRUE) 

Что касается скорости с большими наборами данных, вы можете получить ускорение с помощью data.table, но с 1e5 и 3e5 строк в каждой (как следует), в моей системе, слияние занимает всего 2,6 секунды, а матч и cbind всего 1,5 секунды.

set.seed(5) 
N <- 1e5 
Original.df <- data.frame(a1=1:N, a2=1, a3=1, text1=paste("hi",1:N)) 
LookHereForMatches.df <- data.frame(a1=sample(1:N, 3*N, replace=TRUE), 
            a2=1, a3=1, text2=paste("hi", 1:(3*N))) 
+0

Спасибо. Вот и все. suffix = c ("_ first", "_ second") или что-то близкое к этому также помогает при именовании. Попробуйте%%. Но это, похоже, делает трюк. Я отправлю некоторые данные о сроках, когда я его протещу, и заработаю все. – user791770

+0

Я все еще не совсем понимаю, как cbind правильно соответствует строкам, но поскольку merge() получает меня туда, куда мне нужно идти, я буду придерживаться этого. Сроки: 1,000 rows in original.df; 3000 строк в LookHereForMatches.df merge(): 0.015; для цикла: 3.1 10 000 строк; 30 000 строк merge(): 0,25; для петли 74 секунды. – user791770

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