Найти ближайшее наибольшее значение или эквивалент на основе нескольких переменных - PullRequest
1 голос
/ 12 февраля 2020

У меня есть следующие три кадра данных:

df1
   grade PIR  rate
1      7 min 10.80
2      8 min 11.26
3      9 min 12.10
4      7  X1 11.17
5      8  X1 11.65
6      9  X1 12.56
7      7  X2 11.55
8      8  X2 12.06
9      9  X2 13.03
10     7  X3 11.95
...

и

df2
   grade PIR new_rate
1      7 min    13.00
2      8 min    13.00
3      9 min    13.00
4      7  X1    13.48
5      8  X1    13.48
6      9  X1    13.48
7      7  X2    13.98
8      8  X2    13.98
9      9  X2    13.98
10     7  X3    14.50
...

и

df3
ID      assoc_rate   assoc_grade
124575  10.80        7
123413  11.42        7
111539  11.65        8
112284  12.04        8
125245  12.10        9
132588  12.44        9
....

Для каждого случая df3$assoc_rate и df3$assoc_grade Мне нужно идентифицировать ближайшее наивысшее значение (или эквивалентное) из df1$rate в том же df1$grade, чтобы объединить df1$grade и df1$PIR, что затем позвольте мне присоединить df2$new_rate на основе grade и PIR.

Моя конечная цель - присоединить new_rate и PIR от df2 до df3 на основе их assoc_rate и assoc_grade, но это должно быть по отношению к df1 .

Итак, мой желаемый фрейм данных будет выглядеть так:

df_desired
ID      assoc_rate   assoc_grade   PIR   new_rate 
124575  10.80        7             min     13.00      
123413  11.42        7             X2      13.98     
111539  11.65        8             X1      13.48     
112284  12.04        8             X2      13.98     
125245  12.10        9             min     13.00     
132588  12.44        9             X1      13.48 
....

Here are the dataframes:
df1 <- data.frame(grade = c(7L, 8L, 9L, 7L, 8L, 9L, 7L, 8L, 9L,7L, 8L, 9L, 7L, 8L, 9L), PIR = c("min", "min", "min", "X1", "X1","X1", "X2", "X2", "X2", "X3", "X3", "X3", "X4", "X4", "X4"),rate = c(10.8, 11.26, 12.1, 11.17, 11.65, 12.56, 11.55, 12.06, 13.03, 11.95, 12.49, 13.53, 12.35, 12.93, 14.04))
df2 <- data.frame(grade = c(7L, 8L, 9L, 7L, 8L, 9L, 7L, 8L, 9L,7L, 8L, 9L, 7L, 8L, 9L), PIR = c("min", "min", "min", "X1", "X1","X1", "X2", "X2", "X2", "X3", "X3", "X3", "X4", "X4", "X4"),new_rate = c(13, 13, 13, 13.48, 13.48, 13.48, 13.98, 13.98,13.98, 14.5, 14.5, 14.5, 15.04, 15.04, 15.04))
df3 <- data.frame(ID = c(124575, 123413, 111539, 112284, 125245, 132588), assoc_rate = c(10.80,11.42,11.65,12.04,12.10,12.44), assoc_grade = c(7,7,8,8,9,9))

Спасибо за любые идеи или инструкции. (Я пробовал что-то вроде this , но не знал, как заставить это работать.)

Ответы [ 4 ]

1 голос
/ 13 февраля 2020

Поскольку вы сослались на вопрос с ответом data.table, здесь есть вариант с использованием data.table:

library(data.table)
setDT(df1); setDT(df2); setDT(df3)

#rolling join
df3[, PIR :=
    df1[.SD, on=.(grade=assoc_grade, rate=assoc_rate), roll="nearest", PIR]
]

#update join
df3[df2, on=.(assoc_grade=grade, PIR), new_rate := new_rate]

выход:

       ID assoc_rate assoc_grade PIR new_rate
1: 124575      10.80           7 min    13.00
2: 123413      11.42           7  X2    13.98
3: 111539      11.65           8  X1    13.48
4: 112284      12.04           8  X2    13.98
5: 125245      12.10           9 min    13.00
6: 132588      12.44           9  X1    13.48
1 голос
/ 12 февраля 2020

Использование tidyverse

df3 %>% 
left_join(df1, by = c("assoc_grade" = "grade")) %>% 
mutate(diff     = rate - assoc_rate, 
       new_diff = ifelse(diff < 0, 1000, diff)) %>% 
group_by(ID) %>% 
filter(new_diff == min(new_diff)) %>% 
ungroup() %>% 
left_join(df2, by = c("assoc_grade" = "grade", "PIR" = "PIR"))

join и filter - необходимые шаги. Использование group_by перед filter ing позволяет вам filter для каждого ID.

0 голосов
/ 12 февраля 2020

Спасибо Akash87 за ответ. Но я думаю, что у него мало синтаксических ошибок. Переписав его так, он точно будет соответствовать вашему примеру

df3 %>% 
  left_join(df1, by = c("grade" = "grade")) %>% 
  mutate(diff     = rate - assoc_rate, 
         new_diff = ifelse(diff < 0, 1000, diff)) %>% 
  group_by(ID) %>% 
  filter(new_diff == min(new_diff)) %>% 
  ungroup() %>% 
  left_join(df2, by = c("grade" = "grade", "PIR.x" = "PIR"))
0 голосов
/ 12 февраля 2020

Создать функцию для поиска ближайшего наивысшего или эквивалентного

Вдохновленный ссылкой Как найти первый элемент группы, который удовлетворяет условию

first_equal_sup <- function(x, value){
(x >= value) & (cumsum(x >= value) == 1)}

Получить все соответствующие строки из df1 в списке

j<- 1

x <- list()

for (i in df3$assoc_rate){

# Извлечь группу в df3

df3_group <- df3[df3$assoc_rate == i, "grade"]

# Извлечь все строки с соответствующей группой

df1_group <- df1[df1$grade == df3_group,]

# Поместить каждый соответствующую строку в списке и присоединиться с помощью df2

x[[j]] <- df1_group[first_equal_sup(df1_group$rate, i),]

j <- j+1
}

df <- Reduce(rbind, x) %>% left_join(df2, by=c("grade", "PIR")) %>%
right_join(df3[,c("ID", "grade", "PIR")])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...