Preparació de dades per a Innovation and Human Rights.
En aquest notebook, convertim les dades originals a formats que es poden treballar mès fàcilment a Python, i anem mostrant petites anàlisis.
import pandas as pd
import numpy as np
import plydata as ply
import datetime
import yaml
from functools import lru_cache
ply.options.modify_input_data = True
original = pd.read_csv("data/input/20171101_actualitzat_llistat_Llei_11_2017.csv",delimiter=";",encoding="latin-1")
# sexe "--" marca persones jurídiques
original.query("sexe != '--'").head()
original >> ply.rename(
{'afusellades': 'afusellades',
'any_inicial': 'any inicial',
'any_resol': 'any aprovació sen o altra resol',
'ca_naix': 'Comunitat autònoma naixement',
'ca_res': 'Comunitat autònoma residència',
'codi': 'Codi',
'cognoms': 'cognoms',
'cognoms_nom': 'cognoms nom',
'com_naix': 'Comarca naixement',
'com_res': 'Comarca residència',
'correccio': 'data correccio registre',
'descr': 'autoria i data de la descripció',
'edat': 'edat',
'indult': 'commutació/indult(demanat)',
'mun_naix': 'Municipi naixement',
'mun_res': 'Municipi residència',
'nom': 'nom',
'num_causa': 'num causa',
'pais_naix': 'País naixement',
'pais_res': 'País residència',
'ped_naix': 'Pedanies/Agregats naixement',
'ped_res': 'Pedanies/Agregats residencia',
'pena': 'pena',
'proc_1': 'Tipus procediment 1',
'proc_2': 'Tipus procediment 2',
'prov_naix': 'Província naixement',
'prov_res': 'Província residència',
'ref_arxiu': 'ref num arxiu',
'genere': 'sexe'}
)
pass
# l'ús de lru_cache fa tot més ràpid, perquè cada any només ha de ser convertit a data una sola vegada
@lru_cache(maxsize=100)
def pd_year(n: float) :
try :
return pd.date_range(start=datetime.datetime(int(n),1,1),end=datetime.datetime(int(n),12,31),freq="Y")[0]
except (TypeError,ValueError,OverflowError) :
return n
original["any_inicial"] = original["any_inicial"].apply(pd_year)
original["any_resol"] = original["any_resol"].apply(pd_year)
dura = original.loc[:,["cognoms_nom","any_inicial","any_resol","genere","pena","pais_naix"]]
dura["dura"] = dura["any_resol"] - dura["any_inicial"]
dura.sort_values(["dura"],ascending=False).iloc[:5]
Aquestes categories Es deriven de l’Anexo de la Circular de Creación de las Comisiones de Examen de Penas del any 1940.
En alguns casos, les dades publicades són ambigües - per exemple quan la pena és de "Sobreseïment provisional, tres mesos d'arrest major i llibertat". En aquests casos, categoritzem com la pena més greu que es va imposar ("tres mesos"). Si queden dubtes, la categoria es "altres" - per exemple amb "Pena de multa, remissió o a disposició d'altres autoritats".
Cal tenir en compte també que el “sobreseïment” es podia produir també quan la persona havia mort durant la seva reclusió mentre esperava judici o en altres circumstàncies.
La relació entre les penes que consten a la base de dades original (etiquetes) i les categories analitzades està documentada a l'arxiu categories.yml.
categoria | descripció | |
---|---|---|
mort | pena de mort | |
30a+ | 30 anys i un dia a perpètua | |
20-30a | 20 anys i un dia a 30 anys | Reclusión Mayor |
12-20a | 12 anys i un día a 20 anys | Menor |
6-12a | 6 anys i un dia a 12 anys | Prisión Mayor |
6m-6a | 6 mesos i un dia a 6 anys | Menor |
<6m | fins 6 mesos | |
sob | sobreseïment | |
lib | sin pena | |
alt | altres |
penes_cat = yaml.load(open("data/input/categories.yml"))
ord_categories = { a[1]["nom"] : "%02d" % a[0] for a in enumerate(penes_cat["categories"]) }
categories_penes={ a["pena"] : "%s %s" % (ord_categories[a["categoria"]],a["categoria"])
for a in penes_cat["etiquetes"] }
original["pena_cat"] = original["pena"].apply(
lambda a: categories_penes.get(a,None))
Entre els homes, el grup més gran és el de condemnat a 12 - 20 anys (30.0%). Entre les dones, són les que queden en llibertat (40.8%).
penes = original.query("genere != '--'").\
groupby(["genere","pena_cat"])["pena_cat"].count().\
unstack("genere")
penes["Dones %"] = penes["Dona"].div(sum(penes["Dona"]))
penes["Homes %"] = penes["Home"].div(sum(penes["Home"]))
def highlight_max(s):
is_max = s == s.max()
return ['background-color:yellow' if v else '' for v in is_max]
penes.style.apply(highlight_max,axis=0).\
format("{:.1%}",subset=['Dones %','Homes %'])
Categories:
def cat_naix(cas) :
if cas.prov_naix == '--' and cas.pais_naix == '--' :
naix="?"
if cas.prov_naix == "Barcelona" :
naix="b"
elif cas.ca_naix == "Catalunya" :
naix="c"
elif cas.pais_naix == "Espanya" :
naix="e"
else:
naix="i"
return naix
def cat_res(cas) :
if cas.prov_res == '--' and cas.pais_res == '--' :
return "?"
if cas.prov_res == "Barcelona" :
res="b"
elif cas.ca_res == "Catalunya" :
res="c"
elif cas.pais_res.find("Espanya")>-1 :
res="e"
elif cas.pais_res.find("Sense domicili fix")>-1 :
res="e"
else :
res="i"
return res
original["cat_naix"]=original.apply(cat_naix,axis=1)
original["cat_res"]=original.apply(cat_res,axis=1)
Aplicant les nostres categories, a primer cop d’ull es noten poques diferències entre homes i dones. Queda per investigar.
naix_res = original.query("genere != '--'").\
groupby(["cat_naix","cat_res","genere"])["nom"].\
count().\
unstack("cat_res")
La taula mostra el percentatge entre totes les dones o tots els homes d'aquesta categoria de residència. Exemple: 28.2% de les dones (i 16.0% dels homes) nascudes a Catalunya fora de la província de Barcelona resideixen a la província de Barcelona.
naix_res = naix_res.div(naix_res.sum(axis=1),axis=0)
def highlight_max(s):
is_max = s == s.max()
return ['font-weight:bold' if v else '' for v in is_max]
naix_res.style.apply(highlight_max,axis=1,
subset=(pd.IndexSlice['c'],pd.IndexSlice['b'])).\
format("{:.1%}")
def cat_execut(a) :
if str(a).find("executa") > -1 :
return "exec"
else :
return "no exec"
original["af_cat"]=original["afusellades"].apply(cat_execut)
La majoria de les 41 dones condemnades a pena de mort no van ser executades. Entre els homes, una quarta part dels 4376 condemnats a mort no van ser executats segons les dades.
pena_mort = original.query("pena_cat == '00 mort'").\
groupby(["genere","af_cat"])["pena_cat"].count().\
unstack("genere")
pena_mort_sum=pena_mort.sum(axis=0)
pena_mort_sum.name="sum"
pena_mort = pena_mort.append(pena_mort_sum)
pena_mort["sum"] = pena_mort.sum(axis=1)
pena_mort
original.to_msgpack("data/processat.msg")
Trobem aquestes dues columnes de les dades originals difícils d'interpretar.
original["proc_1_simple"]=original["proc_1"].apply(lambda a: a.replace(" []",""))
original.groupby(["proc_2","proc_1_simple"])["nom"].count().unstack("proc_1_simple").fillna(' ')
original.groupby(["pena_cat","proc_1_simple","genere"])["nom"].\
count().\
unstack("proc_1_simple").\
unstack("genere").\
fillna(0).\
style.format("{:0g}")