Durante las discusiones, surgió una "pequeña" tarea: construir la dinámica de la estructura de la cartera de préstamos (dinámica de una tarjeta de crédito, por ejemplo). Hay una especificidad importante: es necesario aplicar el método FIFO para reembolsar préstamos. Esos. al reembolsar, los primeros préstamos deben reembolsarse primero. Esto impone ciertos requisitos para calcular el estado de cada préstamo individual y determinar su fecha de vencimiento.
Considérelo como un problema de Olimpiada. Sin " premios de energía sangrientos " y pedaleo de código, el enfoque es exclusivamente " pensar primero ". No más de una pantalla de código por prototipo y sin bucles (integrado para mejorar el rendimiento y la legibilidad). A continuación se muestra el código R con un enfoque de prototipo.
Es una continuación de una serie de publicaciones anteriores .
Descomposición
Como hacemos todo desde cero, dividimos la tarea en tres pasos:
- Formación de datos de prueba.
- Cálculo de la fecha de vencimiento de cada préstamo.
- Cálculo y visualización de dinámicas para una ventana de tiempo determinada.
Supuestos y disposiciones para el prototipo:
- Granularidad actualizada. Solo una transacción en una fecha. Si hay varias transacciones en un día, será necesario establecer su orden (para cumplir con el principio FIFO). Puede usar add. índices, puede usar unixtimestamp, puede pensar en algo más. Esto es irrelevante para el prototipo.
- No
for
debería haber ningún bucle explícito . No debe haber copias innecesarias. Céntrese en el consumo mínimo de memoria y el máximo rendimiento. - Consideraremos los siguientes grupos de retrasos: "<0", "0-30", "31-60", "61-90", "90+".
Paso 1. Generar el conjunto de datos
Solo un conjunto de datos de prueba, todas las coincidencias son aleatorias. Para cada usuario, generaremos ~ 10 registros. Para los cálculos, asumimos que el préstamo es un valor positivo, el reembolso es negativo. Y el ciclo de vida completo de cada usuario debe comenzar con un préstamo.
library(tidyverse)
library(lubridate)
library(magrittr)
library(tictoc)
library(data.table)
total_users <- 100
events_dt <- tibble(
date = sample(
seq.Date(as.Date("2021-01-01"), as.Date("2021-04-30"), by = "1 day"),
total_users * 10,
replace = TRUE)
) %>%
# 50 .
mutate(amount = (runif(n(), -2000, 1000)) %/% 50 * 50) %>%
#
mutate(user_id = sample(!!total_users, n(), replace = TRUE)) %>%
setDT(key = "date") %>%
#
.[.[, .I[1L], by = user_id]$V1, amount := abs(amount)] %>%
# ,
#
#
unique(by = c("user_id", "date"))
Paso 2. Calcule la fecha de vencimiento de cada préstamo.
data.table
le permite cambiar objetos por referencia incluso dentro de funciones, lo usaremos activamente.
#
accu_dt <- events_dt[amount < 0, .(accu = cumsum(amount), date), by = user_id]
ff <- function(dt){
#
#
accu_dt[dt, amount := i.amount, on = "user_id"]
accu_dt[is.na(amount) == FALSE, accu := accu + amount][accu > 0, accu := NA, by = user_id]
calc_dt <- accu_dt[!is.na(accu), head(date, 1), by = user_id]
# data.frame,
calc_dt[dt, on = "user_id"]$V1
}
repay_dt <- events_dt[amount > 0] %>%
.[, repayment_date := ff(.SD), by = date] %>%
.[order(user_id, date)]
Paso 3. Cálculo de la dinámica de la estructura para el período.
calcDebt <- function(report_date){
as_tibble(repay_dt) %>%
# ,
filter(is.na(repayment_date) | repayment_date > !! report_date) %>%
mutate(delay = as.numeric(!!report_date - date)) %>%
#
mutate(tag = santoku::chop(delay, breaks = c(0, 31, 61, 90),
labels = c("< 0", "0-30", "31-60", "61-90", "90+"),
extend = TRUE, drop = FALSE)) %>%
#
group_by(tag) %>%
summarise(amount = sum(amount)) %>%
mutate_at("tag", as.character)
}
#
df <- seq.Date(as.Date("2021-04-01"), as.Date("2021-04-30"), by = "1 day") %>%
tibble(date = ., tbl = purrr::map(., calcDebt)) %>%
unnest(tbl)
#
ggplot(df, aes(date, amount, colour = tag)) +
geom_point(alpha = 0.5, size = 3) +
geom_line() +
ggthemes::scale_colour_tableau("Tableau 10") +
theme_minimal()
Podemos conseguir algo como esto.
Una pantalla de código, según sea necesario.
Entrada anterior - "Informe Storytelling R vs. BI, un enfoque pragmático" .