r - ¿Cómo pasar un tibble a una función y calcular sumas condicionales?

CorePress2024-01-25  8

Estoy intentando escribir una función que calcule una puntuación a partir de las divisiones de un jugador de béisbol. He creado el Tibble dividido, un Tibble funcional y una función para usar junto con la función mutar para agregar una columna de puntuación al Tibble funcional, df.

Se supone que la función toma la información del Tibble en funcionamiento y calcula una puntuación (suma de promedios) basada en las divisiones relevantes. He proporcionado el siguiente reprex. Cuando intento ejecutar mi función, obtengo puntuaciones de cero. Los valores de puntuación esperados siguen el reprex.

¿Alguien puede decirme qué estoy haciendo mal?

library(tidyverse)

split <- tibble(player=c("Soto","Soto","Judge","Judge","Soto","Soto","Judge","Judge"),
                split=c("Grass","Turf","Grass","Turf","DAY","NIGHT", "DAY","NIGHT"),
                AVG=c(200,225,250,275,300,325,350,375))
df <- tibble(date = c("2021-03-24", "2021-03-27", "2021-03-21", "2021-03-25"), player=c("Soto","Soto", "Judge", "Judge"), TOD=c("DAY","DAY","DAY","NIGHT"), surface=c("Grass","Turf","Turf","Grass"))

split
#> # A tibble: 8 x 3
#>   player split   AVG
#>   <chr>  <chr> <dbl>
#> 1 Soto   Grass   200
#> 2 Soto   Turf    225
#> 3 Judge  Grass   250
#> 4 Judge  Turf    275
#> 5 Soto   DAY     300
#> 6 Soto   NIGHT   325
#> 7 Judge  DAY     350
#> 8 Judge  NIGHT   375

df
#> # A tibble: 4 x 4
#>   date       player TOD   surface
#>   <chr>      <chr>  <chr> <chr>  
#> 1 2021-03-24 Soto   DAY   Grass  
#> 2 2021-03-27 Soto   DAY   Turf   
#> 3 2021-03-21 Judge  DAY   Turf   
#> 4 2021-03-25 Judge  NIGHT Grass

getSplitScore <- function(df,player,surface, timeofDay){
 
  z <- sum(df[df$player==player & df$split==timeofDay,]$AVG)
  y <- sum(df[df$player==player & df$split==surface,]$AVG)
  
  return(z + y)
}


df <- df %>% 
  mutate(score=getSplitScore(split, player, surface, TOD))

df
#> # A tibble: 4 x 5
#>   date       player TOD   surface score
#>   <chr>      <chr>  <chr> <chr>   <int>
#> 1 2021-03-24 Soto   DAY   Grass       0
#> 2 2021-03-27 Soto   DAY   Turf        0
#> 3 2021-03-21 Judge  DAY   Turf        0
#> 4 2021-03-25 Judge  NIGHT Grass       0

Creado el 27-03-2021 por el paquete reprex (v0.3.0)

Lo que espero es esto:

#> # A tibble: 4 x 5
#>   date       player TOD   surface score
#>   <chr>      <chr>  <chr> <chr>   <int>
#> 1 2021-03-24 Soto   DAY   Grass     500
#> 2 2021-03-27 Soto   DAY   Turf      525
#> 3 2021-03-21 Judge  DAY   Turf      625
#> 4 2021-03-25 Judge  NIGHT Grass     625 

1

No tienes una columna BaVG en el tibble dividido. Tampoco estoy seguro de cómo se llega a los valores de puntuación.

- WilliamGram

27/03/2021 a las 20:39

En el resultado deseado, la puntuación de 200 es la suma de Soto Day & ¿Soto TOD? Sólo necesito un ejemplo de cómo se calcula la puntuación.

Anoushiravan R.

27/03/2021 a las 20:41

La puntuación es simplemente la suma del BaVG a dividir/

Mutualinvestor

27/03/2021 a las 23:57

@WilliamGram Buen partido. A veces puedes estar demasiado cerca de las cosas. ¡Gracias!

Mutualinvestor

28 de marzo de 2021 a las 0:02



------------------------------------

Agregar un group_by antes de ejecutar mutate en pipe funcionará. Ver

df %>% group_by(date, player) %>%
  mutate(score= getSplitScore(split, player, surface, TOD))

# A tibble: 4 x 5
# Groups:   date, player [4]
  date       player TOD   surface score
  <chr>      <chr>  <chr> <chr>   <dbl>
1 2021-03-24 Soto   DAY   Grass     500
2 2021-03-27 Soto   DAY   Turf      525
3 2021-03-21 Judge  DAY   Turf      625
4 2021-03-25 Judge  NIGHT Grass     625

Estrategia alternativa propuesta

df %>% left_join(split, by = c("player" = "player", "TOD" = "split")) %>%
  rbind(df %>% left_join(split, by = c("player" = "player", "surface" = "split"))) %>%
  group_by(date, player, TOD, surface) %>%
  summarise(AVG = sum(AVG))

# A tibble: 4 x 5
# Groups:   date, player, TOD [4]
  date       player TOD   surface   AVG
  <chr>      <chr>  <chr> <chr>   <dbl>
1 2021-03-21 Judge  DAY   Turf      625
2 2021-03-24 Soto   DAY   Grass     500
3 2021-03-25 Judge  NIGHT Grass     625
4 2021-03-27 Soto   DAY   Turf      525

2

Gracias por la respuesta. Se supone que mi función hace referencia al df dividido. No estoy tratando de resumir columnas en df, estoy tratando de calcular una puntuación de la columna AVG en la división cuando la superficie y la hora del día en df y la división coinciden.

Mutualinvestor

28 de marzo de 2021 a las 8:26

1

Sí. Entiendo. Vea mi respuesta revisada. Simplemente agregue un group_by antes de mutar en dplyr pipe y funcionará.

AnilGoyal

28 de marzo de 2021 a las 8:27



------------------------------------

Comenzaría dividiendo la columna split$split en territorio y día. Un enfoque menos elegante:

split <- split %>% 
  mutate(
    TOD = ifelse(split %in% c('DAY', 'NIGHT'), split, 'NA'),
    surface = ifelse(split %in% c('Grass', 'Turf'), split, 'NA'),
    .keep = 'unused'
  )

Entonces puedes dejar de unirte:

df <- df %>% 
  left_join(
    split %>% select(-surface) %>% rename(todVal = AVG), by = c('player', 'TOD')
  ) %>% 
  left_join(
    split %>% select(-TOD) %>% rename(surfaceVal = AVG), by = c('player', 'surface')
  ) %>% 
  mutate(score = (todVal + surfaceVal), .keep='unused')

El resultado que deberías obtener:

df
#         date player   TOD surface score
# 1 2021-03-24   Soto   DAY   Grass 500.0
# 2 2021-03-27   Soto   DAY    Turf 525.0
# 3 2021-03-21  Judge   DAY    Turf 625.0
# 4 2021-03-25  Judge NIGHT   Grass 625.0

Veo que el resultado no es el que querías, pero tal vez deberías intentar ser un poco más claro en lo que estás buscando.tratando de hacer.

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare