a <- c(1,45,90,115,170,203,259)
b <- c(35,60,110,145,190,231,270)
df <- data.frame(a,b)

c <- c(27,175, 230)

Я хотел бы вставить значения c в df, и положение в строке значений должно зависеть от того, где они находятся между значениями столбца a и b. Например. c[2] (175) должно появиться в той же строке, что и a = 170 & b = 190, 230 должно находиться в той же строке, что и a = 203 b = 270, и т. Д.

c содержит меньше значений, чем df, поэтому ячейки могут быть NA.

Я нигде не могу найти на это ответа. Лучшее, что я нашел, - это функция roll = nearest в таблицах данных, но она не допускает условия «не больше».

Я мог бы использовать цикл for, однако данные велики, так что это был бы ресурсный метод.

У кого-нибудь есть идеи? Спасибо.

1
Gary866 8 Сен 2016 в 20:35

3 ответа

Лучший ответ

Используйте findInterval() для определения действительных индексов

aidx = findInterval(c, df$a)
bidx = findInterval(c, df$b) + 1
keep = aidx == bidx

Затем обновите исходный фрейм данных

df[aidx[keep], "c"] = c[keep]

Я ожидал, что это будет быстро до 100 миллионов строк, если строки data.frame уже отсортированы.

3
Martin Morgan 8 Сен 2016 в 23:01

Если вы хотите, чтобы это происходило быстро, вы можете попробовать non-equi функцию присоединения в data.table версии 1.9.7:

library(data.table)
v <- c(27, 175, 230)
v_dt <- data.table(id = v, c = v)  # create a data table with an identical column to 
                                   # join with df

v_dt[setDT(df), .(a, b, c), on = .(id > a, id < b), allow = T]

#     a   b   c
#1:   1  35  27
#2:  45  60  NA
#3:  90 110  NA
#4: 115 145  NA
#5: 170 190 175
#6: 203 231 230
#7: 259 270  NA

Если у вас нет data.table 1.9.7, вы можете использовать foverlaps. Параметр по умолчанию type - any, что означает, что если значение в [id, c] из v_dt имеет какое-либо перекрытие с диапазоном [a, b] из df, они будут совпадать, поскольку id == c для каждой строки, это эквивалентно тому, что id попадает в диапазон:

setkey(v_dt, id, c)
setkey(df, a, b)

foverlaps(df, v_dt)[, id := NULL][,.(a, b, c)]

#     a   b   c
#1:   1  35  27
#2:  45  60  NA
#3:  90 110  NA
#4: 115 145  NA
#5: 170 190 175
#6: 203 231 230
#7: 259 270  NA
1
Psidom 8 Сен 2016 в 21:17

Вот решение с использованием базы R.

#sample data
a <- c(1,45,90,115,170,203,259)
b <- c(35,60,110,145,190,231,270)
df <- data.frame(a,b)
c <- c(27,175, 230)

#Solution
#create place holder column
df$c<-NA
#find rows where the elements of c will fit
location<-which(c > df$a & c<df$b)
#update dataframe
df$c[location]<-c

Команда which выдаст кучу предупреждений, но это не имеет значения. Это решение будет работать только в том случае, если существует 1 и единственное решение для каждого элемента в векторе c.

0
Dave2e 8 Сен 2016 в 18:07