2015-07-01 4 views
4

У меня есть два dataframes:В R: Замена значения столбца фрейма данных по значению другого кадра данных, когда между состоянием подобран

set.seed(343) 
testDF <- data.frame(Score = sample(50, size=50, replace=TRUE), number = rep(letters[1:25],2), Rev = rep(0,50)) 
sourceDF <- data.frame(min = c(1,10,20,30,40), max = c(9, 19, 29, 39, 50), rev = 1:5) 

Для каждой строки testDF, где testDF $ оценки составляет от sourceDF $ min и sourceDF $ max источника DF, замените значение testDF $ Rev на соответствующий sourceDF $ rev.

У меня есть работа с двумя для циклов и условием if, но это ... slow (у моего набора данных есть около 1 миллиона строк). Я пробовал использовать findInterval без успеха.

Есть ли лучший/более эффективный способ сделать это?

+1

Что такое 'письмо'? Кроме того, используйте 'set.seed' при использовании' rnorm'. Наконец, ваш пример не так хорош, потому что 'Score' никогда не будет больше, чем' 9', поэтому он никогда не упадет ни в одном ведре, кроме первого. Вместо этого я бы использовал 'sample'. –

+1

Ваш пример не запускается. нет функции, называемой буквой. Можно найти более быстрое решение, используя() и/или применимое семейство. –

+0

@TanDollars 'apply' семья не собирается ничего улучшать. 'который' не подходит очень хорошо здесь ни AFIK. –

ответ

5

Во-первых, см. Мой комментарий о том, как улучшить свой вопрос и сделать его воспроизводимым. Во-вторых, вот возможный подход, как запустить перекрывание присоединяется быстро с помощью data.table::foverlaps

library(data.table) 
setkey(setDT(testDF)[, Score2 := Score], Score, Score2) # create bounds and key 
setkey(setDT(sourceDF), min, max) # Key by min, max 
indx <- foverlaps(sourceDF, testDF, nomatch = 0L, which = TRUE) # run foverlaps 
testDF[indx$yid, Rev := sourceDF[indx$xid, rev]] # Update in place by corresponding values 
+1

Разве это не просто 'findInterval (testDF $ Score, c (1,10,20,30,40,50))'? – thelatemail

+1

'findInterval (testDF $ Score, c (1,10,20,30,40,50), rightmost.closed = TRUE)', чтобы быть абсолютно конкретным. – thelatemail

+0

@thelatemail у вас есть точка там. Вы, вероятно, должны опубликовать это. Мой подход более общий, хотя он будет работать и для нескольких переменных. –

0

Спасибо за ответы. Думаю, я опубликовал этот пример слишком быстро, не протестировав его. Позор мне ... @ Давид спасибо за указатели Я буду смотреть дальше в функцию foverlaps (и будет исследовать больше мира таблиц данных).

Я нашел работу, которая работает очень хорошо и быстро. Поскольку у меня ограниченное количество диапазонов (5 в примере), я просто подмножу tesdDF на 5 кадров данных, используя функцию фильтра (библиотека dplyr) в переменной Score.

testDF1 <- filter(testDF, Score>=1 & Score <=9) ## First DF 

Тогда речь идет только о назначении значений Rev в каждом из этих кадров данных.

testDF1$Rev <- sourceDF$rev[1] 

Это было менее 1 секунды против 1h35mn для моего старого цикла на 800k + рядах.

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