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()
Codi | cognoms nom | cognoms | nom | sexe | edat | Municipi naixement | Pedanies/Agregats naixement | Comarca naixement | Província naixement | ... | Tipus procediment 2 | num causa | any inicial | any aprovació sen o altra resol | pena | commutació/indult(demanat) | afusellades | ref num arxiu | autoria i data de la descripció | data correccio registre | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
17 | 135218 | ABAD ALFONSO, Erundina | ABAD ALFONSO | Erundina | Dona | 43.0 | Alcoi | -- | Alcoià | Alacant | ... | Sumaríssim | 030827 | 1942.0 | 1943.0 | Sobreseïment | NaN | NaN | 37729.0 | ANC 2017 07 12 | NaN |
18 | 25335 | ABAD ARBÓS, Ricardo | ABAD ARBÓS | Ricardo | Home | 30.0 | Barcelona | -- | Barcelonès | Barcelona | ... | -- | -- | 1939.0 | 1939.0 | Sense declaració de responsabilitats | NaN | NaN | 12842.0 | ANC 2017 07 12 | NaN |
19 | 123192 | ABAD BARAS, José | ABAD BARAS | José | Home | 30.0 | Benavarri | -- | Ribagorça | Osca | ... | Sumaríssim | 000940 | 1939.0 | 1939.0 | Absolt | NaN | NaN | 49476.0 | ANC 2017 07 12 | NaN |
20 | 171 | ABAD BATLLONE, Juan | ABAD BATLLONE | Juan | Home | 42.0 | Barcelona | -- | Barcelonès | Barcelona | ... | Diligències prèvies | -- | 1939.0 | 1939.0 | Sense declaració de responsabilitats | NaN | NaN | 4063.0 | ANC 2017 07 12 | NaN |
21 | 24485 | ABAD BOIRA, Ricardo | ABAD BOIRA | Ricardo | Home | 48.0 | Tauste | -- | -- | Saragossa | ... | Diligències prèvies | -- | 1941.0 | 1942.0 | Sense declaració de responsabilitats | NaN | NaN | 12915.0 | ANC 2017 07 12 | NaN |
5 rows × 29 columns
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]
cognoms_nom | any_inicial | any_resol | genere | pena | pais_naix | dura | |
---|---|---|---|---|---|---|---|
55258 | ROIG ALTADILL, Ramón | 1942-12-31 | 1974-12-31 | Home | Arxiu | Espanya | 11688 days |
3172 | ARCELUS MARTÍNEZ, Aurelio | 1942-12-31 | 1972-12-31 | Home | Sobreseïment | Espanya | 10958 days |
17551 | COT REVERTER, Juan | 1940-12-31 | 1969-12-31 | Home | Repatriació | Espanya | 10592 days |
19057 | DOLZ BES, José María | 1938-12-31 | 1966-12-31 | Home | Sobreseïment | Espanya | 10227 days |
49033 | PIÑOL TORT, León | 1941-12-31 | 1968-12-31 | Home | Sobreseïment | Espanya | 9862 days |
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 %'])
genere | Dona | Home | Dones % | Homes % |
---|---|---|---|---|
pena_cat | ||||
00 mort | 41 | 4376 | 0.7% | 6.9% |
01 30a+ | 119 | 3628 | 2.2% | 5.7% |
02 20-30a | 50 | 1155 | 0.9% | 1.8% |
03 12-20a | 856 | 18935 | 15.6% | 30.0% |
04 6-12a | 590 | 2378 | 10.7% | 3.8% |
05 6m-6a | 95 | 1673 | 1.7% | 2.6% |
06 <6m | 247 | 766 | 4.5% | 1.2% |
07 sob | 813 | 9382 | 14.8% | 14.8% |
08 lib | 2246 | 14404 | 40.8% | 22.8% |
09 alt | 445 | 6525 | 8.1% | 10.3% |
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%}")
cat_res | ? | b | c | e | i | |
---|---|---|---|---|---|---|
cat_naix | genere | |||||
b | Dona | 0.3% | 95.9% | 3.7% | 0.1% | nan% |
Home | 0.1% | 95.3% | 4.2% | 0.3% | 0.1% | |
c | Dona | 0.1% | 28.2% | 71.2% | 0.4% | 0.1% |
Home | 0.1% | 16.0% | 83.5% | 0.3% | 0.1% | |
e | Dona | 0.2% | 87.0% | 7.2% | 5.6% | 0.1% |
Home | 0.3% | 73.7% | 14.3% | 11.3% | 0.4% | |
i | Dona | 11.8% | 67.8% | 16.9% | 2.4% | 1.2% |
Home | 19.0% | 37.4% | 39.2% | 1.8% | 2.5% |
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
genere | Dona | Home | sum |
---|---|---|---|
af_cat | |||
exec | 17 | 3345 | 3362 |
no exec | 24 | 1031 | 1055 |
sum | 41 | 4376 | 4417 |
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(' ')
proc_1_simple | -- | Consells de guerra | Diligències prèvies |
---|---|---|---|
proc_2 | |||
-- | 3313 | 10696 | 4 |
Acord | 1 | ||
Actuacions | 9 | ||
Antecedents | 8 | ||
Auditoria | 2 | 3 | |
Causa | 1100 | ||
Causa acumulada | 965 | ||
Causa criminal | 59 | ||
Causa d'Oficials Generals | 14 | ||
Causa ordinària | 37 | 1975 | |
Causa sumaríssima | 3 | ||
Certificat | 1 | ||
Declaració jurada | 2 | ||
Denúncia | 1 | ||
Diligències | 3 | 118 | |
Diligències d'urgència | 1 | ||
Diligències de guàrdia | 2 | ||
Diligències governatives | 1 | ||
Diligències informatives | 2 | 1 | |
Diligències prèvies | 4181 | ||
Documentació | 6 | ||
Expedient | 236 | 55 | |
Expedient governatiu | 38 | ||
Expedient informatiu | 14 | ||
Expedient judicial | 15 | 29 | |
Expedient no judicial | 2 | ||
Informació | 11 | 1 | |
Informació continuada en causa | 1 | ||
Informe | 1 | ||
Informe judicial | 1 | ||
Informe no judicial | 2 | ||
Informes | 1 | ||
Instància de testimoni | 1 | ||
Liquidacions | 1 | ||
Procediment | 3 | 16 | |
Procediment acumulat | 6 | ||
Procediment ordinari | 1 | 7 | |
Procediment previ | 236 | ||
Sumari | 2 | ||
Sumaríssim | 2 | 46598 | |
Testimoni | 1 | ||
informacions | 1 |
original.groupby(["pena_cat","proc_1_simple","genere"])["nom"].\
count().\
unstack("proc_1_simple").\
unstack("genere").\
fillna(0).\
style.format("{:0g}")
proc_1_simple | -- | Consells de guerra | Diligències prèvies | ||||||
---|---|---|---|---|---|---|---|---|---|
genere | -- | Dona | Home | -- | Dona | Home | -- | Dona | Home |
pena_cat | |||||||||
00 mort | 0 | 0 | 1 | 0 | 41 | 4371 | 0 | 0 | 4 |
01 30a+ | 0 | 1 | 8 | 0 | 118 | 3617 | 0 | 0 | 3 |
02 20-30a | 0 | 0 | 2 | 0 | 50 | 1152 | 0 | 0 | 1 |
03 12-20a | 0 | 2 | 17 | 0 | 851 | 18881 | 0 | 3 | 37 |
04 6-12a | 0 | 2 | 5 | 0 | 588 | 2367 | 0 | 0 | 6 |
05 6m-6a | 0 | 0 | 25 | 0 | 95 | 1643 | 0 | 0 | 5 |
06 <6m | 0 | 48 | 78 | 0 | 186 | 640 | 0 | 13 | 48 |
07 sob | 0 | 4 | 128 | 5 | 789 | 9095 | 2 | 20 | 159 |
08 lib | 0 | 651 | 1772 | 0 | 1095 | 9307 | 7 | 500 | 3325 |
09 alt | 0 | 158 | 753 | 0 | 250 | 5425 | 2 | 37 | 333 |