dplyr - ¿Cómo agregar valor a los últimos valores de cada categoría en R?

CorePress2024-01-24  7

Muestra de datos.

mydat=structure(list(supplier = c("MyAgent", "MyAgent", "MyAgent", 
"MyAgent", "S7", "S7", "S7", "S7", "S7", "Travelfusion", "Travelfusion", 
"Travelfusion"), date = c("28.03.2021", "28.03.2021", "28.03.2021", 
"28.03.2021", "25.03.2021", "25.03.2021", "25.03.2021", "25.03.2021", 
"25.03.2021", "28.03.2021", "28.03.2021", "28.03.2021"), hour = c(3L, 
4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 4L, 5L, 6L), weekday = c(0L, 
0L, 0L, 0L, 4L, 4L, 4L, 4L, 4L, 0L, 0L, 0L), base_price = c(1944.7, 
1949.43, 1954.16, 1958.89, 4595.2, 3170.02, 1744.84, 319.65, 
-1105.53, 3.83, 3.49, 3.15)), class = "data.frame", row.names = c(NA, 
-12L))

Cómo para cada categoría de variable de proveedor, sumar 100.000 al valor más reciente de cada categoría. Por ejemplo, el último valor de la categoría S7 = -1105,53. Entonces -1105,53+100 000=98894,47 Entonces 98894,47 debe pegarse como último valor. Pero al último valor de la categoría Travelfusion se le debe agregar el valor 200 000. Resultado tan deseado

       supplier       date hour weekday base_price
1       MyAgent 28.03.2021    3       0    1944.70
2       MyAgent 28.03.2021    4       0    1949.43
3       MyAgent 28.03.2021    5       0    1954.16
4       MyAgent 28.03.2021    6       0  101958.89
5            S7 25.03.2021    7       4    4595.20
6            S7 25.03.2021    8       4    3170.02
7            S7 25.03.2021    9       4    1744.84
8            S7 25.03.2021   10       4     319.65
9            S7 25.03.2021   11       4   98894.47
10 Travelfusion 28.03.2021    4       0       3.83
11 Travelfusion 28.03.2021    5       0       3.49
12 Travelfusion 28.03.2021    6       0  200003.15

¿Cómo hacerlo?



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

Podríamos hacer esto fácilmente en base R. Cree dos vectores lógicos: 1) que devuelva VERDADERO para el último elemento de cada 'proveedor' (i1), 2) donde el proveedor es 'Travelfusion'. Utilice ese índice para reemplazar la columna 'base_price' value

i1 <- !duplicated(mydat$supplier, fromLast = TRUE)
i2 <- mydat$supplier == 'Travelfusion'
mydat$base_price[i1 & i2] <- mydat$base_price[i1 & i2] + 200000
mydat$base_price[i1 & !i2] <- mydat$base_price[i1 & !i2] + 100000

-salida

mydat
#       supplier       date hour weekday base_price
#1       MyAgent 28.03.2021    3       0    1944.70
#2       MyAgent 28.03.2021    4       0    1949.43
#3       MyAgent 28.03.2021    5       0    1954.16
#4       MyAgent 28.03.2021    6       0  101958.89
#5            S7 25.03.2021    7       4    4595.20
#6            S7 25.03.2021    8       4    3170.02
#7            S7 25.03.2021    9       4    1744.84
#8            S7 25.03.2021   10       4     319.65
#9            S7 25.03.2021   11       4   98894.47
#10 Travelfusion 28.03.2021    4       0       3.83
#11 Travelfusion 28.03.2021    5       0       3.49
#12 Travelfusion 28.03.2021    6       0  200003.15

O usar la misma lógica en dplyr

library(dplyr)
mydat %>%
   mutate(i1 =!duplicated(supplier, fromLast = TRUE),
       i2 = supplier == 'Travelfusion',
       base_price = case_when(i1 & i2 ~ base_price + 200000,
        i1 & !i2 ~ base_price + 100000, TRUE ~ base_price),
      i1 = NULL, i2 = NULL)



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

Una solución es crear una columna de fecha y hora usando lubridate y luego agregar valores hasta el máximo de eso.

library(lubridate)
library(dplyr)
values <- c(100000,100000,200000)

## create datetime column with lubridate
mydat <- mydat %>% as_tibble  %>% 
    mutate(date = dmy(date),
                 hour = hm(paste0(hour,":00")),
                datetime = ymd_hms(paste(date, hour)))

## get the last datetime for each supplier and add values
to_bind <- mydat %>% group_by(supplier) %>% 
    slice_max(datetime) %>% 
    ungroup() %>% 
    mutate(added = values,
                 base_price = base_price + added) %>% 
    select(-added)

## bind_rows with new values 
mydat %>% group_by(supplier) %>% 
    filter(datetime !=max(datetime)) %>% 
    bind_rows(to_bind) %>% 
    arrange(supplier, datetime) 



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

Puedes agregar una nueva columna en los datos para agregar el valor y usarlo con reemplazar:

library(dplyr)

value_to_add <- c(100000,100000, 200000)

mydat %>%
  mutate(value_to_add = value_to_add[match(supplier, unique(supplier))]) %>%
  group_by(supplier) %>%
  mutate(base_price = replace(base_price, n(), last(base_price) + last(value_to_add))) %>%
  ungroup %>%
  select(-value_to_add)

# A tibble: 12 x 5
#   supplier     date        hour weekday base_price
#   <chr>        <chr>      <int>   <int>      <dbl>
# 1 MyAgent      28.03.2021     3       0    1945.  
# 2 MyAgent      28.03.2021     4       0    1949.  
# 3 MyAgent      28.03.2021     5       0    1954.  
# 4 MyAgent      28.03.2021     6       0  101959.  
# 5 S7           25.03.2021     7       4    4595.  
# 6 S7           25.03.2021     8       4    3170.  
# 7 S7           25.03.2021     9       4    1745.  
# 8 S7           25.03.2021    10       4     320.  
# 9 S7           25.03.2021    11       4   98894.  
#10 Travelfusion 28.03.2021     4       0       3.83
#11 Travelfusion 28.03.2021     5       0       3.49
#12 Travelfusion 28.03.2021     6       0  200003.  



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

Podemos usar split() y Map()

do.call(rbind,
Map(function(add, dat){
  # subset variable to add to 
  tmp1 <- dat[, "base_price"]
  
  # add desired amount
  dat[, "base_price"][nrow(dat)] <- tmp1[nrow(dat)] + add

  # return
  dat
},
# here you can choose the number that is added for each supplier
c(1e5, 1e5, 2e5),  
split(mydat, mydat[, "supplier"])))

# yields

#        supplier       date hour weekday base_price
# 1       MyAgent 28.03.2021    3       0    1944.70
# 2       MyAgent 28.03.2021    4       0    1949.43
# 3       MyAgent 28.03.2021    5       0    1954.16
# 4       MyAgent 28.03.2021    6       0  101958.89
# 5            S7 25.03.2021    7       4    4595.20
# 6            S7 25.03.2021    8       4    3170.02
# 7            S7 25.03.2021    9       4    1744.84
# 8            S7 25.03.2021   10       4     319.65
# 9            S7 25.03.2021   11       4   98894.47
# 10 Travelfusion 28.03.2021    4       0       3.83
# 11 Travelfusion 28.03.2021    5       0       3.49
# 12 Travelfusion 28.03.2021    6       0  200003.15

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