Preparació de dades

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.

In [1]:
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

Pas 1: llegir arxiu

In [2]:
original = pd.read_csv("data/input/20171101_actualitzat_llistat_Llei_11_2017.csv",delimiter=";",encoding="latin-1")

Un primer cop d'ull a les dades

In [3]:
# sexe "--" marca persones jurídiques

original.query("sexe != '--'").head()
Out[3]:
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

Pas 2: Canviar noms de columnes a identificadors permesos en Python

In [4]:
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

Pas 3: Canviar el format dels anys a data per automatitzar el càlcul dels eixos

In [5]:
# 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)

Primera anàlisi: els sumaríssims de més durada

In [6]:
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]
Out[6]:
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

Pas 4: Categoritzar penes

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
In [7]:
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))

Primera anàlisi: relació entre penes imposades i gènere

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%).

In [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 %'])
Out[8]:
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%

Pas 5: Categoritzar origen i residència

Categories:

  • b - Barcelona
  • c - Catalunya (fora de la província de Barcelona)
  • e - Espanya (fora de Catalunya)
  • i - internacional (fora d'Espanya)
  • ? - altres / no consta
In [9]:
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)

Primera anàlisi: Relació entre lloc de naixement i de residència

Aplicant les nostres categories, a primer cop d’ull es noten poques diferències entre homes i dones. Queda per investigar.

In [10]:
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.

In [11]:
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%}")
Out[11]:
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%

Pas 6: executades o no?

In [12]:
def cat_execut(a) :
    if str(a).find("executa") > -1 :
        return "exec"
    else :
        return "no exec"


original["af_cat"]=original["afusellades"].apply(cat_execut)

Primera análisi: Pena de mort i execucions

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.

In [13]:
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
Out[13]:
genere Dona Home sum
af_cat
exec 17 3345 3362
no exec 24 1031 1055
sum 41 4376 4417

Pas 7: Guardar dades processats

In [14]:
original.to_msgpack("data/processat.msg")

Primera anàlisi: Relaciò entre "Tipus procediment 1" i "Tipus procediment 2"

Trobem aquestes dues columnes de les dades originals difícils d'interpretar.

In [15]:
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(' ')
Out[15]:
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

Primera anàlisi: Relaciò entre "Tipus procediment 1" i "pena"

In [16]:
original.groupby(["pena_cat","proc_1_simple","genere"])["nom"].\
         count().\
         unstack("proc_1_simple").\
         unstack("genere").\
         fillna(0).\
         style.format("{:0g}")
       
Out[16]:
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