TransWikia.com

Interpolation of values from list

Stack Overflow Asked on November 27, 2021

I have a dataframe containing the results of a competition. In this example competitors b and c have tied for second place. The actual dataframe is very large and could contain multiple ties.

df <- data.frame(name = letters[1:4],
                 place = c(1, 2, 2, 4))

I also have point values for the respective places, where first place gets 4 points, 2nd gets 3, 3rd gets 1 and 4th gets 0.

points <- c(4, 3, 1, 0)
names(points) <- 1:4

I can match points to place to get each competitor’s score

df %>% 
  mutate(score = points[place])
  name place score
1    a     1     4
2    b     2     3
3    c     2     3
4    d     4     0

What I would like to do though is award points to b and c that are the mean of the point values for 2nd and 3rd, such that each receives 2 points like this:

  name place  score
1    a     1      4
2    b     2      2
3    c     2      2
4    d     4      0

How can I accomplish this programmatically?

3 Answers

Robert Wilson's answer gave me an idea. Rather than mapping over nested dataframes the rank function from base can get to the same result

df %>% 
  mutate(new_place = rank(place, ties.method = "first")) %>% 
  mutate(score = points[new_place]) %>% 
  group_by(place) %>% 
  summarize(score = mean(score)) %>% 
  inner_join(df)

  place score name 
  <dbl> <dbl> <chr>
1     1     4 a    
2     2     2 b    
3     2     2 c    
4     4     0 d   

Answered by Greg on November 27, 2021

This can be accomplished in few lines with an ifelse() statement inside of a mutate():

df %>% 
  group_by(place) %>%
  mutate(n_ties = n()) %>%
  ungroup %>%
  mutate(score = (points[place] + ifelse(n_ties > 1, 1, 0))/ n_ties)


# A tibble: 4 x 4
  name  place n_ties score
  <chr> <dbl>  <int> <dbl>
1 a         1      1     4
2 b         2      2     2
3 c         2      2     2
4 d         4      1     0

Answered by CzechInk on November 27, 2021

A solution using nested data frames and purrr.

library(dplyr)
library(tidyr)
library(purrr)
df <- data.frame(name = letters[1:4],
             place = c(1, 2, 2, 4))

points <- c(4, 3, 1, 0)
names(points) <- 1:4
# a function to help expand the dataframe based on the number of ties
expand_all <- function(x,n){
  x:(x+n-1)
}

df %>% 
  group_by(place) %>% 
  tally() %>% 
  mutate(new_place = purrr::map2(place,n, expand_all)) %>% 
  unnest(new_place) %>% 
  mutate(score = points[new_place]) %>% 
  group_by(place) %>% 
  summarize(score = mean(score)) %>% 
  inner_join(df)

Answered by Robert Wilson on November 27, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP