Как сделать объединение и выбрать только определенную строку из связанной группы? - PullRequest
0 голосов
/ 28 сентября 2018

Я не знаю, как именно сформулировать этот вопрос.Я надеюсь, что станет понятнее, когда я приведу вам пример:

Match <- data.frame(PlayerID=c(1,2,2,3,3), Date = c("01.04.2012","05.04.2012","20.04.2012","23.04.2012","30.04.2012"))     
Playerrating <- data.frame(PlayerID = c(1,1,1,2,2,2), Date= c("01.03.2012","02.04.2012","01.05.2012","01.03.2012","19.04.2012","25.04.2012"),Rating=c(64,71,55,59,73,81))

> Match
PlayerID         Date
1          01.04.2012
2          05.04.2012
2          20.04.2012
3          23.04.2012
3          30.04.2012

> Playerrating
PlayerID       Date   Rating
1          01.03.2012     64
1          02.04.2012     71
1          01.05.2012     55
2          01.03.2012     59
2          19.04.2012     73
2          25.04.2012     81

Я хочу присвоить таблице соответствия правильный рейтинг игрока из таблицы Playerrating, который является первым рейтингом для конкретного игрока последата указана в таблице соответствия.В этом случае это должно выглядеть следующим образом:

Match
PlayerID       Date   Rating
1         01.04.2012     71
2         05.04.2012     73
2         20.04.2012     81
3         23.04.2012     NA
3         30.04.2012     NA

Может ли кто-нибудь помочь мне с этой проблемой?

(Это мой первый вопрос, поэтому, пожалуйста, прости меня, если я несформулировал это очень понятно)

Ответы [ 3 ]

0 голосов
/ 28 сентября 2018

Здесь указана опция tidyverse

library(tidyverse)
left_join(Match, Playerrating, by = "PlayerID") %>%
    mutate(d = as.numeric(difftime(as.Date(Date.y, "%d.%m.%Y"), as.Date(Date.x, "%d.%m.%Y")))) %>%
    group_by(PlayerID, Date.x) %>%
    filter(d > 0 | is.na(Date.y)) %>%
    filter(rank(d) == 1) %>%
    ungroup() %>%
    select(-Date.y, Rating, -d)
## A tibble: 5 x 3
#  PlayerID Date.x     Rating
#     <dbl> <fct>       <dbl>
#1        1 01.04.2012     71
#2        2 05.04.2012     73
#3        2 20.04.2012     81
#4        3 23.04.2012     NA
#5        3 30.04.2012     NA

Объяснение: Выполните левое объединение Match и Playerrating на PlayerID, рассчитайте разницу во времени между всеми датами, сгруппируйте по PlayerID и даты от Match, выберите строки с датами в Playerrating после тех из Match (или пропущенных дат) и, наконец, сохраните только те записи из Playerrating, которые наиболее близки к датам из Match.

0 голосов
/ 28 сентября 2018

Использование пакета :

# load the package
library(data.table)

# convert the dataframe's to data.table's
# and convert the 'Date'-columns to actual Date-class
setDT(Match)[, Date := as.Date(Date, "%d.%m.%Y")][]
setDT(Playerrating)[, Date := as.Date(Date, "%d.%m.%Y")][]

# join option 1:
Match[, rating := Playerrating[.SD, on = .(PlayerID, Date > Date)
                               , mult = "first", x.Rating]]

# join option 2: (per @Frank's comment)
Match[, rating := Playerrating[.SD, on = .(PlayerID, Date)
                               , roll = -Inf, x.Rating]][]

, что дает:

> Match
   PlayerID       Date rating
1:        1 2012-04-01     71
2:        2 2012-04-05     73
3:        2 2012-04-20     81
4:        3 2012-04-23     NA
5:        3 2012-04-30     NA

Решение с базойR:

m <- outer(Match$PlayerID, Playerrating$PlayerID, "==") & outer(Match$Date, Playerrating$Date, "<=")
Match$Rating <- Playerrating$Rating[max.col(m, "first") * NA^!rowSums(m)]

, что дает:

> Match
  PlayerID       Date Rating
1        1 2012-04-01     71
2        2 2012-04-05     73
3        2 2012-04-20     81
4        3 2012-04-23     NA
5        3 2012-04-30     NA
0 голосов
/ 28 сентября 2018

Вы можете выполнить объединение с помощью data.table, используя roll=-Inf для отката следующего значения.

library( data.table )

Сначала преобразуйте свои фреймы данных в таблицы данных.

setDT(Match)
setDT(Playerrating)

Преобразуйте даты в класс Date, чтобы они были обработаны соответствующим образом.

Match[ , Date := as.Date( Date, format = "%d.%m.%Y" ) ]
Playerrating[ , Date := as.Date( Date, format = "%d.%m.%Y" ) ]

Убедитесь, что порядок соответствует.Это не обязательно в вашем примере, но это хорошая практика.

setorder( Match, PlayerID, Date )
setorder( Playerrating, PlayerID, Date )

Выполните объединение.Обратите внимание на roll=-Inf.Это то, что приносит следующее доступное значение в объединение.

Playerrating[ Match, on = .( PlayerID, Date ), roll = -Inf ]

Результат:

   PlayerID       Date Rating
1:        1 2012-04-01     71
2:        2 2012-04-05     73
3:        2 2012-04-20     81
4:        3 2012-04-23     NA
5:        3 2012-04-30     NA
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...