#+TITLE: Le pouvoir d'achat des ouvriers anglais du XVIe au XIXe siècle
#+AUTHOR: Antoine RICHARD
#+LANGUAGE: fr
# #+PROPERTY: header-args :eval never-export
#+OPTIONS: ^:{}
#+HTML_HEAD:
#+HTML_HEAD:
#+HTML_HEAD:
#+HTML_HEAD:
#+HTML_HEAD:
#+HTML_HEAD:
Dans document computanionel nous cherchons à reproduire et mettre à
jour l'étude de William Playfair sur l'évolution du pouvoir d'achat
des ouvriers entre les année 1565 et 1810.
* Préface :noexport:
Pour exécuter le code de cette analyse, il faut disposer des logiciels suivants:
** Emacs 25 ou plus
Une version plus ancienne d'Emacs devrait suffire. Pour une version antérieure à 26, il faut installer une version récente (9.x) d'org-mode.
** Python 3.6 ou plus
Nous utilisons le traitement de dates en format ISO 8601, qui a été implémenté en Python seulement avec la version 3.6.
#+BEGIN_SRC python :results output
import sys
if sys.version_info.major < 3 or sys.version_info.minor < 6:
print("Veuillez utiliser Python 3.6 (ou plus) !")
#+END_SRC
#+BEGIN_SRC emacs-lisp :results output
(unless (featurep 'ob-python)
(print "Veuillez activer python dans org-babel (org-babel-do-languages) !"))
#+END_SRC
** R 3.4
Nous n'utilisons que des fonctionnalités de base du langage R, une version antérieure devrait suffire.
#+BEGIN_SRC emacs-lisp :results output
(unless (featurep 'ob-R)
(print "Veuillez activer R dans org-babel (org-babel-do-languages) !"))
#+END_SRC
* Préparation des données
Les données de l'étude de [[https://fr.wikipedia.org/wiki/William_Playfair][William Playfair]] sont disponible à l'adresse suivante:
#+NAME: data-url
https://raw.githubusercontent.com/vincentarelbundock/Rdatasets/master/csv/HistData/Wheat.csv
Quelques explications des colonnes données sur [[https://www.fun-mooc.fr/courses/course-v1:inria+41016+self-paced/courseware/5b932aa591d245d48d8943385cb3120a/57c96f2c7f7b42018eaac3e6b34546f4/][le site du MOOC]]:
| Nom de colonne | Libellé de colonne |
|----------------+-----------------------------------------------------------------------------------------------------------------------------------|
| | Numéro de la ligne |
| ~Year~ | Année au format YYYY |
| ~Wheat~ | Le prix en shillings pour un quart de boisseau de blé |
| ~Wages~ | Salaire en shillings par semaine |
Notons que, jusqu'en 1971, la livre sterling était divisée en 20
shillings, et un shilling en 12 pences.
Notons aussi qu'un quart de boisseau équivaut 15 livres britanniques
ou 6,8 kg.
** Téléchargement des données
Afin de ne pas avoir à télécharger les données à chaque execution, et
pour pouvoir travailler dessus sans accès internet, nous sauvegardons
ces données dans un fichier csv.
De plus, afin d'éviter de possible problèmes d'encodage, nous
enregistrons le fichier octet par octet.
#+BEGIN_SRC python :results output :var data_url=data-url
from urllib.request import urlopen
from os.path import exists
data_file = "data.csv"
if not exists(data_file):
f = open(data_file,"wb")
f.write(urlopen(data_url).read())
f.close()
#+END_SRC
#+RESULTS:
Après avoir téléchargé les données (si nécessaire), nous commençons
par charger les données qui nous intéressent dans un tableau.
#+BEGIN_SRC R :results silent :session *R* :exports none
table = read.csv("data.csv", sep=",", header=TRUE)
#+END_SRC
Regardons un résumé de nos données:
#+BEGIN_SRC R :results value :session *R* :exports both
summary(table)
#+END_SRC
#+RESULTS:
| Min. : 1 | Min. :1565 | Min. :26.00 | Min. : 5.000 |
| 1st Qu.:14 | 1st Qu.:1630 | 1st Qu.:33.00 | 1st Qu.: 6.145 |
| Median :27 | Median :1695 | Median :41.00 | Median : 7.800 |
| Mean :27 | Mean :1695 | Mean :43.26 | Mean :11.582 |
| 3rd Qu.:40 | 3rd Qu.:1760 | 3rd Qu.:47.00 | 3rd Qu.:14.875 |
| Max. :53 | Max. :1821 | Max. :99.00 | Max. :30.000 |
| nil | nil | nil | NA's :3 |
Nous pouvons déjà voir que certaines données semble manquer:
trois entrées n'ont pas de valeur pour la colonne "Wages".
** Recherches des données manquantes
Afin de ne pas géner de futurs traitements de données, commençons par
détecter et supprimer les entrées sans donnée pour la colonne "Wages".
#+begin_src R :results output :session *R* :exports both
table = table[!is.na(table$Wages),]
summary(table)
#+end_src
#+RESULTS:
:
: X Year Wheat Wages
: Min. : 1.00 Min. :1565 Min. :26.00 Min. : 5.000
: 1st Qu.:13.25 1st Qu.:1626 1st Qu.:32.25 1st Qu.: 6.145
: Median :25.50 Median :1688 Median :40.25 Median : 7.800
: Mean :25.50 Mean :1688 Mean :42.14 Mean :11.582
: 3rd Qu.:37.75 3rd Qu.:1749 3rd Qu.:45.75 3rd Qu.:14.875
: Max. :50.00 Max. :1810 Max. :99.00 Max. :30.000
** Extractions des colonnes utilisées
Nous pouvons remarquer que la première colonne du tableau ne contient
que les numéro des lignes. Dans notre études seuls les colonnes ~Year~,
~Wheat~ et ~Wages~ nous intéresse. Nous supprimons donc la première
colonne de nos données.
#+begin_src R :results output :session *R* :exports both
table = table[,2:4]
summary(table)
#+end_src
#+RESULTS:
:
: Year Wheat Wages
: Min. :1565 Min. :26.00 Min. : 5.000
: 1st Qu.:1626 1st Qu.:32.25 1st Qu.: 6.145
: Median :1688 Median :40.25 Median : 7.800
: Mean :1688 Mean :42.14 Mean :11.582
: 3rd Qu.:1749 3rd Qu.:45.75 3rd Qu.:14.875
: Max. :1810 Max. :99.00 Max. :30.000
** Vérification des données
Vérifions maintenant si les données de notre tableau sont crédibles
selon les critères suivants:
- ~Year~: nombre entier composé de quatre chiffres
- ~Wheat~ et ~Wages~: valeur numerique
#+begin_src R :results output :session *R* :exports both
for(row in 1:nrow(table)){
if(!is.integer(table[row,"Year"])
|| nchar(table[row,"Year"]) != 4)
{
print("Valeur suspecte dans la colonne 'Year': ")
print(table[row,])
}
if(!is.numeric(table[row,"Wheat"])){
print("Valeur suspecte dans la colonne 'Wheat': ")
print(table[row,])
}
if(!is.numeric(table[row,"Wages"])){
print("Valeur suspecte dans la colonne 'Wages': ")
print(table[row,])
}
}
#+end_src
#+RESULTS:
Tout semble en règles.
** Vérifications des dates
Chaque entrée est supposée être séparé d'exactement cinq année,
vérifions cela.
#+begin_src R :results output :session *R* :exports both
for(row in 2:nrow(table)){
if(table[row,"Year"] - table[row-1,"Year"] != 5){
print(
paste(
"Il y a",
table[row,"Year"] - table[row-1,"Year"],
"ans entre", table[row,"Year"],
"et", table[row-1,"Year"]
)
)
}
}
#+end_src
#+RESULTS:
Pas de problème de ce coté là non plus, nous pouvons passer à
l'analyse de nos données.
* Reproduction des résultats de William Playfair
Avant d'effectuer nos propres opérations sur les données receuillies,
tentons de reproduire le
[[https://upload.wikimedia.org/wikipedia/commons/3/3a/Chart_Showing_at_One_View_the_Price_of_the_Quarter_of_Wheat%2C_and_Wages_of_Labour_by_the_Week%2C_from_1565_to_1821.png][graphe]]
proposé par William Playfair dans son étude.
Celui-ci représentait l'évolution du prix du blé à l'aide de barres,
un barre par tranche de 5 années, et l'évolution des salaires à l'aide
d'une aire bleue délimitée d'une courbe rouge.
Pour reproduire ce graphe nous allons utilisé la librairie /ggplot2/,
qui permet une création de graphe simple, étape par étape.
#+begin_src R :results silent :session *R*
library(ggplot2)
#+end_src
** Évolution du prix du blé
Comme introduit plus tôt, nous souhaitons visualiser l'évolution du
prix du blé au cours du temps à l'aide d'un /barplot/, que nous obtenons
via la fonction /geom_bar()/.
#+begin_src R :results output graphics :file (org-babel-temp-file "figure" ".png") :exports both :width 600 :height 400 :session *R*
p <- ggplot(table, aes(x=Year)) +
geom_bar(stat="identity", aes(y=Wheat))
p
#+end_src
#+RESULTS:
[[file:/tmp/babel-mdw4ds/figureMc14eD.png]]
Notons que, puisque nous avons supprimée les entrées pour lesquelles
nous n'avions pas de valeurs pour la colonne /Wages/, les trois
dernières barre du graphe original ne sont pas présentes dans notre
reproduction.
** Évolution des salaires
Dans l'étude de Playfair, l'évolution des salaires était représentée à
l'aide d'une aire bleue délimitée par une courbe rouge.
Pour reproduire cela nous utilisons la fonction /geom_area()/ pour
l'aire et la fonction /geom_line()/ pour la ligne de délimitation.
#+begin_src R :results output graphics :file (org-babel-temp-file "figure" ".png") :exports both :width 600 :height 400 :session *R*
p <- p + geom_area(aes(y=Wages),stat="identity",fill="lightblue")
p <- p + geom_line(aes(y=Wages),color="red",size=2)
p
#+end_src
#+RESULTS:
[[file:/tmp/babel-mdw4ds/figurezDPXzY.png]]
** Ajout de divers éléments
Maintenant que nous avons affiché nos données dans un graphe à la
manière de Playfair, nous allons procéder à quelques ajouts pour nous
rapprocher du graphe initial, tels que:
- Changer le label de l'axe des ordonnées en "Shillings"
- Dupliquer l'axe des ordonnées à droite du graphe
- Répartir l'axe des ordonnées en divisions de 5 shillings
- Répartir l'axe des abscisses en divisions de 10 années
- Ajouter un titre
#+begin_src R :results output graphics :file (org-babel-temp-file "figure" ".png") :exports both :width 600 :height 400 :session *R*
p <- p + ylab("Shillings")
p <- p + scale_y_continuous(
breaks=seq(0,100,5),
sec.axis=sec_axis(~.,name=derive(),breaks=derive())
)
p <- p + scale_x_continuous(
breaks=seq(min(table$Year),max(table$Year),10)
) +
theme(axis.text.x = element_text(angle=45))
p <- p + ggtitle("Showing at one view the price of the quarter of Wheat and Wages of labour by the week")
p
#+end_src
#+RESULTS:
[[file:/tmp/babel-mdw4ds/figureG4TJjY.png]]
* Mise à jour du graphe de Playfair
Lors de la sortie de ses travaux, Playfair était un pionnier de la
présentation graphique des données.
Cependant, certains choix de représentation ne sont plus admissible de
nos jours.
Dans cette section nous proposons des modifications pour mettre le
graphe de Playfair en adéquation avec les normes actuelles.
** Différenciation entre Prix et Salaires
Dans son graphe, Playfair combine "Shillings par quart de boisseau de
blé" et "Shillings par semaine" en une seule unité "Shillings", ce qui
n'est plus acceptable de nos jours.
Notre première modification du graphe de Playfair consistera donc à
différencier les unités "Shillings par quart de boisseau de blé" et
"Shillings par semaine" en utilisé deux axes distinct.
Pour ce faire nous utilisons simplement le paramètre /sec.axis/ de la
fonction /scale_y_continuous()/.
#+begin_src R :results output graphics :file (org-babel-temp-file "figure" ".png") :exports both :width 600 :height 400 :session *R*
ggplot(table, aes(x=Year)) +
geom_bar(aes(y=Wheat), stat="identity") +
geom_area(aes(y=Wages), stat="identity", fill="lightblue") +
geom_line(aes(y=Wages), stat="identity", color="red",size=2) +
ylab("Price of the Quarter of Wheat in Shillings") +
scale_y_continuous(
breaks=seq(0,100,5),
sec.axis=sec_axis(~.,
name="Weekly Wages in Shillings",
breaks=derive()
)
)+
scale_x_continuous(breaks=seq(min(table$Year),max(table$Year),10))+
theme(axis.text.x = element_text(angle=45)) +
ggtitle("Showing at one view the price of the quarter of Wheat and Wages of labour by the week")
#+end_src
#+RESULTS:
[[file:/tmp/babel-mdw4ds/figureuSpAnt.png]]
** Autres représentations graphiques
Mixer ensemble un /barplot/ et un /linechart/, mis à part dans des cas
très spécifiques, peut rendre compliquer la comparaison des données.
De nos jours, il est préférable d'utiliser le même type de
représentation graphique lors de la comparaison entre deux données.
Cependant, il nous faut dans un premier temps retravailler le format
de nos données à l'aide de la fonction /melt()/ de la librairie /reshape2/,
afin de rendre plus aisé leur représentation à l'aide de /ggplot/.
#+begin_src R :results output :session *R* :exports both
library(reshape2)
n_data <- melt(table, id.vars="Year", measure.vars=c("Wheat","Wages"))
summary(n_data)
#+end_src
#+RESULTS:
:
: Year variable value
: Min. :1565 Wheat:50 Min. : 5.00
: 1st Qu.:1625 Wages:50 1st Qu.: 7.90
: Median :1688 Median :27.25
: Mean :1688 Mean :26.86
: 3rd Qu.:1750 3rd Qu.:40.12
: Max. :1810 Max. :99.00
Une première représentation possible est d'utiliser des barres les
prix et pour les salaires, cela afin de rendre plus aisée leur
comparaison.
#+begin_src R :results output graphics :file (org-babel-temp-file "figure" ".png") :exports both :width 600 :height 400 :session *R*
ggplot(n_data, aes(x=Year, y=value, fill=variable)) +
geom_bar(stat="identity",position=position_dodge()) +
ylab("Price of the Quarter of Wheat in Shillings") +
scale_y_continuous(
breaks=seq(0,100,5),
sec.axis=sec_axis(~.,
name="Weekly Wages in Shillings",
breaks=derive()
)
)+
scale_x_continuous(breaks=seq(min(table$Year),max(table$Year),10)) +
theme(axis.text.x = element_text(angle=45))
#+end_src
#+RESULTS:
[[file:/tmp/babel-mdw4ds/figureyidnjM.png]]
Cependant, si cette représentation permet de comparer prix du blé et
salaire hedbomadaire, la prix du blé reste assez volatile et il est
compliqué d'observer l'évolution conjointe de ces deux données.
Pour ce faire nous allons plutôt utiliser une représentation par nuage
de points et régressions à l'aide des fonctions /geom_point()/ et
/geom_smooth()/.
#+begin_src R :results output graphics :file (org-babel-temp-file "figure" ".png") :exports both :width 600 :height 400 :session *R*
ggplot(n_data,aes(x=Year,y=value, color=variable)) +
geom_point() +
geom_smooth() +
ylab("Price of the Quarter of Wheat in Shillings") +
scale_y_continuous(
breaks=seq(0,100,5),
sec.axis=sec_axis(~.,
name="Weekly Wages in Shillings",
breaks=derive()
)
)+
scale_x_continuous(breaks=seq(min(table$Year),max(table$Year),10)) +
theme(axis.text.x = element_text(angle=45))
#+end_src
#+RESULTS:
[[file:/tmp/babel-mdw4ds/figurel1YOJe.png]]
Avec cette dernière représentation, nous pouvons observer une
augmentation quasi-linéaire des salaires depuis environ l'année
1700, ainsi qu'une diminution du prix du blé jusqu'à environ l'année
1750, ce qui peut laisser supposer à une augmentation du "pouvoir
d'achat" des ouvriers.
Cependant, nous pouvons aussi observer qu'à partir de 1750 (environ),
le prix du blé a augmenté de manière drastiquement plus rapidement que
les salaires hebdomadaire.
Cette observation remet quelque peu en question l'augmentation du
pouvoir d'achat des ouvriers décrite par William Playfair.
* Mise en évidence du pouvoir d'achat des ouvriers
Dans son étude, William Playfair souhaitait mettre en évidence
l'augmentation dans le temps du pouvoir d'achat des ouvriers.
Cependant, le pouvoir d'achat, définie comme "la quantité de blé qu'un
ouvrier peut acheter avec son salaire hebdomadaire", n'est pas une
quelque chose que l'on peut quantifier simplement en comparant
l'évolution du prix du blé et des salaires. Il nous faut donc la
calculer pour en avoir une meilleure appréciation.
Pour ce faire, nous allons ajouter une colonne /Qty/ à notre table qui
contiendra la quantité de blé (en Kg) qu'un ouvrier peut acheter avec
son salaire hebdomadaire, calculé à l'aide de la formule $Qty = Wages /
Wheat * 6.8$ (un quart de boisseau de blé équivalent, environ, à 6.8Kg).
#+begin_src R :results output :session *R* :exports both
table["Qty"] = table$Wages / table$Wheat * 6.8
summary(table)
#+end_src
#+RESULTS:
:
: Year Wheat Wages Qty
: Min. :1565 Min. :26.00 Min. : 5.000 Min. :0.5886
: 1st Qu.:1626 1st Qu.:32.25 1st Qu.: 6.145 1st Qu.:1.1088
: Median :1688 Median :40.25 Median : 7.800 Median :1.4316
: Mean :1688 Mean :42.14 Mean :11.582 Mean :1.9012
: 3rd Qu.:1749 3rd Qu.:45.75 3rd Qu.:14.875 3rd Qu.:2.7566
: Max. :1810 Max. :99.00 Max. :30.000 Max. :3.7238
Nous pouvons maintenant représenter l'évolution du pouvoir d'achat des
ouvriers au court du temps comme nous l'avons fait précédemment à
l'aide d'un nuage de points et d'un regression.
#+begin_src R :results output graphics :file (org-babel-temp-file "figure" ".png") :exports both :width 600 :height 400 :session *R*
ggplot(table, aes(x=Year, y=Qty)) +
geom_point() +
geom_smooth() +
scale_y_continuous(breaks=seq(0,5,0.25)) +
scale_x_continuous(breaks=seq(min(table$Year),max(table$Year),10)) +
ylab("Quantity of Wheat (Kg) purchasable with Weekly Wages") +
ggtitle("Buying power of labourers from 1565 to 1810") +
theme(
axis.text.x = element_text(angle=45),
plot.title = element_text(hjust = 0.5)
)
#+end_src
#+RESULTS:
[[file:/tmp/babel-mdw4ds/figurekVEer5.png]]
Nous pouvons voir sur ce graphique une nette augmentation du pouvoir
d'achat des ouvriers avec un pic aux alentours des années 1750 - 1770.
Cependant, nous pouvons aussi observer une diminution du pouvoir
d'achat à partir de ces années, ce qui peut s'expliquer par
l'augmentation drastique du prix du blé depuis 1750, comme observé
précedemment.
** Évolution des salaires en fonction du prix du blé
Une autre manière de représenter le pouvoir d'achat, peut se faire en
observant l'évolution du salaire par rapport au prix du blé à l'aide
d'un nuage de points.
Afin de ne pas perdre la progression du temps, nous colorons les
points en fonction de l'année associée. Les points les plus sombres
réprésentant les plus vieilles entrées et les points les plus clairs,
les plus récentes.
#+begin_src R :results output graphics :file (org-babel-temp-file "figure" ".png") :exports both :width 600 :height 400 :session *R*
ggplot(table, aes(x=Wheat,y=Wages)) +
geom_point(aes(colour=Year)) +
ylab("Weekly Wages in Shillings") +
xlab("Price of the Quarter of Wheat in Shillings") +
scale_y_continuous(breaks=seq(min(table$Wages),max(table$Wages),5)) +
scale_x_continuous(breaks=seq(min(table$Wheat),max(table$Wheat),5))+
ggtitle("Weekly Wages depending on the Price of Wheat, from 1565 to 1810") +
theme(plot.title = element_text(hjust = 0.5))
#+end_src
#+RESULTS:
[[file:/tmp/babel-mdw4ds/figure1OsMTj.png]]
Nous pouvons voir sur ce graphique que, à quelques exceptions pret, le prix
du quart de boisseau de blé reste entre 26 et 51 Shillings au court du
temps. Au contraire, le salaire hebdomadaire des ouvriers n'a fait
qu'augmenter au cours du temps, laissant supposer une augmentation du
pouvoir d'achat des ouvriers.