cassionAnalyse de données

Leçon 5 sur 8

Unité · Le marché est aussi un résultat

Le calendrier pèse plus que le programme

Le maïs médian vaut 75 gourdes à la récolte de décembre et 130 au pic de juillet. Comparez deux passages d'enquête pris à des points différents de ce cycle et vous avez mesuré le calendrier — et le panel d'un district a changé de composition exactement quand cela comptait.

PythonR135 minCadre intégré de classification de la sécurité alimentaire (IPC)Standards Sphère

Une ligne de preuve indépendante

Tout ce qui figure dans les deux premières unités est ce que les ménages ont déclaré sur eux-mêmes. Une série de prix ne l’est pas : personne ne se souvient de rien, et un marché dont le prix du maïs a doublé l’a fait qu’une enquête ait été sur le terrain ou non.

import pandas as pd

prices = pd.read_csv("market-prices-2024.v1.csv")
print(f"{len(prices):,} observations")
print(f"{prices['market_id'].nunique()} markets, "
      f"{prices['commodity'].nunique()} series, "
      f"{prices['period'].nunique()} months")
library(dplyr)

prices |> summarise(n = n(), markets = n_distinct(market_id),
                    series = n_distinct(commodity), months = n_distinct(period))

2 273 observations, douze marchés, huit séries, vingt-quatre mois. Deux ans est la longueur utile minimale, car une seule année ne permet pas de distinguer un pic saisonnier d’une dégradation.

Nettoyez trois choses avant tout tracé

prices["price_htg"] = pd.to_numeric(prices["price_htg"])

dollars = prices["price_htg"] < 10
marmite = (prices["commodity"] == "maize") & (prices["market_id"] == "MK005")
thin = prices["trader_quotes"] == 1

print(f"dollar entries: {dollars.sum()}")
print(f"marmite market maize rows: {marmite.sum()}")
print(f"single-quote observations: {thin.sum()}")
prices |> summarise(
  dollars = sum(price_htg < 10),
  thin = sum(trader_quotes == 1)
)

Huit prix sont en dollars avec la colonne de devise indiquant toujours HTG. Ils se lisent comme des valeurs inférieures à 10 et un filtre de valeurs aberrantes les supprimerait, alors que les multiplier par environ 132 les récupère.

Un marché relève le maïs à la marmite, mesure de volume d’environ 2,7 kg, et le classe dans une colonne libellée au kilogramme. Son prix médian du maïs vaut 263 gourdes contre environ 100 partout ailleurs.

by_market = prices[prices["commodity"] == "maize"].groupby("market_id")["price_htg"].median()
print(by_market.round(1).sort_values())
prices |> filter(commodity == "maize") |>
  summarise(median = median(price_htg), .by = market_id) |> arrange(median)

L’erreur d’unité est invisible dans un marché et évidente sur douze. C’est la règle générale du décalage d’unité : il n’a jamais l’air faux sur sa propre ligne, et il a toujours l’air faux à côté de ses pairs.

Treize observations reposent sur une seule cotation. Ce ne sont pas des erreurs. Une médiane d’une valeur est une cotation et non un prix, et la décision est de les exclure ou de leur donner moins de poids — l’un ou l’autre est défendable, le silence ne l’est pas.

Le cycle saisonnier

clean = prices[~dollars & ~marmite]
maize = clean[clean["commodity"] == "maize"]
series = maize.groupby("period")["price_htg"].median()
print(series.round(0))
prices |>
  filter(commodity == "maize", price_htg >= 10, market_id != "MK005") |>
  summarise(median = median(price_htg), .by = period) |> arrange(period)
Mois 2023 2024
Janvier 66 70
Avril 97 110
Juillet (pic de soudure) 130 159
Octobre 92 104
Décembre (récolte) 75 81

Le maïs coûte 74 % de plus au pic de juillet qu’à la récolte de décembre en 2023, et 96 % de plus en 2024. C’est l’ampleur de l’effet saisonnier, et elle dépasse presque tout effet de programme qu’on vous demandera de détecter.

La conséquence pour un plan d’enquête est directe. Une situation de référence en décembre et une évaluation finale en juillet montreraient une dégradation catastrophique entièrement produite par le calendrier. Comparez ce qui est comparable : juillet contre juillet.

peaks = series.loc[["2023-07", "2024-07"]]
print(f"lean peak 2023: {peaks['2023-07']:.1f}")
print(f"lean peak 2024: {peaks['2024-07']:.1f}")
print(f"year on year: {peaks['2024-07'] / peaks['2023-07'] - 1:+.1%}")
# Same point in the season, one year apart. Everything else is the calendar.

130,1 contre 159,3 — une hausse de 22 % au même point de la saison. Voilà la dégradation, et elle vaut le quart de l’oscillation saisonnière qu’on aurait pu prendre pour elle.

Le panel qui a changé de composition

coverage = maize.pivot_table(index="period", columns="market_id",
                             values="price_htg", aggfunc="size")
print(coverage.isna().sum(axis=1)[lambda s: s > 0])
prices |> filter(commodity == "maize") |> count(period, market_id) |>
  count(period) |> filter(n < 11)

MK001 cesse de rapporter de juin à septembre 2024, quand sa route est coupée. Les lignes sont absentes plutôt que nulles, si bien que rien dans le fichier ne l’annonce.

C’est aussi le marché le plus cher de Nord-Ouest, et Nord-Ouest ne compte que trois marchés — en perdre un déplace donc la moyenne du district d’un tiers de son écart et non d’un douzième.

nord = maize[maize["district"] == "Nord-Ouest"]
reported = nord.groupby("period")["price_htg"].mean()

balanced = nord[nord["market_id"] != "MK001"].groupby("period")["price_htg"].mean()
print(pd.DataFrame({"reported": reported, "balanced": balanced}).round(1)
      .loc["2024-04":"2024-10"])
prices |>
  filter(commodity == "maize", district == "Nord-Ouest") |>
  summarise(reported = mean(price_htg), .by = period)
Mois Ceux qui ont rapporté Les deux ayant rapporté chaque mois
Mai 2024 147,0 123,2
Juin 2024 172,1 172,1
Mai à juin +17 % +40 %

La série rapportée sous-estime de plus de moitié la hausse de soudure, et chacun de ses nombres est une moyenne correcte des marchés qui ont rapporté. La composition a changé sous la série et la série ne l’a pas dit.

Employez un panel équilibré — seulement les marchés présents à chacun des mois comparés — ou chaînez des variations d’un mois à l’autre calculées à l’intérieur de chaque marché. Les deux demandent plus de travail qu’un groupby et les deux font la différence entre une hausse de 17 % et une de 40 %.

Rapportez la série avec son panel

Maize price, gourdes per kg, median across markets

  2023 harvest (Dec)        75      2024 harvest (Dec)       81
  2023 lean peak (Jul)     130      2024 lean peak (Jul)    159
  Seasonal swing          +74%      Seasonal swing         +96%
  Year on year at the lean peak: +22%

  Balanced panel of 10 markets throughout. MK001 (Nord-Ouest) did not
  report June to September 2024 and is excluded from all periods; MK005
  records maize by the marmite and is excluded from maize.
  8 dollar-denominated entries converted at 132 HTG; 13 single-quote
  observations retained and flagged.

Le panel énoncé, les exclusions comptées, et la comparaison d’une année sur l’autre faite au même point de la saison. Un tableau de prix sans son panel est le même défaut qu’un chiffre de couverture sans son taux de rapportage, et ce cours vient de le rencontrer pour la troisième fois.

La suite

Un prix dit ce que la nourriture coûtait. Il ne dit pas si quelqu’un pouvait se la payer, et la leçon suivante porte sur le rapport qui le dit — où une chèvre dont le prix a baissé de 18 % a perdu 62 % de son pouvoir d’achat.

Animer cette leçon

La leçon en diaporama, la prose étant reléguée dans les notes du présentateur plutôt que projetée. Produit à partir de cette page, dont il ne peut donc pas s'écarter.

Lancer le diaporamaLire les diapositives

Le PDF ne requiert aucun logiciel et se projette depuis n'importe quel poste. Le fichier PowerPoint est fait pour être modifié : appliquez la charte de votre organisation, retirez une section pour une séance plus courte, ou fusionnez deux leçons en atelier.