Функция применяется в цикле на двух разных фреймах данных - PullRequest
3 голосов
/ 05 июля 2019

у меня два dataframes. Первая (games) показывает для каждой из нескольких игр год и то, какой игрок достиг определенных неопределенных целей (player1, player2, player3). Второй (rankings) показывает рейтинг каждого игрока в данном году.

Моя цель - добавить столбец данных games, указывающий средний рейтинг всех игроков, достигших этих целей в каждой игре.

Воспроизводимый пример:

set.seed(0)
players <- c("Abe", "Bob", "Chris", "John", "Jane", "Linda", "Mason", "Zoe", "NA")
years <- c(2000:2005)
season <- sample(years, 20, replace = TRUE)
player1 <- sample(players, 20, replace = TRUE)
player2 <- sample(players, 20, replace = TRUE)
player3 <- sample(players, 20, replace = TRUE)
games <- data.frame(season, player1, player2, player3, stringsAsFactors = FALSE)
rankings <- data.frame(replicate(6,sample(1:5,8,rep=TRUE)))
colnames(rankings) <- years
ranked_players <- players[-9]
rankings <- cbind(ranked_players, rankings)

games - это первый dataframe, показывающий год игры (season), который был player1, кто был player2, а кто был player3. Не всегда игрок для всех категорий для всех игр.

rankings - это второе dataframe, показывающее рейтинг от 1 до 5 каждого игрока в данном году.

Я хочу рассчитать рейтинг игрока, который сыграл соответственно player1, player2 и player3 для каждой игры в играх, и усреднить эти рейтинги.

Чтобы рассчитать рейтинг, я попробовал эту функцию:

calc_ranking <- function(x, y) {
  z <- select(filter(rankings, ranked_players==x), c(y))
  z <- as.integer(z[1,1])
  z
}

Видимо, работает. Теперь я должен применить его для каждого игрока, который играл в игры в играх, и для каждого года.

Я пробовал этот цикл:

new_col <- mapply(calc_ranking, games$player1, games$season)

но это не работает. Это дает мне ошибку

 Error in inds_combine(.vars, ind_list) : Position must be between 0 and n 

Однако, даже если это сработало, с этим решением я должен повторить цикл 3 раза, чтобы создать 3 столбца, по одному для каждой роли как player1, player2 и player3, а затем создать столбец, который я действительно хочу (средний из 3 столбцов). Я подозреваю, что есть более эффективный способ сделать это без повторения цикла (при условии, что я могу это исправить)? Это было бы очень полезно, потому что в моем реальном наборе данных у меня 13 «ролей», для которых мне нужно вычислить рейтинг.

Надеюсь, этот второй вопрос лучше моего первого. Извиняюсь за любую ошибку, я только 1 неделю изучаю R (это мой первый опыт работы с кодированием в целом).

Большое спасибо!

Ответы [ 2 ]

1 голос
/ 05 июля 2019

Я интерпретировал ваш желаемый результат немного по-другому, чем @Cole, так как вы хотели, чтобы столбец средних рангов игрока за игру.Моя стратегия заключалась в том, чтобы извлекать игроков в свои собственные кадры данных (при этом нужно менять имена столбцов, чтобы они не были числовыми).Затем для каждого из player1, player2 и player3 найдите игрока в этой «позиции» и найдите его рейтинг в отдельном кадре данных.Я уверен, что есть более эффективные способы сделать это, но в этом случае это сработало (хотя я не уверен, что это именно то, что вам нужно.

Выход:

> head(games,10)
     season player1 player2 player3 player1_rank player2_rank player3_rank    means
1  year2005   Mason    John    John            3            3            3 3.000000
2  year2001    <NA>     Zoe    <NA>           NA            4           NA       NA
3  year2002     Bob   Linda   Chris            3            4            3 3.333333
4  year2003   Linda     Zoe    Jane            5            5            3 4.333333
5  year2005     Bob    Jane   Chris            5            1            3 3.000000
6  year2001   Chris    Jane   Linda            1            1            4 2.000000
7  year2005    John     Zoe   Chris            3            3            3 3.000000
8  year2005     Abe     Abe    Jane            4            4            1 3.000000
9  year2003    John    Jane   Mason            1            3            3 2.333333
10 year2003     Zoe   Mason     Abe            5            3            5 4.333333

Код:

for (player in players){
    temp_player <- filter(rankings, ranked_players == player)
    colnames(temp_player) <- c("player","year2000","year2001","year2002","year2003","year2004","year2005")
    assign(paste(player), temp_player)
}

games$season <- paste0("year",games$season)
games[games=="NA"] <- NA

i <- 1
for (rows in games$player1){
        if (!is.na(games$player1[i])) {
            season <- games$season[i]
            games$player1_rank[i] <- get(games$player1[i])[,season]
        }
        else
        {
            games$player1_rank[i] <- NA
        }
        i <- i + 1
    }

i <- 1
for (rows in games$player2){
        if (!is.na(games$player2[i])) {
            season <- games$season[i]
            games$player2_rank[i] <- get(games$player2[i])[,season]
        }
        else
        {
            games$player2_rank[i] <- NA
        }
        i <- i + 1
    }

i <- 1
for (rows in games$player3){
        if (!is.na(games$player3[i])) {
            season <- games$season[i]
            games$player3_rank[i] <- get(games$player3[i])[,season]
        }
        else
        {
            games$player3_rank[i] <- NA
        }
        i <- i + 1
    }

games$means <- rowMeans(games[,5:7]

Данные:

set.seed(0)
players <- c("Abe", "Bob", "Chris", "John", "Jane", "Linda", "Mason", "Zoe", "NA")
years <- c(2000:2005)
season <- sample(years, 20, replace = TRUE)
player1 <- sample(players, 20, replace = TRUE)
player2 <- sample(players, 20, replace = TRUE)
player3 <- sample(players, 20, replace = TRUE)
games <- data.frame(season, player1, player2, player3, stringsAsFactors = FALSE)
rankings <- data.frame(replicate(6,sample(1:5,8,rep=TRUE)))
colnames(rankings) <- years
ranked_players <- players[-9]
rankings <- cbind(ranked_players, rankings)
1 голос
/ 05 июля 2019

Насколько я понимаю, каждая строка в games является отдельным идентификатором игры. Так для:

season    player1    player2   player3
  2001        Joe       Bill      Jane

player    season     ranking
   Joe      2001           1
  Bill      2001           3
  Jane      2001           5

Предполагаемый ответ - 3 для этой игры. Чтобы решить эту проблему, самый простой способ - объединить данные, а затем объединить два data.frames в сезоне и имя игрока. Редактировать: добавлен вывод, аналогичный @heds со строками dcast().

library(data.table)

setDT(games)
games[, game_id := seq_len(.N), keyby = season]

molten_games <- melt(games, id.vars = c('season', 'game_id'), variable.name = 'player_number', value.name = 'player')

setDT(rankings)
molten_rankings <- melt(rankings, id.vars = 'ranked_players', variable.name = 'season', value.name = 'ranking', variable.factor = F)[, season:= as.integer(season)]

merged_dt <- molten_rankings[molten_games
                             , on = .(season
                                      , ranked_players = player )
                             , nomatch = 0L
                             ]

merged_dt[, mean(ranking, na.rm = T), by = .(season, game_id)]
    season game_id       V1
 1:   2000       1 2.666667
 2:   2001       2 2.000000
 3:   2001       3 1.333333
 4:   2001       4 4.000000
 5:   2002       1 3.333333
...
#or if you want all the players and rankings
dcast(merged_dt, season + game_id ~ player_number, value.var = c('ranked_players', 'ranking')
      )[, means := rowMeans(.SD), .SDcols = c('ranking_player1', 'ranking_player2', 'ranking_player3')][]

    season game_id ranked_players_player1 ranked_players_player2 ranked_players_player3 ranking_player1 ranking_player2 ranking_player3    means
 1:   2000       1                   John                  Mason                    Zoe               2               2               4 2.666667
 2:   2001       1                   <NA>                    Zoe                   <NA>              NA               4              NA       NA
 3:   2001       2                  Chris                   Jane                  Linda               1               1               4 2.000000
 4:   2001       3                   Jane                   Jane                   John               1               1               2 1.333333
 5:   2001       4                  Linda                    Zoe                    Zoe               4               4               4 4.000000
...

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

library(dplyr)
library(tidyr)

long_rankings <- rankings%>%
  gather(key = 'season', value = 'ranking', - ranked_players)%>%
  mutate(season = as.integer(season))

long_games <- games%>%
  arrange(season)%>%
  group_by(season)%>%
  mutate(game_id = row_number())%>%
  ungroup()%>%
  gather(key = 'player_number', value = 'player', -season, - game_id)

inner_join(long_rankings
           ,long_games
           , by = c('season' = 'season'
                    , 'ranked_players' = 'player'))%>%
  group_by(season, game_id)%>%
  summarize(game_rank_ave = mean(ranking, na.rm = T))

   season game_id game_rank_ave
    <int>   <int>         <dbl>
 1   2000       1          2.67
 2   2001       1          4   
 3   2001       2          2   
 4   2001       3          1.33
 5   2001       4          4   
 6   2002       1          3.33

Что касается генерации ваших данных, пожалуйста, будьте осторожны с cbind() !! Он приводит объекты в матрицу, и матрицы могут иметь только один класс, например символьный или числовой. Я обратился к генерации data.frame для решения этой проблемы.

Используемые данные:

set.seed(0)
players <- c("Abe", "Bob", "Chris", "John", "Jane", "Linda", "Mason", "Zoe", "NA")
years <- c(2000:2005)
season <- sample(years, 20, replace = TRUE)
player1 <- sample(players, 20, replace = TRUE)
player2 <- sample(players, 20, replace = TRUE)
player3 <- sample(players, 20, replace = TRUE)
games <- data.frame(season, player1, player2, player3, stringsAsFactors = FALSE)
rankings <- data.frame(replicate(6,sample(1:5,8,rep=TRUE)))
colnames(rankings) <- years
ranked_players <- players[-9]
#rankings <- cbind(ranked_players, rankings) ##don't cbind unless you're making a matrix!
rankings$ranked_players <- players[-9] 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...