Как объединить фрейм данных, выбирая выбранные значения на основе некоторых логических критериев?

#r #dataframe #merge #logical-operators #forecasting

#r #фрейм данных #слияние #логические операторы #прогнозирование

Вопрос:

У меня есть 3 фрейма данных с аналогичной структурой, и я пытаюсь заполнить 4-й фрейм данных значениями из первых 3 фреймов данных, но на основе логических условий.

Мой фрейм данных 1

 `Account id Value $   RMSE
   1          500      10 
   2         7000      15 
   3         1900      20 
  

Мой фрейм данных 2

 `Account id Value $   RMSE
   1           400      5 
   2          8000     18 
   3          1700     18 
  

Мой фрейм данных 3

 `Account id Value $   RMSE
   1           500     10 
   2          2000     25 
   3          5000    0.2 
  

Мой желаемый результат (значение, полученное из фрейма данных, который имеет наименьший соответствующий RMSE)

 `Account id Value $
  1           400
  2          7000
  3          5000
  

Просим вашей помощи о том, как объединить.

Ответ №1:

В случае вашей проблемы вам необходимо связать все ваши фреймы данных по строкам. После этого вы можете использовать tidyverse функции для фильтрации по группе, определенной идентификатором учетной записи. Здесь код с tidyverse подходом:

 library(tidyverse)
#Code
ndf <- do.call(bind_rows,list(df1,df2,df3)) %>%
  group_by(Account.id) %>%
  filter(RMSE==min(RMSE)) %>% select(Account.id,Value) %>%
  arrange(Account.id)
  

Вывод:

 # A tibble: 3 x 2
# Groups:   Account.id [3]
  Account.id Value
       <int> <int>
1          1   400
2          2  7000
3          3  5000
  

Некоторые используемые данные:

 #Data 1
df1 <- structure(list(Account.id = 1:3, Value = c(500L, 7000L, 1900L
), RMSE = c(10L, 15L, 20L)), class = "data.frame", row.names = c(NA, 
-3L))

#Data 2
df2 <- structure(list(Account.id = 1:3, Value = c(400L, 8000L, 1700L
), RMSE = c(5L, 18L, 18L)), class = "data.frame", row.names = c(NA, 
-3L))

#Data 3
df3 <- structure(list(Account.id = 1:3, Value = c(500L, 2000L, 5000L
), RMSE = c(10, 25, 0.2)), class = "data.frame", row.names = c(NA, 
-3L))
  

Ответ №2:

Опция с data.table

 library(data.table)
rbindlist(list(df1, df2, df3))[, .(Value = Value[which.min(RMSE)]), .(Account.id)]
#   Account.id Value
#1:          1   400
#2:          2  7000
#3:          3  5000
  

Или с tidyverse использованием slice_min после связывания наборов данных вместе с bind_rows

 library(dplyr)
bind_rows(df1, df2, df3) %>% 
    group_by(Account.id) %>% 
    slice_min(RMSE) %>% 
    select(-RMSE)
# A tibble: 3 x 2
# Groups:   Account.id [3]
#  Account.id Value
#       <int> <int>
#1          1   400
#2          2  7000
#3          3  5000
  

 df1 <- structure(list(Account.id = 1:3, Value = c(500L, 7000L, 1900L
), RMSE = c(10L, 15L, 20L)), class = "data.frame", row.names = c(NA, 
-3L))

df2 <- structure(list(Account.id = 1:3, Value = c(400L, 8000L, 1700L
), RMSE = c(5L, 18L, 18L)), class = "data.frame", row.names = c(NA, 
-3L))

df3 <- structure(list(Account.id = 1:3, Value = c(500L, 2000L, 5000L
), RMSE = c(10, 25, 0.2)), class = "data.frame", row.names = c(NA, 
-3L))
  

Ответ №3:

Базовая опция R использует merge aggregate

 merge(
  df <- do.call(rbind, lst(df1, df2, df3)),
  aggregate(RMSE ~ Account.id, df, min)
)[c("Account.id","Value")]
  

что дает

   Account.id Value
1          1   400
2          2  7000
3          3  5000