DOC_VER
min/max ;Trois niveaux sont utilisés :
df_gen : grain = instanceid + doc_verdf_item : grain =
instanceid + key_itm_nbr + doc_verdf_tax : grain physique exploité =
instanceid + key_itm_nbr + doc_ver + tax_lin_codRègle absolue : on conserve doc_ver
pendant les agrégations, puis on compare DOC_VER_MIN et
DOC_VER_MAX.
| Terme | Définition |
|---|---|
| Déclaration | niveau instanceid + doc_ver |
| Article | niveau instanceid + key_itm_nbr + doc_ver |
| Taxe agrégée article | niveau instanceid + key_itm_nbr + doc_ver, après
agrégation préalable par tax_lin_cod |
| Version initiale | DOC_VER_MIN |
| Version finale | DOC_VER_MAX |
| DELTA_TAX | TAX_FIN - TAX_INI |
| Variation fiscale absolue | abs(DELTA_TAX) |
| Workflow normal | déclaration avec mainlevée atteinte et stabilité HS / VIT / tax |
| Signal | cas à examiner |
| owner | code déclarant (à rapprocher de dec_cod) — distinct de
end_user |
| exa_exa | vérificateur (No examiner si valeur manquante, vide ou
égale à None) |
| end_user | acteur technique réel de l’opération, non analysé dans cet atelier |
Rappels :
DOC_VER_MIN et DOC_VER_MAX ;tax_lin_cod, en conservant doc_ver.setwd('C:/Users/PC/Desktop/Formation Douanes/ML APPRENTISSAGE/ATELIER SAD HIS/anonymised')
data_dir <- "C:/Users/PC/Desktop/Formation Douanes/ML APPRENTISSAGE/ATELIER SAD HIS/anonymised"
cols_gen <- c(
"instanceid", "doc_ver", "ide_reg_dat","ide_ast_dat","ide_rcp_dat", "op_date_time", "status", "op_name",
"cmp_con_cod", "cmp_exp_cod", "cmp_fis_cod", "ide_cuo_cod", "ide_cuo_nam",
"owner", "ied_id", "exa_exa"
)
cols_item <- c(
"instanceid", "key_itm_nbr", "doc_ver",
"tar_hsc_nb1", "tar_hsc_nb2", "vit_stv", "vit_cif",
"gds_org_cty", "tar_prf"
)
cols_tax <- c(
"instanceid", "key_itm_nbr", "doc_ver",
"tax_lin_cod", "tax_lin_bse", "tax_lin_rat", "tax_lin_amt"
)
df_gen <- read_parquet(
file.path(data_dir, "sad_general_his_anon.parquet"),
col_select = all_of(cols_gen)
) %>% as.data.frame()
df_item <- read_parquet(
file.path(data_dir, "sad_item_his_anon.parquet"),
col_select = all_of(cols_item)
) %>% as.data.frame()
df_tax <- read_parquet(
file.path(data_dir, "sad_tax_his_anon.parquet"),
col_select = all_of(cols_tax)
) %>% as.data.frame()
# Filtrage sur l'année 2022 (logique métier : périmètre de l'atelier)
df_gen <- df_gen %>%
filter(year(ide_reg_dat) == 2022)
valid_instance_ids <- df_gen$instanceid
df_item <- df_item %>%
filter(instanceid %in% valid_instance_ids)
df_tax <- df_tax %>%
filter(instanceid %in% valid_instance_ids)
cat("Nombre de déclarations (general) après filtrage :", nrow(df_gen), "\n")## Nombre de déclarations (general) après filtrage : 675353
## Nombre de lignes item après filtrage : 1023156
## Nombre de lignes tax après filtrage : 4694107
df_gen <- df_gen %>%
mutate(
instanceid = as.integer(instanceid),
doc_ver = as.integer(doc_ver),
op_date_time = as.POSIXct(op_date_time),
ide_reg_dat = as.POSIXct(ide_reg_dat),
ide_ast_dat = as.POSIXct(ide_ast_dat),
ide_rcp_dat = as.POSIXct(ide_rcp_dat),
exa_exa = case_when(
is.na(exa_exa) ~ "No examiner",
trimws(as.character(exa_exa)) == "" ~ "No examiner",
toupper(trimws(as.character(exa_exa))) == "NONE" ~ "No examiner",
TRUE ~ trimws(as.character(exa_exa))
),
op_name_std = case_when(
op_name == "Print Release Order" ~ "PRINT_RELEASE_ORDER",
op_name == "Payment" ~ "PAYMENT",
op_name == "Re-route to green" ~ "RE_ROUTE_GREEN",
op_name == "Totally exit" ~ "TOTALLY_EXIT",
op_name == "Exit" ~ "EXIT",
op_name == "Exit Paid" ~ "EXIT_PAID",
op_name == "Exit Assessed Credit" ~ "EXIT_ASSESSED_CREDIT",
op_name == "Validate and assess" ~ "VALIDATE_AND_ASSESS",
op_name == "Assess Registered" ~ "ASSESS_REGISTERED",
op_name == "Assess Registered (direct)" ~ "ASSESS_REGISTERED_DIRECT",
op_name == "Assessed direct to prepaid" ~ "ASSESSED_DIRECT_TO_PREPAID",
op_name == "Assess from selected standby" ~ "ASSESS_FROM_SELECTED_STANDBY",
op_name == "Validate" ~ "VALIDATE",
op_name == "Modify Registered" ~ "MODIFY_REGISTERED",
op_name == "Post-Entry" ~ "POST_ENTRY",
op_name == "Lock" ~ "LOCK",
op_name == "Unlock" ~ "UNLOCK",
op_name == "Cancel" ~ "CANCEL",
op_name == "Refund" ~ "REFUND",
op_name == "Register T1 on SAD" ~ "REGISTER_T1_ON_SAD",
op_name == "Re-route to query" ~ "RE_ROUTE_QUERY",
op_name == "Re-route to red" ~ "RE_ROUTE_RED",
op_name == "Export release" ~ "EXPORT_RELEASE",
TRUE ~ str_to_upper(str_replace_all(op_name, "[^A-Za-z0-9]+", "_"))
),
status_std = case_when(
status %in% c("Assessed", "Assesed") ~ "ASSESSED",
status == "Paid" ~ "PAID",
status == "Registered" ~ "REGISTERED",
status == "Totally exited" ~ "TOTALLY_EXITED",
status == "Exited" ~ "EXITED",
status == "Cancelled" ~ "CANCELLED",
TRUE ~ str_to_upper(status)
)
) %>%
# Logique métier : les déclarations annulées sont exclues de toute analyse
filter(status_std != "CANCELLED")
df_item <- df_item %>%
mutate(
instanceid = as.integer(instanceid),
key_itm_nbr = as.integer(key_itm_nbr),
doc_ver = as.integer(doc_ver),
HS = paste0(coalesce(tar_hsc_nb1, ""), coalesce(tar_hsc_nb2, "")),
VIT_STV = as.numeric(vit_stv),
VIT_CIF = as.numeric(vit_cif)
)
df_tax <- df_tax %>%
mutate(
instanceid = as.integer(instanceid),
key_itm_nbr = as.integer(key_itm_nbr),
doc_ver = as.integer(doc_ver),
tax_lin_cod = as.character(tax_lin_cod),
tax_lin_bse = as.numeric(tax_lin_bse),
tax_lin_rat = as.numeric(tax_lin_rat),
tax_lin_amt = as.numeric(tax_lin_amt)
)versions <- function(df, keys, version_col = "doc_ver") {
df %>%
group_by(across(all_of(keys))) %>%
summarise(
DOC_VER_MIN = min(.data[[version_col]], na.rm = TRUE),
DOC_VER_MAX = max(.data[[version_col]], na.rm = TRUE),
nb_versions = n_distinct(.data[[version_col]]),
.groups = "drop"
)
}
first_last_by_version <- function(df, keys, keep_cols, version_col = "doc_ver") {
v <- versions(df, keys = keys, version_col = version_col)
ini <- df %>%
inner_join(v, by = keys) %>%
filter(.data[[version_col]] == DOC_VER_MIN) %>%
select(all_of(keys), all_of(keep_cols)) %>%
distinct()
fin <- df %>%
inner_join(v, by = keys) %>%
filter(.data[[version_col]] == DOC_VER_MAX) %>%
select(all_of(keys), all_of(keep_cols)) %>%
distinct()
list(versions = v, ini = ini, fin = fin)
}decl_dates <- df_gen %>%
group_by(instanceid) %>%
summarise(
date_depot = {
x <- ide_reg_dat[!is.na(ide_reg_dat)]
if (length(x) == 0) as.POSIXct(NA) else min(x)
},
date_bae = {
x <- op_date_time[op_name_std == "PRINT_RELEASE_ORDER" & !is.na(op_date_time)]
if (length(x) == 0) as.POSIXct(NA) else min(x)
},
date_payment = {
x <- ide_rcp_dat[!is.na(ide_rcp_dat)]
if (length(x) == 0) as.POSIXct(NA) else min(x)
},
op_last = {
x <- op_date_time[!is.na(op_date_time)]
if (length(x) == 0) as.POSIXct(NA) else max(x)
},
.groups = "drop"
)
decl_workflow <- versions(df_gen, keys = c("instanceid")) %>%
left_join(decl_dates, by = "instanceid") %>%
mutate(
mainlevee = !is.na(date_bae),
delay_depot_bae_min = as.numeric(difftime(date_bae, date_depot, units = "mins")),
delay_pay_bae_days = as.numeric(difftime(date_bae, date_payment, units = "days"))
)
workflow_ops <- df_gen %>%
count(op_name_std, sort = TRUE, name = "nb_operations")
rupture_ops <- workflow_ops %>%
filter(op_name_std %in% c(
"MODIFY_REGISTERED", "POST_ENTRY", "RE_ROUTE_QUERY", "RE_ROUTE_RED",
"LOCK", "UNLOCK", "CANCEL"
))
workflow_ops## op_name_std nb_operations
## 1 PAYMENT 131331
## 2 VALIDATE_AND_ASSESS 130026
## 3 RE_ROUTE_GREEN 109339
## 4 ASSESS_FROM_SELECTED_STANDBY 98577
## 5 PRINT_RELEASE_ORDER 93635
## 6 TOTALLY_EXIT 73780
## 7 REGISTER_T1_ON_SAD 32476
## 8 POST_ENTRY 2799
## 9 MODIFY_REGISTERED 1331
## 10 UNLOCK 929
## 11 VIEW_CRITERIA 472
## 12 EXIT 367
## 13 LOCK 140
## 14 EXIT_PAID 23
## 15 ASSESS_REGISTERED 19
## 16 EXIT_ASSESSED_CREDIT 18
## 17 RE_ROUTE_QUERY 9
## 18 REFUND 5
## 19 ASSESSED_DIRECT_TO_PREPAID 1
## 20 VALIDATE 1
## op_name_std nb_operations
## 1 POST_ENTRY 2799
## 2 MODIFY_REGISTERED 1331
## 3 UNLOCK 929
## 4 LOCK 140
## 5 RE_ROUTE_QUERY 9
TODO étudiant :
- Expliquer pourquoi le workflow se calcule au grain déclaration et non au grain article.
- Parmi les opérations observées dans
rupture_ops, lesquelles signalent une rupture de parcours ? Donner leur volume respectif et commenter l’absence éventuelle de certaines opérations attendues.
item_fl <- first_last_by_version(
df_item,
keys = c("instanceid", "key_itm_nbr"),
keep_cols = c("HS", "VIT_STV", "VIT_CIF", "gds_org_cty", "tar_prf")
)
item_compare <- item_fl$versions %>%
left_join(
item_fl$ini %>%
rename(HS_ini = HS, VIT_STV_ini = VIT_STV, VIT_CIF_ini = VIT_CIF,
ORG_ini = gds_org_cty, PRF_ini = tar_prf),
by = c("instanceid", "key_itm_nbr")
) %>%
left_join(
item_fl$fin %>%
rename(HS_fin = HS, VIT_STV_fin = VIT_STV, VIT_CIF_fin = VIT_CIF,
ORG_fin = gds_org_cty, PRF_fin = tar_prf),
by = c("instanceid", "key_itm_nbr")
) %>%
mutate(
chg_hs = coalesce(HS_ini, "") != coalesce(HS_fin, ""),
chg_org = coalesce(ORG_ini, "") != coalesce(ORG_fin, ""),
chg_prf = coalesce(PRF_ini, "") != coalesce(PRF_fin, ""),
d_vit_stv = VIT_STV_fin - VIT_STV_ini,
d_vit_cif = VIT_CIF_fin - VIT_CIF_ini
)
item_presence <- item_fl$versions %>%
left_join(
item_fl$ini %>% transmute(instanceid, key_itm_nbr, in_ini = TRUE),
by = c("instanceid", "key_itm_nbr")
) %>%
left_join(
item_fl$fin %>% transmute(instanceid, key_itm_nbr, in_fin = TRUE),
by = c("instanceid", "key_itm_nbr")
) %>%
mutate(
in_ini = coalesce(in_ini, FALSE),
in_fin = coalesce(in_fin, FALSE),
item_status = case_when(
in_ini & in_fin ~ "PRESENT_DANS_LES_2",
in_ini & !in_fin ~ "DISPARU_EN_FINAL",
!in_ini & in_fin ~ "APPARU_EN_FINAL",
TRUE ~ "AUTRE"
)
)
item_presence_summary <- item_presence %>%
count(item_status, name = "nb_items")
hs_change_vit_stable <- item_compare %>%
filter(
chg_hs == TRUE,
coalesce(d_vit_stv, 0) == 0,
coalesce(d_vit_cif, 0) == 0
) %>%
select(instanceid, key_itm_nbr, HS_ini, HS_fin,
VIT_STV_ini, VIT_STV_fin, VIT_CIF_ini, VIT_CIF_fin)
item_presence_summary## # A tibble: 1 × 2
## item_status nb_items
## <chr> <int>
## 1 PRESENT_DANS_LES_2 195898
## # A tibble: 0 × 8
## # ℹ 8 variables: instanceid <int>, key_itm_nbr <int>, HS_ini <chr>,
## # HS_fin <chr>, VIT_STV_ini <dbl>, VIT_STV_fin <dbl>, VIT_CIF_ini <dbl>,
## # VIT_CIF_fin <dbl>
TODO étudiant :
- Interpréter les catégories de
item_presence_summary: que signifientAPPARU_EN_FINAL,DISPARU_EN_FINAL,PRESENT_DANS_LES_2? Que conclure si certaines catégories sont absentes du résultat ?- Le tableau
hs_change_vit_stableest-il vide ou non ? Que faut-il en conclure méthodologiquement — peut-on affirmer l’absence de tels cas ou l’absence de résultat est-elle contextuelle ?
tax_item_ver_code <- df_tax %>%
group_by(instanceid, key_itm_nbr, doc_ver, tax_lin_cod) %>%
summarise(
tax_lin_bse = sum(tax_lin_bse, na.rm = TRUE),
tax_lin_amt = sum(tax_lin_amt, na.rm = TRUE),
tax_lin_rat = max(tax_lin_rat, na.rm = TRUE),
.groups = "drop"
)
tax_item_ver <- tax_item_ver_code %>%
group_by(instanceid, key_itm_nbr, doc_ver) %>%
summarise(
TAX = sum(tax_lin_amt, na.rm = TRUE),
n_tax_codes = n_distinct(tax_lin_cod),
tax_codes = paste(sort(unique(tax_lin_cod)), collapse = "|"),
.groups = "drop"
)
rm(df_tax)
gc()## used (Mb) gc trigger (Mb) max used (Mb)
## Ncells 1808135 96.6 22541472 1203.9 35221048 1881.1
## Vcells 61176328 466.8 198378950 1513.6 169334386 1292.0
tax_fl <- first_last_by_version(
tax_item_ver,
keys = c("instanceid", "key_itm_nbr"),
keep_cols = c("TAX", "n_tax_codes", "tax_codes")
)
item_tax_compare <- tax_fl$versions %>%
left_join(
tax_fl$ini %>%
rename(TAX_INI = TAX, N_TAX_INI = n_tax_codes, TAX_CODES_INI = tax_codes),
by = c("instanceid", "key_itm_nbr")
) %>%
left_join(
tax_fl$fin %>%
rename(TAX_FIN = TAX, N_TAX_FIN = n_tax_codes, TAX_CODES_FIN = tax_codes),
by = c("instanceid", "key_itm_nbr")
) %>%
mutate(
DELTA_TAX = TAX_FIN - TAX_INI,
ABS_DELTA_TAX = abs(DELTA_TAX),
chg_tax_codes = coalesce(TAX_CODES_INI, "") != coalesce(TAX_CODES_FIN, "")
)
delta_tax_hs_stable <- item_compare %>%
left_join(
item_tax_compare,
by = c("instanceid", "key_itm_nbr", "DOC_VER_MIN", "DOC_VER_MAX", "nb_versions")
) %>%
filter(chg_hs == FALSE, coalesce(ABS_DELTA_TAX, 0) > 0) %>%
select(instanceid, key_itm_nbr, HS_ini, HS_fin, TAX_INI, TAX_FIN, DELTA_TAX, ABS_DELTA_TAX)
tax_code_changes <- item_tax_compare %>%
filter(chg_tax_codes == TRUE) %>%
select(instanceid, key_itm_nbr, TAX_CODES_INI, TAX_CODES_FIN, TAX_INI, TAX_FIN, DELTA_TAX)
head(delta_tax_hs_stable, 20)## # A tibble: 20 × 8
## instanceid key_itm_nbr HS_ini HS_fin TAX_INI TAX_FIN DELTA_TAX ABS_DELTA_TAX
## <int> <int> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 2682538 1 392390… 39239… 1.85e5 2.80e5 95207. 95207.
## 2 2682752 1 390290… 39029… 9.76e5 1.28e6 299224. 299224.
## 3 2682875 1 340249… 34024… 1.76e6 2.47e6 709008. 709008.
## 4 2682956 1 851640… 85164… 2.87e5 5.41e5 253394. 253394.
## 5 2682956 2 851610… 85161… 2.48e5 5.13e5 265101. 265101.
## 6 2682956 3 851660… 85166… 4.63e5 7.31e5 268346. 268346.
## 7 2682956 6 841840… 84184… 3.71e6 3.97e6 261924. 261924.
## 8 2682969 3 854449… 85444… 6.21e5 8.81e5 260661. 260661.
## 9 2684539 1 040221… 04022… 9.45e6 1.50e7 5512386. 5512386.
## 10 2684605 1 040221… 04022… 1.10e7 1.55e7 4547719. 4547719.
## 11 2684615 1 870422… 87042… 5.94e5 5.32e5 -61221. 61221.
## 12 2684630 1 870210… 87021… 2.68e5 4.28e5 160583. 160583.
## 13 2684903 1 870422… 87042… 5.18e5 6.17e5 99277. 99277.
## 14 2685034 1 870421… 87042… 4.03e5 3.39e5 -64882. 64882.
## 15 2685195 1 550810… 55081… 2.91e6 5.88e6 2968668. 2968668.
## 16 2685502 1 870421… 87042… 3.39e5 4.03e5 64882. 64882.
## 17 2685679 1 391890… 39189… 4.13e6 5.43e6 1303399. 1303399.
## 18 2685742 1 391890… 39189… 4.13e6 5.43e6 1303666. 1303666.
## 19 2686135 1 200899… 20089… 1.71e5 3.21e5 150068. 150068.
## 20 2686135 2 640220… 64022… 1.14e5 1.10e5 -4356. 4356.
## # A tibble: 20 × 7
## instanceid key_itm_nbr TAX_CODES_INI TAX_CODES_FIN TAX_INI TAX_FIN DELTA_TAX
## <int> <int> <chr> <chr> <dbl> <dbl> <dbl>
## 1 2684615 1 DD|ISB|PC|PCS… DD|PC|PCS|PU… 5.94e5 5.32e5 -61221.
## 2 2684903 1 DD|PC|PCS|PUA… DD|ISB|PC|PC… 5.18e5 6.17e5 99277.
## 3 2685034 1 DD|ISB|PC|PCS… DD|PC|PCS|PU… 4.03e5 3.39e5 -64882.
## 4 2685502 1 DD|PC|PCS|PUA… DD|ISB|PC|PC… 3.39e5 4.03e5 64882.
## 5 2686798 1 DD|PC|PCS|PUA… ADA|DD|PC|PC… 2.44e6 3.04e6 601128.
## 6 2687817 1 DD|PC|PCS|PUA… DD|ISB|PC|PC… 4.06e5 4.84e5 77857.
## 7 2688654 1 ADA|DD|PC|PCS… DD|PC|PCS|PU… 1.58e6 1.27e6 -312097.
## 8 2688925 1 DD|ISB|PC|PCS… DD|PC|PCS|PU… 1.01e5 2.82e5 181221.
## 9 2691103 1 DD|PC|PCS|PUA… ADA|DD|PC|PC… 4.42e5 5.51e5 108846.
## 10 2691916 1 DD|ISB|PC|PCS… DD|PC|PCS|PU… 1.00e6 8.85e5 -117178.
## 11 2692785 1 DD|ISB|PC|PCS… DD|PC|PCS|PU… 2.01e6 3.59e5 -1648451.
## 12 2692787 1 DD|ISB|PC|PCS… DD|PC|PCS|PU… 2.27e6 6.25e5 -1648632.
## 13 2693156 1 TSR ISB|TSR 2.47e4 3.46e4 9895.
## 14 2695188 1 DD|PC|PCS|RSI… DD|ISB|PC|PC… 6.45e5 6.45e5 129.
## 15 2696851 1 ADA|DD|PC|PCS… DD|PC|PCS|PU… 6.49e5 3.90e5 -258366.
## 16 2697032 1 TVA DD|RSI|TVA|T… 5.59e5 1.32e6 764346.
## 17 2697053 1 PCS|TVA|TVI DD|PCS|RSI|T… 9.58e5 2.10e6 1143171.
## 18 2697069 1 PCS|TVA|TVI DD|PCS|RSI|T… 9.58e5 2.10e6 1143171.
## 19 2697081 1 PCS|TVA|TVI DD|PCS|RSI|T… 9.58e5 2.10e6 1143171.
## 20 2697119 1 DD|ISB|PCS|PI… DD|PCS|RSI|T… 2.52e5 2.95e4 -222214.
TODO étudiant :
- Expliquer pourquoi l’agrégation par
tax_lin_codest réalisée avant la comparaison initiale/finale. Que se passerait-il si on comparait directement les lignes brutes dedf_tax?- Que signifie un
DELTA_TAXnon nul pour un article dont leHSn’a pas changé ? Donner 2 exemples de causes possibles.- Que révèle un changement de
tax_codes(ex. apparition ou disparition du codeISBouADA) entre version initiale et finale ?
header_ref <- df_gen %>%
group_by(instanceid) %>%
arrange(doc_ver, op_date_time, .by_group = TRUE) %>%
slice_tail(n = 1) %>%
ungroup() %>%
select(instanceid, cmp_con_cod, cmp_exp_cod, cmp_fis_cod,
ide_cuo_cod, ide_cuo_nam, owner, exa_exa)
item_compare_full <- item_compare %>%
left_join(
item_tax_compare %>%
select(instanceid, key_itm_nbr, TAX_INI, TAX_FIN, DELTA_TAX, ABS_DELTA_TAX, chg_tax_codes),
by = c("instanceid", "key_itm_nbr")
) %>%
left_join(header_ref, by = "instanceid") %>%
mutate(
FLAG_BAISSE_TAX = DELTA_TAX < 0,
SENS_DELTA_TAX = case_when(
DELTA_TAX < 0 ~ "BAISSE_TAX",
DELTA_TAX > 0 ~ "HAUSSE_TAX",
TRUE ~ "STABLE"
)
)TODO étudiant :
- Pourquoi
item_compare_fullest-elle construite au grain article et non au grain déclaration ? Quels types de jointures permettent de l’enrichir avec les informations d’en-tête (header_ref) ?- Pourquoi
header_refest-il construit en prenant la dernière ligne parinstanceid(tri pardoc_ver+op_date_time,slice_tail) plutôt que n’importe quelle ligne ?
decl_stability <- item_compare_full %>%
group_by(instanceid) %>%
summarise(
hs_stable_decl = all(!chg_hs, na.rm = TRUE),
vit_stable_decl = all(coalesce(d_vit_stv, 0) == 0, na.rm = TRUE),
tax_stable_decl = all(coalesce(DELTA_TAX, 0) == 0, na.rm = TRUE),
stable_decl = hs_stable_decl & vit_stable_decl & tax_stable_decl,
.groups = "drop"
)
workflow_ref <- decl_workflow %>%
left_join(decl_stability, by = "instanceid") %>%
filter(mainlevee == TRUE, stable_decl == TRUE)
Q95_workflow <- workflow_ref %>%
summarise(Q95 = quantile(nb_versions, 0.95, na.rm = TRUE)) %>%
pull(Q95)
decl_workflow <- decl_workflow %>%
left_join(decl_stability, by = "instanceid") %>%
mutate(cascade = nb_versions > Q95_workflow)
Q95_workflow## 95%
## 7
TODO étudiant :
- Le workflow normal est défini par 4 conditions cumulatives. Expliquer le rôle de chacune (
mainlevee,hs_stable,vit_stable,tax_stable) et justifier pourquoi elles doivent être vérifiées ensemble.- Quelle est la valeur de
Q95_workflowobtenue ? Interpréter ce seuil : qu’est-ce qu’il représente pour la population de référence ?- Pourquoi utilise-t-on le P95 plutôt que, par exemple, la moyenne ou le P99 comme seuil de détection des cascades ?
normal_tax <- item_compare_full %>%
inner_join(workflow_ref %>% select(instanceid), by = "instanceid") %>%
filter(chg_hs == FALSE)
tax_threshold <- normal_tax %>%
summarise(
N_REF = n(),
P90_TAX = quantile(ABS_DELTA_TAX, 0.90, na.rm = TRUE),
P95_TAX = quantile(ABS_DELTA_TAX, 0.95, na.rm = TRUE),
P99_TAX = quantile(ABS_DELTA_TAX, 0.99, na.rm = TRUE)
)
eps_tax <- tax_threshold$P95_TAX[[1]]
tax_threshold## # A tibble: 1 × 4
## N_REF P90_TAX P95_TAX P99_TAX
## <int> <dbl> <dbl> <dbl>
## 1 131179 0 0 0
## eps_tax retenu (P95) = 0
item_tax_flag <- item_compare_full %>%
mutate(
FLAG_ATYPIQUE_TAX = ABS_DELTA_TAX > eps_tax,
FLAG_BAISSE_TAX = DELTA_TAX < 0,
SENS_DELTA_TAX = case_when(
DELTA_TAX < 0 ~ "BAISSE_TAX",
DELTA_TAX > 0 ~ "HAUSSE_TAX",
TRUE ~ "STABLE"
)
) %>%
select(instanceid, key_itm_nbr, HS_ini, HS_fin, TAX_INI, TAX_FIN,
DELTA_TAX, ABS_DELTA_TAX, SENS_DELTA_TAX, FLAG_BAISSE_TAX, FLAG_ATYPIQUE_TAX)
head(item_tax_flag, 20)## # A tibble: 20 × 11
## instanceid key_itm_nbr HS_ini HS_fin TAX_INI TAX_FIN DELTA_TAX ABS_DELTA_TAX
## <int> <int> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 2682290 1 870322… 87032… 3.90e5 3.90e5 0 0
## 2 2682293 1 870322… 87032… 3.90e5 3.90e5 0 0
## 3 2682296 1 190219… 19021… 2.59e5 2.59e5 0 0
## 4 2682296 2 110100… 11010… 4.42e5 4.42e5 0 0
## 5 2682296 3 170199… 17019… 2.07e5 2.07e5 0 0
## 6 2682298 1 190219… 19021… 2.62e5 2.62e5 0 0
## 7 2682298 2 110100… 11010… 4.47e5 4.47e5 0 0
## 8 2682298 3 080410… 08041… 3.65e4 3.65e4 0 0
## 9 2682298 4 200990… 20099… 1.19e5 1.19e5 0 0
## 10 2682298 5 040221… 04022… 6.39e4 6.39e4 0 0
## 11 2682301 1 870899… 87089… NA NA NA NA
## 12 2682304 1 870322… 87032… 3.59e5 3.59e5 0 0
## 13 2682305 1 330499… 33049… 1.91e5 1.91e5 0 0
## 14 2682305 2 690740… 69074… 6.50e4 6.50e4 0 0
## 15 2682305 3 841381… 84138… 1.35e5 1.35e5 0 0
## 16 2682305 4 401110… 40111… 6.30e4 6.30e4 0 0
## 17 2682306 1 100620… 10062… 2.07e6 2.07e6 0 0
## 18 2682307 1 100620… 10062… 1.72e6 1.72e6 0 0
## 19 2682308 1 870322… 87032… 3.34e4 3.34e4 0 0
## 20 2682309 1 902789… 90278… 0 0 0 0
## # ℹ 3 more variables: SENS_DELTA_TAX <chr>, FLAG_BAISSE_TAX <lgl>,
## # FLAG_ATYPIQUE_TAX <lgl>
TODO étudiant :
- Sur quelle population de référence est calculé
eps_tax? Pourquoi est-il important de se restreindre aux articles en workflow normal avecchg_hs == FALSE?- La valeur obtenue pour
eps_taxest-elle attendue ? Sieps_tax = 0, que cela implique-t-il pour la conditionFLAG_ATYPIQUE_TAX = ABS_DELTA_TAX > eps_tax? Comment faut-il lire le scoring de risque dans ce cas ?- Comparer P90, P95 et P99 : quel seuil choisiriez-vous pour le ciblage opérationnel et pourquoi ?
item_compare_full <- item_compare_full %>%
mutate(
risk_level = case_when(
chg_hs & ABS_DELTA_TAX > eps_tax ~ "FORT",
!chg_hs & ABS_DELTA_TAX > eps_tax ~ "FORT",
chg_hs & ABS_DELTA_TAX == 0 ~ "MOYEN",
chg_hs & ABS_DELTA_TAX > 0 & ABS_DELTA_TAX <= eps_tax ~ "MOYEN",
(chg_org | chg_prf) & ABS_DELTA_TAX <= eps_tax ~ "MOYEN",
ABS_DELTA_TAX == 0 & !chg_hs & !chg_org & !chg_prf &
abs(coalesce(d_vit_stv, 0)) == 0 & abs(coalesce(d_vit_cif, 0)) == 0 ~ "AUCUN",
TRUE ~ "FAIBLE"
)
)
org_prf_cases <- item_compare_full %>%
filter(chg_org | chg_prf) %>%
count(chg_org, chg_prf, risk_level, sort = TRUE, name = "nb_items")
risk_distribution <- item_compare_full %>%
count(risk_level, sort = TRUE, name = "nb_items") %>%
mutate(part = nb_items / sum(nb_items))
org_prf_cases## # A tibble: 5 × 4
## chg_org chg_prf risk_level nb_items
## <lgl> <lgl> <chr> <int>
## 1 TRUE FALSE FORT 33
## 2 TRUE FALSE MOYEN 29
## 3 TRUE FALSE FAIBLE 15
## 4 FALSE TRUE FORT 8
## 5 TRUE TRUE FORT 1
## # A tibble: 4 × 3
## risk_level nb_items part
## <chr> <int> <dbl>
## 1 AUCUN 149868 0.765
## 2 FAIBLE 44628 0.228
## 3 FORT 1265 0.00646
## 4 MOYEN 137 0.000699
TODO étudiant :
- Décrire la logique de la matrice de risque : pourquoi un article avec
!chg_hsmaisABS_DELTA_TAX > eps_taxest-il classé FORT et non FAIBLE ?- Pourquoi les changements d’ORG ou PRF sans impact fiscal sont-ils classés MOYEN et non FAIBLE ?
- Commenter la distribution observée dans
risk_distribution. Est-elle cohérente avec la nature du système douanier analysé ?- Si
eps_tax = 0, quel effet cela a-t-il sur les catégories MOYEN et AUCUN ? Comment recalibrer la règle si ce cas se présente ?
Pour chaque question : 1. produire le tableau demandé ; 2. trier du plus important au moins important ; 3. rédiger une interprétation courte en 2-3 phrases maximum.
Objectif métier : classer les importateurs selon le nombre de déclarations redressées et le montant total de redressement.
Sortie attendue : tableau avec
cmp_con_cod, nb_declarations_redressees,
montant_total_redressement.
q1 <- item_compare_full %>%
filter(risk_level == "FORT", DELTA_TAX > 0) %>%
group_by(cmp_con_cod) %>%
summarise(
nb_declarations_redressees = n_distinct(instanceid),
montant_total_redressement = sum(DELTA_TAX, na.rm = TRUE),
.groups = "drop"
) %>%
arrange(desc(montant_total_redressement), desc(nb_declarations_redressees))
q1_concentration <- q1 %>%
mutate(
part_montant = montant_total_redressement / sum(montant_total_redressement, na.rm = TRUE),
cumul_part = cumsum(part_montant)
)
head(q1, 5)## # A tibble: 5 × 3
## cmp_con_cod nb_declarations_redressees montant_total_redressement
## <chr> <int> <dbl>
## 1 COD_65739828 110 54700313.
## 2 COD_BF47887D 15 43514924.
## 3 COD_19F52A62 1 34726185.
## 4 COD_D23C1BA1 33 33677629.
## 5 COD_95C46A9C 2 25741305.
## # A tibble: 10 × 5
## cmp_con_cod nb_declarations_redressees montant_total_redresse…¹ part_montant
## <chr> <int> <dbl> <dbl>
## 1 COD_65739828 110 54700313. 0.105
## 2 COD_BF47887D 15 43514924. 0.0835
## 3 COD_19F52A62 1 34726185. 0.0666
## 4 COD_D23C1BA1 33 33677629. 0.0646
## 5 COD_95C46A9C 2 25741305. 0.0494
## 6 COD_C6B55A2A 37 21206933. 0.0407
## 7 COD_04D7E70E 33 19644107. 0.0377
## 8 COD_BA7FDA7A 2 18425042. 0.0354
## 9 COD_951EF987 6 16835605. 0.0323
## 10 COD_B994AC9D 32 16372078. 0.0314
## # ℹ abbreviated name: ¹montant_total_redressement
## # ℹ 1 more variable: cumul_part <dbl>
TODO étudiant : Interpréter les 5 premiers importateurs. Quelle est la part cumulée des 5 premiers dans le montant total de redressement ? Que révèle cette concentration sur la structure du risque fiscal ?
Objectif métier : repérer les déclarations très rapides (délai dépôt–mainlevée inférieur à 2 heures), puis préciser qui, combien et dans quels bureaux.
Sortie attendue : tableau détaillé avec
instanceid, cmp_con_cod,
ide_cuo_cod, ide_cuo_nam,
date_depot, date_bae,
delay_depot_bae_min ; synthèse par bureau.
q2_detail <- decl_workflow %>%
left_join(
header_ref %>% select(instanceid, cmp_con_cod, ide_cuo_cod, ide_cuo_nam, owner),
by = "instanceid"
) %>%
filter(!is.na(delay_depot_bae_min), delay_depot_bae_min < 120) %>%
arrange(delay_depot_bae_min) %>%
select(instanceid, cmp_con_cod, ide_cuo_cod, ide_cuo_nam, owner,
date_depot, date_bae, delay_depot_bae_min)
q2_bureau <- q2_detail %>%
group_by(ide_cuo_cod, ide_cuo_nam) %>%
summarise(nb_cas = n(), .groups = "drop") %>%
arrange(desc(nb_cas))
head(q2_detail, 20)## # A tibble: 0 × 8
## # ℹ 8 variables: instanceid <int>, cmp_con_cod <chr>, ide_cuo_cod <chr>,
## # ide_cuo_nam <chr>, owner <chr>, date_depot <dttm>, date_bae <dttm>,
## # delay_depot_bae_min <dbl>
## # A tibble: 0 × 3
## # ℹ 3 variables: ide_cuo_cod <chr>, ide_cuo_nam <chr>, nb_cas <int>
TODO étudiant :
- Le tableau
q2_detailest-il vide ? Si oui, proposer une interprétation méthodologique : est-ce dû au seuil choisi, au proxy utilisé pourdate_bae, ou à la nature réelle des données ?- Si le résultat est vide, proposer deux pistes d’amélioration du proxy ou du seuil pour rendre cette détection opérationnelle.
Objectif métier : identifier les bureaux et agents
(owner) les plus concernés.
Note : owner est utilisé ici comme code
déclarant. end_user n’est pas analysé dans cet atelier.
Sortie attendue : deux tableaux, l’un pour les opérations hors heures (avant 8h ou à partir de 18h), l’autre pour les opérations du week-end.
ops_time <- df_gen %>%
mutate(
heure = lubridate::hour(op_date_time),
jour_num = lubridate::wday(op_date_time, week_start = 1),
jour = c("Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim")[jour_num],
hors_heures = !is.na(heure) & (heure < 8 | heure >= 18),
weekend = !is.na(jour_num) & jour_num %in% c(6, 7)
)
q3_hors_heures <- ops_time %>%
filter(hors_heures) %>%
group_by(ide_cuo_cod, ide_cuo_nam, owner) %>%
summarise(nb_operations_hors_heures = n(), .groups = "drop") %>%
arrange(desc(nb_operations_hors_heures))
q3_weekend <- ops_time %>%
filter(weekend) %>%
group_by(ide_cuo_cod, ide_cuo_nam, owner) %>%
summarise(nb_operations_weekend = n(), .groups = "drop") %>%
arrange(desc(nb_operations_weekend))
head(q3_hors_heures, 20)## # A tibble: 20 × 4
## ide_cuo_cod ide_cuo_nam owner nb_operations_hors_heures
## <chr> <chr> <chr> <int>
## 1 CUO_8062B850 CUO_499564F0 COD_10189223 9978
## 2 CUO_313A6A2E CUO_CA6A5B1B COD_6CFDEE48 4961
## 3 CUO_88C4B39F CUO_7145CEDD COD_819CF064 4105
## 4 CUO_313A6A2E CUO_CA6A5B1B COD_1D44BB6E 3979
## 5 CUO_61E48A76 CUO_83E92C90 COD_DC31D3E2 3820
## 6 CUO_8062B850 CUO_499564F0 COD_F22F246E 3745
## 7 CUO_6BC153ED CUO_DFC2161D COD_6CFDEE48 3386
## 8 CUO_6BC153ED CUO_DFC2161D COD_819CF064 3286
## 9 CUO_313A6A2E CUO_CA6A5B1B COD_91A0D8A8 2808
## 10 CUO_88C4B39F CUO_7145CEDD COD_2A7D61D5 2726
## 11 CUO_08824E78 CUO_B80496FD COD_3382CCAB 2611
## 12 CUO_8062B850 CUO_499564F0 COD_29D2B98B 2529
## 13 CUO_8062B850 CUO_499564F0 COD_5F795437 2516
## 14 CUO_88C4B39F CUO_7145CEDD COD_6AE100D0 2442
## 15 CUO_313A6A2E CUO_CA6A5B1B COD_7E58B39D 2417
## 16 CUO_57FDEDA7 CUO_F674DC97 COD_9CA665A8 2352
## 17 CUO_6BC153ED CUO_DFC2161D COD_29D2B98B 2277
## 18 CUO_313A6A2E CUO_CA6A5B1B COD_347779D3 2166
## 19 CUO_E01087D7 CUO_3355DC7F COD_1D44BB6E 2147
## 20 CUO_313A6A2E CUO_CA6A5B1B COD_B51ECEFB 2111
## # A tibble: 20 × 4
## ide_cuo_cod ide_cuo_nam owner nb_operations_weekend
## <chr> <chr> <chr> <int>
## 1 CUO_8062B850 CUO_499564F0 COD_10189223 6124
## 2 CUO_61E48A76 CUO_83E92C90 COD_DC31D3E2 3896
## 3 CUO_313A6A2E CUO_CA6A5B1B COD_6CFDEE48 3413
## 4 CUO_E01087D7 CUO_3355DC7F COD_10189223 3351
## 5 CUO_E01087D7 CUO_3355DC7F COD_1D44BB6E 3055
## 6 CUO_88C4B39F CUO_7145CEDD COD_819CF064 2825
## 7 CUO_313A6A2E CUO_CA6A5B1B COD_1D44BB6E 2581
## 8 CUO_57FDEDA7 CUO_F674DC97 COD_9CA665A8 2550
## 9 CUO_250974A4 CUO_C99A3DF6 COD_5D5A6B83 2340
## 10 CUO_88C4B39F CUO_7145CEDD COD_2A7D61D5 2149
## 11 CUO_313A6A2E CUO_CA6A5B1B COD_7E58B39D 2130
## 12 CUO_D08406A2 CUO_3061FD94 COD_BA899B2D 2128
## 13 CUO_313A6A2E CUO_CA6A5B1B COD_29D2B98B 2053
## 14 CUO_6BC153ED CUO_DFC2161D COD_819CF064 1981
## 15 CUO_FA720F78 CUO_14AB4E59 COD_91A0D8A8 1961
## 16 CUO_D08406A2 CUO_3061FD94 COD_6CFDEE48 1960
## 17 CUO_313A6A2E CUO_CA6A5B1B COD_347779D3 1842
## 18 CUO_313A6A2E CUO_CA6A5B1B COD_91A0D8A8 1822
## 19 CUO_8062B850 CUO_499564F0 COD_F22F246E 1816
## 20 CUO_6BC153ED CUO_DFC2161D COD_6CFDEE48 1792
TODO étudiant : Identifier les bureaux les plus concernés par les opérations hors heures et le week-end. Un même bureau ou déclarant apparaît-il dans les deux tableaux ? Que cela suggère-t-il ? Rappeler pourquoi il s’agit d’un signal de process et non d’une conclusion individuelle directe.
Objectif métier : repérer les déclarations avec un nombre de versions atypique, ventiler par bureau, et croiser avec les redressements associés.
Sortie attendue : tableau avec
instanceid, nb_versions,
Q95_workflow, surplus_versions,
ide_cuo_cod, ide_cuo_nam, owner,
exa_exa ; ventilation par bureau ; extension avec les
montants de redressement.
q4 <- decl_workflow %>%
left_join(
header_ref %>% select(instanceid, ide_cuo_cod, ide_cuo_nam, owner, exa_exa),
by = "instanceid"
) %>%
filter(cascade == TRUE) %>%
mutate(
Q95_workflow = Q95_workflow,
surplus_versions = nb_versions - Q95_workflow
) %>%
arrange(desc(nb_versions))
head(q4, 20)## # A tibble: 20 × 22
## instanceid DOC_VER_MIN DOC_VER_MAX nb_versions date_depot
## <int> <int> <int> <int> <dttm>
## 1 2741376 1 51 51 2022-04-02 02:00:00
## 2 2831489 1 43 43 2022-08-31 02:00:00
## 3 2744878 1 39 39 2022-04-12 02:00:00
## 4 2690518 1 36 36 2022-01-11 01:00:00
## 5 2726190 1 35 35 2022-02-23 01:00:00
## 6 2832726 1 34 34 2022-09-02 02:00:00
## 7 2708054 1 27 27 2022-02-01 01:00:00
## 8 2723536 1 27 27 2022-02-19 01:00:00
## 9 2691868 1 26 26 2022-01-12 01:00:00
## 10 2715681 1 25 25 2022-02-09 01:00:00
## 11 2835689 1 25 25 2022-09-07 02:00:00
## 12 2846177 1 25 25 2022-09-22 02:00:00
## 13 2692683 1 24 24 2022-01-13 01:00:00
## 14 2695164 1 24 24 2022-01-15 01:00:00
## 15 2695176 1 23 23 2022-01-15 01:00:00
## 16 2715338 1 23 23 2022-02-09 01:00:00
## 17 2726872 1 23 23 2022-02-23 01:00:00
## 18 2808465 1 22 22 2022-07-27 02:00:00
## 19 2689673 1 21 21 2022-01-09 01:00:00
## 20 2712320 1 21 21 2022-02-05 01:00:00
## # ℹ 17 more variables: date_bae <dttm>, date_payment <dttm>, op_last <dttm>,
## # mainlevee <lgl>, delay_depot_bae_min <dbl>, delay_pay_bae_days <dbl>,
## # hs_stable_decl <lgl>, vit_stable_decl <lgl>, tax_stable_decl <lgl>,
## # stable_decl <lgl>, cascade <lgl>, ide_cuo_cod <chr>, ide_cuo_nam <chr>,
## # owner <chr>, exa_exa <chr>, Q95_workflow <dbl>, surplus_versions <dbl>
# Ventilation par bureau
q4_bureau <- q4 %>%
count(ide_cuo_cod, ide_cuo_nam, sort = TRUE, name = "nb_declarations_cascade")
q4_bureau## # A tibble: 19 × 3
## ide_cuo_cod ide_cuo_nam nb_declarations_cascade
## <chr> <chr> <int>
## 1 CUO_313A6A2E CUO_CA6A5B1B 1020
## 2 CUO_6BC153ED CUO_DFC2161D 583
## 3 CUO_FA720F78 CUO_14AB4E59 495
## 4 CUO_D08406A2 CUO_3061FD94 259
## 5 CUO_BA4A1571 CUO_54D892CD 249
## 6 CUO_8D6D6EF8 CUO_014E9359 228
## 7 CUO_8062B850 CUO_499564F0 213
## 8 CUO_537C11F3 CUO_6656FDFD 151
## 9 CUO_E01087D7 CUO_3355DC7F 134
## 10 CUO_57FDEDA7 CUO_F674DC97 132
## 11 CUO_61E48A76 CUO_83E92C90 112
## 12 CUO_8F4D3372 CUO_BBFD7BA3 86
## 13 CUO_A330C94C CUO_B9BD7F9F 55
## 14 CUO_A4FFC1CE CUO_8AC30101 36
## 15 CUO_250974A4 CUO_C99A3DF6 18
## 16 CUO_9294067C CUO_5A8393D7 9
## 17 CUO_2EF99218 CUO_83A56DC6 1
## 18 CUO_6BC153ED CUO_5EC09149 1
## 19 CUO_AE023546 CUO_7D2DB62F 1
# Extension : croisement cascade × redressements
q4_redressement <- q4 %>%
left_join(
item_compare_full %>%
filter(risk_level == "FORT", DELTA_TAX > 0) %>%
group_by(instanceid) %>%
summarise(
montant_redressement = sum(DELTA_TAX, na.rm = TRUE),
nb_articles_redresses = n(),
.groups = "drop"
),
by = "instanceid"
) %>%
mutate(
redresse = !is.na(montant_redressement),
montant_redressement = coalesce(montant_redressement, 0)
)
cat("Déclarations en cascade :", nrow(q4), "\n")## Déclarations en cascade : 3783
## Dont redressées (FORT + hausse) : 368
## Taux de redressement : 9.7 %
cat("Montant total redressement cascade:", format(sum(q4_redressement$montant_redressement), big.mark = " "), "\n")## Montant total redressement cascade: 221 886 084
q4_bureau_redressement <- q4_redressement %>%
group_by(ide_cuo_cod, ide_cuo_nam) %>%
summarise(
nb_declarations_cascade = n(),
nb_redressees = sum(redresse),
taux_redressement = round(mean(redresse) * 100, 1),
montant_total_redress = sum(montant_redressement, na.rm = TRUE),
nb_versions_max = max(nb_versions),
.groups = "drop"
) %>%
arrange(desc(montant_total_redress))
q4_bureau_redressement## # A tibble: 19 × 7
## ide_cuo_cod ide_cuo_nam nb_declarations_cascade nb_redressees
## <chr> <chr> <int> <int>
## 1 CUO_6BC153ED CUO_DFC2161D 583 48
## 2 CUO_D08406A2 CUO_3061FD94 259 46
## 3 CUO_FA720F78 CUO_14AB4E59 495 126
## 4 CUO_8D6D6EF8 CUO_014E9359 228 25
## 5 CUO_BA4A1571 CUO_54D892CD 249 22
## 6 CUO_537C11F3 CUO_6656FDFD 151 14
## 7 CUO_E01087D7 CUO_3355DC7F 134 17
## 8 CUO_61E48A76 CUO_83E92C90 112 14
## 9 CUO_250974A4 CUO_C99A3DF6 18 2
## 10 CUO_A4FFC1CE CUO_8AC30101 36 5
## 11 CUO_57FDEDA7 CUO_F674DC97 132 10
## 12 CUO_A330C94C CUO_B9BD7F9F 55 4
## 13 CUO_8062B850 CUO_499564F0 213 8
## 14 CUO_8F4D3372 CUO_BBFD7BA3 86 13
## 15 CUO_313A6A2E CUO_CA6A5B1B 1020 14
## 16 CUO_2EF99218 CUO_83A56DC6 1 0
## 17 CUO_6BC153ED CUO_5EC09149 1 0
## 18 CUO_9294067C CUO_5A8393D7 9 0
## 19 CUO_AE023546 CUO_7D2DB62F 1 0
## # ℹ 3 more variables: taux_redressement <dbl>, montant_total_redress <dbl>,
## # nb_versions_max <int>
TODO étudiant :
- Commenter le lien entre multiplication des versions et rupture de workflow : une cascade documentaire implique-t-elle systématiquement un redressement fiscal ?
- À partir de
q4_bureau_redressement, identifier les bureaux où la cascade est la plus fortement associée à un redressement effectif (taux et montant). Distinguer les bureaux à fort volume de cascade sans redressement notable de ceux à cascade + impact fiscal fort.- Que pourrait signifier un bureau avec beaucoup de cascades mais peu de redressements ? Et inversement ?
Objectif métier : analyser les articles dont le code HS a été modifié entre version initiale et version finale, puis qualifier l’effet fiscal associé.
Sortie attendue : tableau au grain article avec
instanceid, key_itm_nbr, HS_ini,
HS_fin, TAX_INI, TAX_FIN,
DELTA_TAX, ABS_DELTA_TAX,
risk_level.
q5 <- item_compare_full %>%
filter(chg_hs == TRUE) %>%
arrange(desc(ABS_DELTA_TAX)) %>%
select(instanceid, key_itm_nbr, HS_ini, HS_fin, TAX_INI, TAX_FIN,
DELTA_TAX, ABS_DELTA_TAX, SENS_DELTA_TAX, FLAG_BAISSE_TAX, risk_level)
head(q5, 30)## # A tibble: 30 × 11
## instanceid key_itm_nbr HS_ini HS_fin TAX_INI TAX_FIN DELTA_TAX ABS_DELTA_TAX
## <int> <int> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 2909136 1 271019… 27101… 2.22e6 1.51e7 12870653. 12870653.
## 2 2909140 1 271019… 27101… 2.22e6 1.51e7 12870653. 12870653.
## 3 2717101 1 190190… 19019… 4.64e6 1.05e7 5862754. 5862754.
## 4 2717135 1 190190… 19019… 4.64e6 1.05e7 5862754. 5862754.
## 5 2717144 1 190190… 19019… 4.64e6 1.05e7 5862754. 5862754.
## 6 2856336 1 851769… 85366… 1.53e7 2.06e7 5395701. 5395701.
## 7 2682561 1 190190… 04021… 6.34e6 1.11e7 4748598. 4748598.
## 8 2805765 1 870840… 87021… 7.32e5 5.10e6 4371452. 4371452.
## 9 2805761 1 870840… 87021… 7.67e5 4.50e6 3729116. 3729116.
## 10 2853086 1 170199… 17019… 3.06e6 6.71e6 3651098. 3651098.
## # ℹ 20 more rows
## # ℹ 3 more variables: SENS_DELTA_TAX <chr>, FLAG_BAISSE_TAX <lgl>,
## # risk_level <chr>
q5_baisse_tax <- item_compare_full %>%
filter(chg_hs == TRUE, DELTA_TAX < 0) %>%
arrange(DELTA_TAX) %>%
select(instanceid, key_itm_nbr, HS_ini, HS_fin, TAX_INI, TAX_FIN,
DELTA_TAX, ABS_DELTA_TAX, SENS_DELTA_TAX, risk_level)
head(q5_baisse_tax, 30)## # A tibble: 30 × 10
## instanceid key_itm_nbr HS_ini HS_fin TAX_INI TAX_FIN DELTA_TAX ABS_DELTA_TAX
## <int> <int> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 2692787 1 871130… 87032… 2.27e6 6.25e5 -1648632. 1648632.
## 2 2692785 1 871130… 87032… 2.01e6 3.59e5 -1648451. 1648451.
## 3 2754985 1 151190… 15119… 2.98e6 1.36e6 -1615691. 1615691.
## 4 2824886 1 730900… 85013… 1.47e6 1.44e5 -1330294. 1330294.
## 5 2793008 1 110100… 11031… 7.38e5 2.46e5 -491919. 491919.
## 6 2893655 1 870323… 87032… 1.80e6 1.37e6 -429770. 429770.
## 7 2820812 1 040291… 34011… 1.30e6 9.24e5 -375743. 375743.
## 8 2732877 1 340119… 11031… 5.60e5 2.92e5 -267927. 267927.
## 9 2696851 1 870323… 87032… 6.49e5 3.90e5 -258366. 258366.
## 10 2741786 1 110100… 19021… 4.85e5 2.59e5 -225982. 225982.
## # ℹ 20 more rows
## # ℹ 2 more variables: SENS_DELTA_TAX <chr>, risk_level <chr>
q5_compare_sens <- item_compare_full %>%
filter(chg_hs == TRUE) %>%
count(SENS_DELTA_TAX, risk_level, sort = TRUE, name = "nb_items")
q5_baisse_bureau <- item_compare_full %>%
filter(chg_hs == TRUE, DELTA_TAX < 0) %>%
count(ide_cuo_cod, ide_cuo_nam, sort = TRUE, name = "nb_items_baisse_tax")
q5_baisse_owner <- item_compare_full %>%
filter(chg_hs == TRUE, DELTA_TAX < 0) %>%
count(owner, sort = TRUE, name = "nb_items_baisse_tax")
q5_compare_sens## # A tibble: 4 × 3
## SENS_DELTA_TAX risk_level nb_items
## <chr> <chr> <int>
## 1 STABLE FAIBLE 182
## 2 HAUSSE_TAX FORT 130
## 3 STABLE MOYEN 108
## 4 BAISSE_TAX FORT 31
## # A tibble: 11 × 3
## ide_cuo_cod ide_cuo_nam nb_items_baisse_tax
## <chr> <chr> <int>
## 1 CUO_FA720F78 CUO_14AB4E59 9
## 2 CUO_313A6A2E CUO_CA6A5B1B 3
## 3 CUO_8F4D3372 CUO_BBFD7BA3 3
## 4 CUO_A330C94C CUO_B9BD7F9F 3
## 5 CUO_537C11F3 CUO_6656FDFD 2
## 6 CUO_57FDEDA7 CUO_F674DC97 2
## 7 CUO_61E48A76 CUO_83E92C90 2
## 8 CUO_6BC153ED CUO_DFC2161D 2
## 9 CUO_8D6D6EF8 CUO_014E9359 2
## 10 CUO_E01087D7 CUO_3355DC7F 2
## 11 CUO_BA4A1571 CUO_54D892CD 1
## # A tibble: 16 × 2
## owner nb_items_baisse_tax
## <chr> <int>
## 1 COD_1D44BB6E 4
## 2 COD_3D42F48C 4
## 3 COD_91A0D8A8 4
## 4 COD_6AE100D0 3
## 5 COD_DC31D3E2 3
## 6 COD_2A7D61D5 2
## 7 COD_43C7B650 2
## 8 COD_1E20F0CA 1
## 9 COD_5D5A6B83 1
## 10 COD_6805DBE3 1
## 11 COD_6BAB4A7E 1
## 12 COD_6CFDEE48 1
## 13 COD_9A9822B9 1
## 14 COD_C2EFE914 1
## 15 COD_D04DB0EF 1
## 16 COD_D46603E0 1
TODO étudiant :
- Quelle est la proportion de cas
HAUSSE_TAXvsBAISSE_TAXparmi les articles avec HS modifié ? Interpréter cette répartition.- Les cas
BAISSE_TAX + FORTméritent une attention particulière. Pourquoi ? Donner 2 interprétations possibles d’un reclassement HS conduisant à une baisse de taxes.- Identifier les bureaux les plus représentés dans les cas de baisse. Un même bureau concentre-t-il les cas de hausse et de baisse ?
Objectif métier : décrire les couples vérificateur /
code déclarant les plus fréquents, vérifier si ces couples sont
concentrés dans certains bureaux. Rappel :
owner est le code déclarant ; end_user (acteur
technique réel) n’est pas analysé dans cet atelier.
Sortie attendue : tableau des couples
exa_exa / owner les plus fréquents ; synthèse par
ide_cuo_cod.
q6_couples <- df_gen %>%
filter(!is.na(owner)) %>%
count(ide_cuo_cod, ide_cuo_nam, exa_exa, owner, name = "nb_operations") %>%
arrange(desc(nb_operations))
head(q6_couples, 20)## ide_cuo_cod ide_cuo_nam exa_exa owner nb_operations
## 1 CUO_8062B850 CUO_499564F0 No examiner COD_10189223 13990
## 2 CUO_FA720F78 CUO_14AB4E59 No examiner COD_91A0D8A8 12950
## 3 CUO_61E48A76 CUO_83E92C90 No examiner COD_DC31D3E2 10257
## 4 CUO_E01087D7 CUO_3355DC7F No examiner COD_1D44BB6E 9788
## 5 CUO_E01087D7 CUO_3355DC7F No examiner COD_10189223 9581
## 6 CUO_313A6A2E CUO_CA6A5B1B No examiner COD_6CFDEE48 8391
## 7 CUO_57FDEDA7 CUO_F674DC97 No examiner COD_9CA665A8 7829
## 8 CUO_88C4B39F CUO_7145CEDD No examiner COD_819CF064 7798
## 9 CUO_313A6A2E CUO_CA6A5B1B No examiner COD_1D44BB6E 6869
## 10 CUO_88C4B39F CUO_7145CEDD No examiner COD_2A7D61D5 6607
## 11 CUO_6BC153ED CUO_DFC2161D No examiner COD_819CF064 6229
## 12 CUO_250974A4 CUO_C99A3DF6 No examiner COD_5D5A6B83 6170
## 13 CUO_6BC153ED CUO_DFC2161D No examiner COD_6CFDEE48 5668
## 14 CUO_D08406A2 CUO_3061FD94 No examiner COD_7AB3C08E 5651
## 15 CUO_D08406A2 CUO_3061FD94 No examiner COD_6CFDEE48 5636
## 16 CUO_537C11F3 CUO_6656FDFD No examiner COD_95EBB17A 5631
## 17 CUO_FA720F78 CUO_14AB4E59 No examiner COD_3D42F48C 5566
## 18 CUO_FA720F78 CUO_14AB4E59 No examiner COD_5D5A6B83 5563
## 19 CUO_313A6A2E CUO_CA6A5B1B No examiner COD_7E58B39D 5449
## 20 CUO_08824E78 CUO_B80496FD No examiner COD_3382CCAB 5225
q6_no_examiner_bureau <- df_gen %>%
filter(!is.na(owner)) %>%
mutate(no_examiner = exa_exa == "No examiner") %>%
count(ide_cuo_cod, ide_cuo_nam, no_examiner, name = "nb_operations") %>%
tidyr::pivot_wider(
names_from = no_examiner,
values_from = nb_operations,
values_fill = 0,
names_prefix = "no_examiner_"
) %>%
rename(
nb_operations_exa_renseigne = no_examiner_FALSE,
nb_operations_no_examiner = no_examiner_TRUE
) %>%
mutate(
nb_operations_total = nb_operations_exa_renseigne + nb_operations_no_examiner,
part_no_examiner = nb_operations_no_examiner / nb_operations_total
) %>%
arrange(desc(part_no_examiner), desc(nb_operations_no_examiner))
q6_couples_renseignes <- df_gen %>%
filter(!is.na(owner), exa_exa != "No examiner") %>%
count(ide_cuo_cod, ide_cuo_nam, exa_exa, owner, name = "nb_operations") %>%
arrange(desc(nb_operations))
q6_bureau_renseignes <- q6_couples_renseignes %>%
group_by(ide_cuo_cod, ide_cuo_nam) %>%
summarise(
nb_couples_renseignes = n(),
nb_operations_renseignees = sum(nb_operations, na.rm = TRUE),
max_operations_sur_un_couple = max(nb_operations, na.rm = TRUE),
.groups = "drop"
) %>%
arrange(desc(max_operations_sur_un_couple), desc(nb_operations_renseignees))
head(q6_no_examiner_bureau, 20)## # A tibble: 20 × 6
## ide_cuo_cod ide_cuo_nam nb_operations_no_examiner nb_operations_exa_rense…¹
## <chr> <chr> <int> <int>
## 1 CUO_88C4B39F CUO_7145CEDD 48704 0
## 2 CUO_1B047186 CUO_0A52E7E3 4348 0
## 3 CUO_2EF99218 CUO_83A56DC6 1758 0
## 4 CUO_26F930EB CUO_C3543505 1618 0
## 5 CUO_860710AE CUO_C0695F99 1420 0
## 6 CUO_C13F951D CUO_C4FC5C52 1198 0
## 7 CUO_A7A73784 CUO_8A211420 1085 0
## 8 CUO_4D10587C CUO_71BD6C81 1084 0
## 9 CUO_5EA92951 CUO_C7E5CFFF 599 0
## 10 CUO_B701682B CUO_63C53650 493 0
## 11 CUO_A3F0385F CUO_A1702257 190 0
## 12 CUO_0631B89C CUO_A8372852 174 0
## 13 CUO_F493F68F CUO_E274C758 103 0
## 14 CUO_F0521822 CUO_D4608D63 49 0
## 15 CUO_AE023546 CUO_7D2DB62F 28 0
## 16 CUO_71E210E2 CUO_5954CF36 12 0
## 17 CUO_0A35421D CUO_24BA7FBE 4 0
## 18 CUO_08824E78 CUO_B80496FD 5387 1
## 19 CUO_BA4A1571 CUO_54D892CD 13378 2302
## 20 CUO_6BC153ED CUO_DFC2161D 47598 9206
## # ℹ abbreviated name: ¹nb_operations_exa_renseigne
## # ℹ 2 more variables: nb_operations_total <int>, part_no_examiner <dbl>
## ide_cuo_cod ide_cuo_nam exa_exa owner nb_operations
## 1 CUO_313A6A2E CUO_CA6A5B1B EXA_7A3DC350 COD_29D2B98B 2239
## 2 CUO_250974A4 CUO_C99A3DF6 EXA_0030EA59 COD_5D5A6B83 2033
## 3 CUO_313A6A2E CUO_CA6A5B1B EXA_7A3DC350 COD_1D44BB6E 1665
## 4 CUO_313A6A2E CUO_CA6A5B1B EXA_7A3DC350 COD_E99FB750 1403
## 5 CUO_8062B850 CUO_499564F0 EXA_059C22C2 COD_10189223 1304
## 6 CUO_313A6A2E CUO_CA6A5B1B EXA_7A3DC350 COD_347779D3 1023
## 7 CUO_8062B850 CUO_499564F0 EXA_F58A7E1A COD_10189223 1009
## 8 CUO_313A6A2E CUO_CA6A5B1B EXA_86AA87FC COD_6CFDEE48 973
## 9 CUO_313A6A2E CUO_CA6A5B1B EXA_7A3DC350 COD_7E58B39D 959
## 10 CUO_313A6A2E CUO_CA6A5B1B EXA_7A3DC350 COD_C3D3F58C 882
## 11 CUO_313A6A2E CUO_CA6A5B1B EXA_7A3DC350 COD_91A0D8A8 840
## 12 CUO_250974A4 CUO_C99A3DF6 EXA_0030EA59 COD_37901709 767
## 13 CUO_313A6A2E CUO_CA6A5B1B EXA_7A3DC350 COD_6CFDEE48 697
## 14 CUO_313A6A2E CUO_CA6A5B1B EXA_120AE2A6 COD_6CFDEE48 692
## 15 CUO_313A6A2E CUO_CA6A5B1B EXA_7A3DC350 COD_B51ECEFB 669
## 16 CUO_250974A4 CUO_C99A3DF6 EXA_0030EA59 COD_6CFDEE48 569
## 17 CUO_8062B850 CUO_499564F0 EXA_4F21B130 COD_10189223 521
## 18 CUO_8062B850 CUO_499564F0 EXA_8B810B00 COD_10189223 518
## 19 CUO_313A6A2E CUO_CA6A5B1B EXA_7A3DC350 COD_2376C426 517
## 20 CUO_57FDEDA7 CUO_F674DC97 EXA_296A114A COD_9CA665A8 516
## # A tibble: 20 × 5
## ide_cuo_cod ide_cuo_nam nb_couples_renseignes nb_operations_renseignees
## <chr> <chr> <int> <int>
## 1 CUO_313A6A2E CUO_CA6A5B1B 141 22246
## 2 CUO_250974A4 CUO_C99A3DF6 19 4498
## 3 CUO_8062B850 CUO_499564F0 221 12981
## 4 CUO_57FDEDA7 CUO_F674DC97 134 9917
## 5 CUO_FA720F78 CUO_14AB4E59 599 13616
## 6 CUO_61E48A76 CUO_83E92C90 261 5755
## 7 CUO_8D6D6EF8 CUO_014E9359 75 4466
## 8 CUO_E01087D7 CUO_3355DC7F 242 6102
## 9 CUO_8F4D3372 CUO_BBFD7BA3 112 4218
## 10 CUO_A4FFC1CE CUO_8AC30101 94 2376
## 11 CUO_9294067C CUO_5A8393D7 45 578
## 12 CUO_A330C94C CUO_B9BD7F9F 41 960
## 13 CUO_537C11F3 CUO_6656FDFD 687 4872
## 14 CUO_BA4A1571 CUO_54D892CD 322 2302
## 15 CUO_6BC153ED CUO_DFC2161D 998 9206
## 16 CUO_D08406A2 CUO_3061FD94 1653 14315
## 17 CUO_BA4A1571 CUO_E48E7BBF 9 25
## 18 CUO_6BC153ED CUO_5EC09149 11 18
## 19 CUO_FA720F78 CUO_D41BEFDA 11 22
## 20 CUO_08824E78 CUO_B80496FD 1 1
## # ℹ 1 more variable: max_operations_sur_un_couple <int>
TODO étudiant :
- Quels bureaux affichent un taux
No examinerélevé (proche de 100 %) ? Proposer deux interprétations possibles (circuit sans contrôle vs saisie incomplète).- Parmi les couples
exa_exa / ownerrenseignés, identifier les plus fréquents. Que peut signifier une forte récurrence d’un même couple vérificateur / déclarant dans un même bureau ?- Pourquoi est-il important de distinguer
owner(code déclarant) deend_user(acteur technique) dans cette analyse ?
icp <- decl_workflow %>%
summarise(
ICP1_liquidation_jour_meme = mean(as.Date(date_payment) == as.Date(date_depot), na.rm = TRUE),
ICP2_mainlevee_le_2j = mean(delay_pay_bae_days <= 2, na.rm = TRUE),
ICP3_efficacite_repression = mean(instanceid %in% (item_compare_full %>%
filter(DELTA_TAX > 0) %>% pull(instanceid)), na.rm = TRUE),
ICP4_contribution_recouvrement = mean(item_compare_full$DELTA_TAX[item_compare_full$DELTA_TAX > 0],
na.rm = TRUE)
)
icp## # A tibble: 1 × 4
## ICP1_liquidation_jour_meme ICP2_mainlevee_le_2j ICP3_efficacite_repression
## <dbl> <dbl> <dbl>
## 1 0.485 0.941 0.00623
## # ℹ 1 more variable: ICP4_contribution_recouvrement <dbl>
TODO étudiant :
- Interpréter chacun des 4 ICP en une phrase : que mesure-t-il, quelle est la valeur obtenue, est-elle favorable ou défavorable ?
- ICP3 mesure le taux de déclarations avec au moins un redressement positif. Quelle nuance faut-il apporter à l’interprétation de ce taux (un taux faible signifie-t-il forcément un système très conforme) ?
- ICP4 est une moyenne. Pourquoi la médiane serait-elle un indicateur complémentaire utile ici ?