Análisis de los Gastos de Representación del Ayuntamiento de Madrid, sacados de su portal de #OpenData del primer semestre 2017.
Como siempre comenzamos con la imporación de las librerías necesarias.
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import datetime
import matplotlib.dates as mdates
%matplotlib inline
import matplotlib.ticker as mtick
from matplotlib.ticker import FuncFormatter
String para referenciar la informacion al site de OpenData del Ayuntamiento de Madrid
fuente='Fuente : Ayuntamiento de Madrid, http://datos.madrid.es'
URL del fichero fuente :
path_web='http://datos.madrid.es/egobfiles/MANUAL/300058/Protocolarios%202017.csv'
Importamos los datos…
gastos=pd.read_csv(path_web,sep=";",encoding='windows-1250',index_col=False)
Veamos el formato que tienen :
gastos.columns
Index([‘APELLIDO 1’, ‘APELLIDO 2’, ‘NOMBRE’, ‘NUMTRANS’, ‘PUESTO’,
‘NOMBRE UNIDAD ADSCRIPCIÓN’, ‘NOMBRE AREA/JM/OOAA/EP’, ‘FECHA’,
‘MOTIVO’, ‘COMIDAS \nINSTITUCIONALES’, ‘PRODUCTOS \nALIMENTICIOS’,
‘FLORES’, ‘CATERING ‘, ‘TROFEOS DISTINCIONES’, ‘CONCEPTO’, ‘IMPORTE’,
‘Unnamed: 16′],
dtype=’object’)
gastos.head(2)
APELLIDO 1 | APELLIDO 2 | NOMBRE | NUMTRANS | PUESTO | NOMBRE UNIDAD ADSCRIPCIÓN | NOMBRE AREA/JM/OOAA/EP | FECHA | MOTIVO | COMIDAS INSTITUCIONALES |
PRODUCTOS ALIMENTICIOS |
FLORES | CATERING | TROFEOS DISTINCIONES | CONCEPTO | IMPORTE | Unnamed: 16 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | ARCE | LEGUA | ROMMY | 516203.0 | CONCEJAL/A PRESIDENTE/A DE DISTRITO | CONCEJAL PRESIDENTE JMD ARGANZUELA | JUNTA MUNICIPAL DEL DISTRITO DE ARGANZUELA | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1 | ARCE | LEGUA | ROMMY | 516203.0 | CONCEJAL/A PRESIDENTE/A DE DISTRITO | CONCEJAL PRESIDENTE JMD USERA | JUNTA MUNICIPAL DEL DISTRITO DE USERA | 19/04/2017 | Inauguración Semana del Libro en el Distrito d… | NaN | NaN | NaN | 715,00 | NaN | NaN | NaN | NaN |
Llenamos los campos N/A con ceros
gastos.fillna(0,inplace=True)
Eliminamos el separador de miles (‘.’) y cambiamos el decimal por (‘.’), ya que son los utilizados en Float de Python3
gastos['IMPORTE']=gastos['IMPORTE'].apply(lambda x: float( str(x).replace(',', '%temp%').replace('.', '').replace('%temp%', '.')))
Vemos una anomalía en el formato. Entendemos que cada fila es un gasto, del que tenemos los datos del empleado público que lo realizó fecha, motivo etc..Adicionalmente tenemos una serie de columnas en las que se describe el gasto : CATERING, FLORES; TROFEOS etc…Pero además nos encontramos con una columna ‘CONCEPTO’ y otra importe..
gastos[gastos['IMPORTE']!=0][['CONCEPTO','IMPORTE']]
CONCEPTO | IMPORTE | |
---|---|---|
14 | Obsequios protocolarios | 19.75 |
18 | Obsequios protocolarios | 399.30 |
22 | Obsequios protocolarios | 526.35 |
31 | Recital de guitarra | 605.00 |
33 | Servicio de Guías del Museo Reina Sofía | 332.75 |
47 | Obsequios protocolarios | 220.00 |
49 | Obsequios protocolarios | 110.00 |
53 | Obsequios protocolarios | 64.58 |
71 | Pago desplazamiento de Tania Balló para asisti… | 187.85 |
72 | Organización, coordinación y difusión rueda pr… | 211.75 |
93 | Velas | 40.00 |
Para tener datos con formato homogéneo movemos el contenido de la columna ‘CONCEPTO’ a cabececeras de columnas cuyo valor será la celda de ‘IMPORTE’ :
for x in gastos.index: if gastos.iloc[[x]]['CONCEPTO'].values[0]!=0: gastos.loc[x,gastos.iloc[[x]]['CONCEPTO'].values[0]]=gastos.iloc[[x]]['IMPORTE'].values[0]
gastos.columns
Index([‘APELLIDO 1’, ‘APELLIDO 2’, ‘NOMBRE’, ‘NUMTRANS’, ‘PUESTO’,
‘NOMBRE UNIDAD ADSCRIPCIÓN’, ‘NOMBRE AREA/JM/OOAA/EP’, ‘FECHA’,
‘MOTIVO’, ‘COMIDAS \nINSTITUCIONALES’, ‘PRODUCTOS \nALIMENTICIOS’,
‘FLORES’, ‘CATERING ‘, ‘TROFEOS DISTINCIONES’, ‘CONCEPTO’, ‘IMPORTE’,
‘Unnamed: 16’, ‘Obsequios protocolarios’, ‘Recital de guitarra’,
‘Servicio de Guías del Museo Reina Sofía’,
‘Pago desplazamiento de Tania Balló para asistir al acto de presentación a los medios de comunicación , dentro del Plan Memoria de Madrid, de un homenaje a las mujeres que formaron parte de la Generación del 27, en la Fundación José Ortega y Gasset-Gregori’,
‘Organización, coordinación y difusión rueda prensa música Semana Santa’,
‘Velas’],
dtype=’object’)
gastos.columns=['APELLIDO 1', 'APELLIDO 2', 'NOMBRE', 'NUMTRANS', 'PUESTO', 'NOMBRE UNIDAD', 'NOMBRE AREA', 'FECHA', 'MOTIVO', 'COMIDAS INSTITUCIONALES', 'PRODUCTOS ALIMENTICIOS', 'FLORES', 'CATERING', 'TROFEOS DISTINCIONES', 'CONCEPTO', 'IMPORTE', 'Unnamed: 16', 'Obsequios protocolarios', 'Recital de guitarra', 'Servicio de Guías del Museo Reina Sofía', 'Desp de Tania Balló', 'Rueda prensa música Semana Santa', 'Velas']
Para facilitar el trabajo definiremos una lista con las columnas relacionadas con Conceptos de gasto. Son columnas que tendrán un contenido numérico.
columnas_gastos=gastos.columns[[9,10,11,12,13,17,18,19,20,21,22]] columnas_gastos
Index([‘COMIDAS INSTITUCIONALES’, ‘PRODUCTOS ALIMENTICIOS’, ‘FLORES’,
‘CATERING’, ‘TROFEOS DISTINCIONES’, ‘Obsequios protocolarios’,
‘Recital de guitarra’, ‘Servicio de Guías del Museo Reina Sofía’,
‘Desp de Tania Balló’, ‘Rueda prensa música Semana Santa’, ‘Velas’],
dtype=’object’)
De igual manera a como antes hicimos cambiaremos el formato del separador de miles y decimal.
for columna in columnas_gastos[0:5]: gastos[columna]=gastos[columna].apply(lambda x: float( str(x).replace(',', '%temp%').replace('.', '').replace('%temp%', '.')))
Creamos un par de columnas auxilares, y formateamos correctamente la columna de Fechas :
– Una de ella con la concatenacion de Nombre (‘NOMBRE’) y primer Apellido (‘APELLIDO 1’)
– La otra con la suma de todas las columnas de gastos de la fila
gastos['NOM_APELL'] = gastos.apply(lambda x: ''.join([str(x['NOMBRE']),' ',str(x['APELLIDO 1'])]), axis=1)
En la web se aclara que : «Para facilitar el análisis comparativo de los gastos, figuran todos los titulares en activo en algún momento del periodo al que se refiere el fichero, sin que conste cantidad alguna cuando no se hubiese producido algún gasto.». En nuestro caso vamos a borar esas lineas con gastos a cero.
gastos['gasto_total']=gastos[columnas_gastos].sum(axis=1) gastos = gastos.drop(gastos[gastos.gasto_total==0].index)
<br />
gastos['FECHA']=pd.to_datetime(gastos['FECHA'],format='%d/%m/%Y')
Aseguramos que no hay celdas con N/A y eliminamos las columnas que no necesitamos
gastos.fillna(0,inplace=True)
del gastos['IMPORTE'] del gastos['CONCEPTO'] del gastos['NOMBRE'] del gastos['APELLIDO 1'] del gastos['APELLIDO 2']
Empezamos a calcular y a sacar los primeros resultados. ¿Cuánto es el total de gastos? y ¿Cuantas entradas tiene el fichero?
len(gastos)
92
total_gastos=gastos[columnas_gastos].sum().sum() print ("{0:,.2f} euros".format(total_gastos))
31,146.54 euros
Veamos el nombre, cargo y área de las personas nominadas en la lista :
tabla_personas=gastos[['NOM_APELL','PUESTO','NOMBRE AREA']].pivot_table(index=['NOM_APELL','PUESTO','NOMBRE AREA'],aggfunc='count') tabla_personas
NOM_APELL | PUESTO | NOMBRE AREA |
---|---|---|
CELIA MAYER | CONCEJAL/A DE GOBIERNO | AREA DE GOBIERNO DE CULTURA Y DEPORTES |
ESTHER GOMEZ | CONCEJAL/A PRESIDENTE/A DE DISTRITO | JUNTA MUNICIPAL DEL DISTRITO DE CARABANCHEL |
FRANCISCO PEREZ | CONCEJAL/A PRESIDENTE/A DE DISTRITO | JUNTA MUNICIPAL DEL DISTRITO DE VILLA DE VALLECAS |
FRANCISCO PÉREZ | CONCEJAL PRESIDENTE DE DISTRITO | JUNTA MUNICIPAL DEL DISTRITO PUENTE DE VALLECAS |
INES SABANES | CONCEJAL/A DE GOBIERNO | AREA DE GOBIERNO DE MEDIO AMBIENTE Y MOVILIDAD |
JOSE JAVIER BARBERO | CONCEJAL/A DE GOBIERNO | AREA DE GOBIERNO DE SALUD, SEGURIDAD Y EMERGENCIAS |
JOSE MANUEL CALVO | CONCEJAL/A DE GOBIERNO | AREA DE GOBIERNO DE DESARROLLO URBANO SOSTENIBLE |
MANUELA CARMENA | ALCALDE/SA | ALCALDIA |
CONCEJAL/A DE GOBIERNO | AREA DE GOBIERNO DE CULTURA Y DEPORTES | |
MARTA GOMEZ | CONCEJAL/A PRESIDENTE/A DE DISTRITO | JUNTA MUNICIPAL DEL DISTRITO DE BARAJAS |
JUNTA MUNICIPAL DEL DISTRITO DE SAN BLAS CANILLEJAS | ||
MAURICIO VALIENTE | CONCEJAL PRESIDENTE DE DISTRITO | JUNTA MUNICIPAL DEL DISTRITO DE CHAMARTIN |
TERCER/A TENIENTE DE ALCALDIA | PLENO | |
PABLO CESAR CARMONA | CONCEJAL/A PRESIDENTE/A DE DISTRITO | JUNTA MUNICIPAL DEL DISTRITO DE MORATALAZ |
ROMMY ARCE | CONCEJAL/A PRESIDENTE/A DE DISTRITO | JUNTA MUNICIPAL DEL DISTRITO DE USERA |
YOLANDA RODRIGUEZ | CONCEJAL/A PRESIDENTE/A DE DISTRITO | JUNTA MUNICIPAL DEL DISTRITO DE CIUDAD LINEAL |
Vemos como por ejemplo nuestra Alcaldesa reporta los gastos desde sus dos funciones :
– Alcaldesa
– Concejala de deportes
Calculemos los gastos presentados por cada una de las personas :
gastos_nombre=gastos.groupby(['NOM_APELL'])['gasto_total'] gastos_nombre.sum().sort_values(ascending=False)
NOM_APELL
MANUELA CARMENA 21831.73
MAURICIO VALIENTE 3789.25
CELIA MAYER 1021.60
PABLO CESAR CARMONA 893.75
ESTHER GOMEZ 796.00
ROMMY ARCE 715.00
JOSE JAVIER BARBERO 464.86
MARTA GOMEZ 423.06
FRANCISCO PÉREZ 319.00
YOLANDA RODRIGUEZ 250.24
JOSE MANUEL CALVO 233.05
FRANCISCO PEREZ 209.00
INES SABANES 200.00
Name: gasto_total, dtype: float64
Manuela Carmena, lógicamente asociado a la máxima posición en la jerarquia, tiene el volumen más alto de gasto de representación y protocolo. Bajo mi punto de vista es una señal de buena práctica corporativa. Veámoslo a continuación en una tabla, con referencia adicional al porcentaje sobre el gasto total :
pd_aux=gastos_nombre.sum().sort_values(ascending=False) width=.5 ind = np.arange(len(pd_aux)) fig = plt.figure(1, (10,7)) ax = fig.add_subplot(1,1,1) rects = ax.barh(ind,pd_aux.values, width, align='center',color='b', label='Euros') ax.set_title('Simple plot') ax.set_ylabel('Concepto de gasto',size=20) ax.set_xlabel('Euros',size=16) ax.set_yticks(ind) ax.set_yticklabels(['{:>20}'.format(x.strip()[:20]) for x in pd_aux.index], size=12,rotation=0,color='b') ax.invert_yaxis() ax.get_xaxis().set_major_formatter( matplotlib.ticker.FuncFormatter(lambda x,P: format(int(x), ','))) ax.set_xticks([x for x in range(0,25000,2000)]) ax.grid(axis='x') ax.set_title('Gasto por concepto') ax.legend(loc=5) fig.suptitle(fuente,size=20,x=1,y=0.01) for rect in rects: width = rect.get_width() plt.text(width,rect.get_y()+rect.get_height()/2 ,'%1.1f%%' % (100*width/total_gastos), size=16, ha='left', va='center') plt.show() fig.savefig('gastos_persona',bbox_inches = 'tight')
Calculemos ahora los gastos por posición y no por nombre :
gastos_depto=gastos.groupby(['NOMBRE UNIDAD'])['gasto_total'] gastos_depto.sum().sort_values(ascending=False)
NOMBRE UNIDAD
ALCALDE 21710.04
CONCEJAL PRESIDENTE JMD 2239.80
PLENO 1549.45
DELEGACION AREA DE GOBIERNO DE CULTURA Y DEPORTES 1143.29
CONCEJAL PRESIDENTE JMD MORATALAZ 893.75
CONCEJAL PRESIDENTE JMD CARABANCHEL 796.00
CONCEJAL PRESIDENTE JMD USERA 715.00
DELEGACION AREA DE GOBIERNO DE SALUD, SEGURIDAD,Y EMERGENCIAS 464.86
CONCEJAL PRESIDENTE JMD SAN BLAS CANILLEJAS 384.56
CONCEJAL PRESIDENTE JMD PUENTE DE VALLECAS 319.00
CONCEJAL PRESIDENTE JMD CIUDAD LINEAL 250.24
DELEGADO AREA DE GOBIERNO DE DESARROLLO URBANO SOSTENIBLE 233.05
CONCEJAL PRESIDENTE JMD VILLA DE VALLECAS 209.00
DELEGACION AREA DE GOBIERNO DE MEDIO AMBIENTE Y MOVILIDAD 200.00
CONCEJAL PRESIDENTE JMD BARAJAS 38.50
Name: gasto_total, dtype: float64
Vemos que como Alcaldesa Manuela Carmena tiene 21.710 €, muy poco menos que el total a su nombre. Veamos esos resultados en un gráfico, con porcentajes también para ver los números relativos
pd_aux=gastos_depto.sum().sort_values(ascending=False) N=5 width=.5 ind = np.arange(len(pd_aux)) fig = plt.figure(1, (10,7)) ax = fig.add_subplot(1,1,1) rects = ax.barh(ind,pd_aux.values, width, align='center',color='b', label='Miles de Euros') ax.set_title('Simple plot') ax.set_ylabel('Concepto de gasto',size=20) ax.set_xlabel('Acumulado miles de euros',size=16) ax.set_yticks(ind) ax.set_yticklabels(['{:>50}'.format(x.strip()[:50]) for x in pd_aux.index], size=12,rotation=0,color='b') ax.invert_yaxis() ax.get_xaxis().set_major_formatter( matplotlib.ticker.FuncFormatter(lambda x,P: format(int(x/1000), ','))) ax.set_xticks([x for x in range(0,24000,2000)]) ax.grid(axis='x') ax.set_title('Gasto por concepto') ax.legend(loc=5) fig.suptitle(fuente,size=20,x=1,y=0.01) for rect in rects: width = rect.get_width() plt.text(width,rect.get_y()+rect.get_height()/2 ,'%1.1f%%' % (100*width/total_gastos), size=16, ha='left', va='center') plt.show() fig.savefig('gastos_persona',bbox_inches = 'tight')
Otra tabla : distribución de gasto por concepto (los relacionados en columnas_gastos)
pd_aux=gastos[columnas_gastos].sum().sort_values(ascending=True) N=5 width=.5 ind = np.arange(len(pd_aux)) fig, ax = plt.subplots() rects = ax.barh(ind, pd_aux.values, width, align='center',color='b', label='Euros') ax.set_title('Simple plot') ax.set_ylabel('Concepto de gasto',size=20) ax.set_xlabel('Acumulado euros',size=16) ax.set_yticks(ind) ax.set_yticklabels(['{:>60}'.format(x.strip()[:60]) for x in pd_aux.index], size=12,rotation=0,color='b') #ax.invert_yaxis() ax.grid(axis='x') ax.set_title('Gasto por concepto') ax.legend(loc=4) fig.suptitle(fuente,size=10,x=1,y=-0.01) for rect in rects: width = rect.get_width() plt.text(width,rect.get_y()+rect.get_height()/2 ,'%1.1f%%' % (100*width/total_gastos), size=14, ha='left', va='center') plt.show() fig.savefig('gastos_euros_concepto',bbox_inches = 'tight')
A continuación veamos la distribución por eventos, es decir filtrando por los motivos incluidos en cada uno de los gastos. Hemos limitado, con el objetivo de que quede una gráfica legible, a 20 eventos. He incluido dos gráficas : la primera con los 20 eventos con mayor gasto y otra equivalente con los 20 con menor gasto.
gastos_motivo=gastos.groupby(['MOTIVO'])['gasto_total'] gastos_motivo.sum().sort_values(ascending=False)
MOTIVO
Adquisición de Llaves de Oro de la Villa, para su entrega al Presidente de la República Argentina D. Mauricio Macri y otra para stock para futuras visitas de Estado 3243.36
Atención protocolaria con motivo del Acto Jubilados del Ayuntamiento de Madrid 2016, celebrado en los Jardines de Cecilio Rodríguez 2970.00
Atención protocolaria con motivo de la entrega de medallas de Oro de la Ciudad 2805.00
Atención protocolaria con motivo de la Presentación Madrid en FIL 2017 (Feria Internacional del Libro de Guadalajara, México) bajo el lema «Ganarás la Luz» 1958.00
Atención protocolaria con motivo del acto de inauguración de la exposición de pintura municipal «La mirada de nuestro tiempo» 1169.74
Cóctel inauguración asignación nombre «Manuel Alonso Zapata» a sala exposiciones Centro Cultural Nicolás Salmerón. Asociaciones de Vecinos y Grupos Municipales del distrito. 1000.00
Cóctel inauguración Centro Socio Comunitario Colonias Históricas de Chamartín. Asociaciones de Vecinos y Grupos Municipales del distrito. 952.00
Atención protocolaria con motivo de la visita institucional de los participantes en el Digital Entreprise Show, Presidentes de las empresas Partner, Ceos, Country Manager y embajadores de Israel y Suecia, entre otros 949.41
Adquisición de obsequios para su entrega como atención institucional y protocolaria 925.65
Placa entregada con ocasión aniversario liberación campo de Mauthausen, en recuerdo y homenaje a los madrileńos que sufrieron los horrores de los campos de concentración nazi 907.50
Rosquillas para los centros municipales de mayores con motivo de las Fiestas de San Isidro 796.00
Inauguración Semana del Libro en el Distrito de Usera 715.00
Atención institucional y protocolaria con motivo de la celebración del Pleno de Adolescentes 686.40
Atención protocolaria celebrada con motivo de la visita institucional del Presidente de Ecuador, Excmo. Sr. Don Rafael Correa 660.00
Atención protocolaria de carácter institucional con motivo de la presencia en Madrid de alcaldes y autoridades de varios países, para asistir al Foro Mundial sobre las Violencias Urbanas y Educación para la Convivencia y la Paz 654.50
Recital de guitarra como atención protocolaria en el acto de inauguración del Jardín de los Combatientes de la Nueve, al que asistieron entre otros la Alcaldesa de París, Anne Hidalgo 605.00
Organización del acto de presentación de la programación musical de la edición 2017 de la Semana Santa, en la capilla del Museo de Historia 563.75
Adquisición de medallas de Oro de la Ciudad para su entrega en la Fiesta de San Isidro 540.53
Servicio de catering para acto de presentación a los medios de comunicación, dentro del Plan Memoria de Madrid, de un homenaje a las mujeres que formaron parte de la Generación del 27, en la Fundación José Ortega y Gasset-Gregorio Marańón 457.85
Adquisición de flores para el acto protocolario de inauguración del Jardín de los Combatientes de la Nueve, al que asistieron entre otros la Alcaldesa de París, Anne Hidalgo 432.00
Adquisición de medallas de oro, plata y bronce, para su entrega en el Concurso de Rosas Nuevas 333.96
Atención protocolaria a las autoridades invitadas asistentes al Foro Mundial sobre las Violencias Urbanas y Educación para la Convivencia y la Paz, celebrado el 21 de abril de 2017, consistente en un servicio de Guía en castellano y otro Guía en inglés pa 332.75
Desayuno sesión Foro Local de Moratalaz 330.00
Sesión Foro Local de Moratalaz 330.00
Atención protocolaria con motivo de la visita institucional de los integrantes de la Alegre Cofradía del Entierro de la Sardina, durante la Fiesta del Carnaval 2017 323.40
Atención protocolaria. Centros de flores, con motivo de la visita institucional del Presidente de Ecuador, Excmo. Sr. Don Rafael Correa 320.00
Ofrenda floral Estación del Pozo. Conmemoración 319.00
Comida ofrecida a los miembros del Comisionado de la Memoria Histórica 277.50
Atención protocolaria con motivo del pregón de la Fiesta de San Isidro 272.49
Atención protocolaria con motivo de la celebración el día 9 de mayo de 2017 en el Palacio de Cibeles, del I Encuentro de Municipios Madrileńos Comprometidos con el Refugio, en materia de acogida personas migrantes y refugiadas 250.02
…
Atención institucional y protocolaria, con motivo de la recepción en el Palacio de Cibeles al Real Madrid, como campeón de la Champios League 2017 110.00
Atención protocolaria con motivo de la visita institucional de la Asociación de Cámaras de Comercio Europeas, en la Sala de Madera del Palacio de Cibeles 106.26
Atención protocolaria con motivo de la recepción a un grupo de profesores y alumnos de la Fundación International Studies Miami, en la Sala de Madera del Palacio de Cibeles 94.78
Reunión con Director de Gabinete, Gerente Organismo Autonomo Madrid Salud, Subdirector General de Prevención y Promoción de la Salud y la Jefa de Servicio de Prevención y Promoción de Salud, para tratar el tema sobre reorientación del organismo Autónomo M 81.20
Gasto suplido por adquisición de flores para el acto protocolario de inauguración del Jardín de los Combatientes de la Nueve, al que asistieron entre otros la Alcaldesa de París, Anne Hidalgo (Grujeval SL) 75.00
Atención protocolaria con motivo de la visita institucional del Gobernador de San Petesburgo y su Delegación 73.49
Flores entregadas en Mauthausen, en recuerdo y homenaje a los madrileńos que sufrieron los horrores de los campos de concentración nazi 68.40
Reunión con Coordinador General de Seguridad y Emergencias, Director de Gabinete, Asesor, Sargento de Policia, para tratar el tema sobre la unidad de gestión por la diversidad 67.20
Atención protocolaria con motivo de la celebración en el Palacio de Cibeles, de un Encuentro de Mediación Escolar con Centros Educativos de Primaria y Secundaria 64.58
Comida ofrecida a especialistas en Derechos Humanos pertenecientes a la Universidad Autónoma y Complutense de Madrid 63.25
Atención protocolaria con motivo de la visita de miembros de la Asociación de Familiares de Víctimas del accidente del Yack42 54.54
Desayuno ofrecido a los miembros del Comisionado de la Memoria Histórica 49.15
Encuentro equipo de trabajo preparatorio Foro Local de Chamartín. Total 3 comensales 47.80
Atención protocolaria con motivo de la visita institucional del Canciller de México, a quien acompańaban la Embajadora de México en Espańa y una delegación de ese país 45.75
Entrega de velas para el acto de encendido de velas conmemorativas en el Día Internacional de Conmemoración Anual en Memoria de las Victimas del Holocausto 40.00
Con motivo del Día Internacional de la Mujer, el 8 de marzo, se obsequia con un clavel morado a todas las mujeres que asistan al Pleno del Distrito, que se celebra el mismo día 38.50
Atención protocolaria con motivo de la visita de una delegación de Israel, encabezada por el Alcalde de Tel Aviv, Mr. Ron Huldai y por el Embajador de ese país en Espańa, Mr. Daniel Kutner 37.95
Reunión con Coordinador General de Seguridad y Emergencias, Asesor, Director General de Policia Municipal; Inspector Jefe, Subinspector, Oficial Subinspección territorial de Villa de Vallecas, subinspector Territorial de Puente de Vallecas, Oficial Subins 32.00
Reunión con el Secretario General de Caritas Espańola, para tratar temas relacionados con el acceso a la salud de la población vulnerable 30.80
Reunión con estudiante para tratar tema sobre participación y problemas de botellón 25.00
Atención protocolaria con motivo de la visita de los familiares de D. Leopoldo López 24.50
Atención protocolaria con motivo de la visita institucional del Presidente de la Generalitat D. Carles Puigdemont y del Vicepresidente D. Oriol Junqueras 24.50
Reunión con experta en adicciones para tratar el tema sobre la problemática de las adicciones 23.60
Reunión con Director General de Seguridad de Madrid destino para tratar temas relativos a seguridad 22.30
Reunion con Concejal del Grupo Municipal PSOE para la realización de análisis político 20.30
Atención protocolaria a la Alcaldesa de Roma Dońa Virginia Raggi, al Palazzo Senatorio en Roma 19.75
Reunión con representante de Forum de Ciudadanos para la Paz para tratar temas relativos a la seguridad 19.00
Pegamento para la placa entregada con ocasión aniversario liberación campo de Mauthausen, en recuerdo y homenaje a los madrileńos que sufrieron los horrores de los campos de concentración nazi 15.80
Atención protocolaria con motivo de la cuestación contra el cáncer, organizada por la Asociación Espańola contra el Cáncer, ofreciéndose un desayuno a los integrantes de la mesa que se instaló en la Plaza de Cibeles 11.10
Café ofrecido a los participantes en el 1ş Encuentro en la Casa de Cisneros «Homenaje a Herman Heller» 8.85
Name: gasto_total, Length: 82, dtype: float64
pd_aux=gastos_motivo.sum().sort_values(ascending=False).head(20) N=5 width=.7 ind = np.arange(len(pd_aux)) fig = plt.figure(1, (30,30)) ax = fig.add_subplot(1,1,1) rects = ax.barh(ind,pd_aux.values, width, align='center',color='b', label='Euros') ax.set_ylabel('Concepto de gasto',size=30) ax.set_xlabel('Acumulado en euros',size=30) ax.set_yticks(ind) ax.set_yticklabels(['{:>100}'.format(x.strip()[:100]) for x in pd_aux.index], size=40,rotation=0,color='b') ax.invert_yaxis() ax.get_xaxis().set_major_formatter( matplotlib.ticker.FuncFormatter(lambda x,P: format(int(x), ','))) ax.set_xticks([x for x in range(0,4000,500)]) for item in (ax.get_xticklabels()): item.set_fontsize(35) ax.grid(axis='x') ax.set_title('Eventos',size=40) ax.legend(loc=5,fontsize=40) fig.suptitle(fuente,size=40,x=1,y=0.01) for rect in rects: width = rect.get_width() plt.text(width,rect.get_y()+rect.get_height()/2 ,'%1.1f%%' % (100*width/total_gastos), size=35, ha='left', va='center') plt.show() fig.savefig('gastos_evento',bbox_inches = 'tight')
pd_aux=gastos_motivo.sum().sort_values(ascending=False).tail(20) N=5 width=.7 ind = np.arange(len(pd_aux)) fig = plt.figure(1, (30,30)) ax = fig.add_subplot(1,1,1) rects = ax.barh(ind,pd_aux.values, width, align='center',color='b', label='Euros') ax.set_ylabel('Concepto de gasto',size=40) ax.set_xlabel('Acumulado en euros',size=40) ax.set_yticks(ind) ax.set_yticklabels(['{:>100}'.format(x.strip()[:100]) for x in pd_aux.index], size=40,rotation=0,color='b') ax.invert_yaxis() ax.get_xaxis().set_major_formatter( matplotlib.ticker.FuncFormatter(lambda x,P: format(int(x), ','))) ax.set_xticks([x for x in range(0,200,50)]) for item in (ax.get_xticklabels()): item.set_fontsize(40) ax.grid(axis='x') ax.set_title('Eventos',size=30) ax.legend(loc=5,fontsize=50) fig.suptitle(fuente,size=40,x=1,y=0.01) for rect in rects: width = rect.get_width() plt.text(width,rect.get_y()+rect.get_height()/2 ,'%1.1f%%' % (100*width/total_gastos), size=40, ha='left', va='center') plt.show() fig.savefig('gastos_evento',dpi=200,bbox_inches = 'tight')
Y veamos que se pueden limitar los gráficos a una persona en particular. Veamos aqui la misma serie anterior, pero filtrada para presentar sólo los datos de la Alcaldesa Carmena.
pd_aux=gastos[gastos['NOM_APELL']=='MANUELA CARMENA'][columnas_gastos].sum().sort_values(ascending=True) gastos_carmena=pd_aux.sum() N=5 width=.5 ind = np.arange(len(pd_aux)) fig, ax = plt.subplots() rects = ax.barh(ind, pd_aux.values, width, align='center',color='b', label='Euros') ax.set_title('Simple plot') ax.set_ylabel('Concepto de gasto',size=20) ax.set_xlabel('Acumulado euros',size=16) ax.set_yticks(ind) ax.set_yticklabels(['{:>60}'.format(x.strip()[:60]) for x in pd_aux.index], size=12,rotation=0,color='b') #ax.invert_yaxis() ax.grid(axis='x') ax.set_title('Gasto por concepto') ax.legend(loc=4) fig.suptitle(fuente,size=10,x=1,y=-0.01) for rect in rects: width = rect.get_width() plt.text(width,rect.get_y()+rect.get_height()/2 ,'%1.1f%%' % (100*width/gastos_carmena), size=14, ha='left', va='center') plt.show() fig.savefig('gastos_euros_concepto',bbox_inches = 'tight')
gastos_motivo=gastos[gastos['NOM_APELL']=='MANUELA CARMENA'].groupby(['MOTIVO'])['gasto_total'] pd_aux=gastos_motivo.sum().sort_values(ascending=False).head(30) width=.5 ind = np.arange(len(pd_aux)) fig = plt.figure(1, (30,30)) ax = fig.add_subplot(1,1,1) rects = ax.barh(ind,pd_aux.values, width, align='center',color='b', label='Euros') ax.set_ylabel('Concepto de gasto',size=40) ax.set_xlabel('Acumulado en euros',size=40) ax.set_yticks(ind) ax.set_yticklabels(['{:>100}'.format(x.strip()[:100]) for x in pd_aux.index], size=50,rotation=0,color='b') ax.invert_yaxis() ax.get_xaxis().set_major_formatter( matplotlib.ticker.FuncFormatter(lambda x,P: format(int(x), ','))) ax.set_xticks([x for x in range(0,4000,500)]) for item in (ax.get_xticklabels()): item.set_fontsize(40) ax.grid(axis='x') ax.set_title('Eventos',size=40) ax.legend(loc=5,fontsize=50) fig.suptitle(fuente,size=40,x=1,y=0.01) for rect in rects: width = rect.get_width() plt.text(width,rect.get_y()+rect.get_height()/2 ,'%1.1f%%' % (100*width/gastos_carmena), size=40, ha='left', va='center') plt.show() fig.savefig('gastos_evento',bbox_inches = 'tight')
gastos_motivo=gastos[gastos['NOM_APELL']=='MANUELA CARMENA'].groupby(['MOTIVO'])['gasto_total'] pd_aux=gastos_motivo.sum().sort_values(ascending=False).tail(30) N=5 width=.5 ind = np.arange(len(pd_aux)) fig = plt.figure(1, (30,30)) ax = fig.add_subplot(1,1,1) rects = ax.barh(ind,pd_aux.values, width, align='center',color='b', label='Euros') ax.set_ylabel('Concepto de gasto',size=40) ax.set_xlabel('Acumulado en euros',size=40) ax.set_yticks(ind) ax.set_yticklabels(['{:>100}'.format(x.strip()[:100]) for x in pd_aux.index], size=50,rotation=0,color='b') ax.invert_yaxis() ax.get_xaxis().set_major_formatter( matplotlib.ticker.FuncFormatter(lambda x,P: format(int(x), ','))) ax.set_xticks([x for x in range(0,500,50)]) for item in (ax.get_xticklabels()): item.set_fontsize(50) ax.grid(axis='x') ax.set_title('Eventos',size=40) ax.legend(loc=5,fontsize=40) fig.suptitle(fuente,size=40,x=1,y=0.01) for rect in rects: width = rect.get_width() plt.text(width,rect.get_y()+rect.get_height()/2 ,'%1.1f%%' % (100*width/gastos_carmena), size=40, ha='left', va='center') plt.show() fig.savefig('gastos_evento',bbox_inches = 'tight')
Se me ocurre preparar una gráfica como la anterior, pero categorizando los gastos según su concepto (de nuevo bajo columnas_gastos)
lista_ordenada=gastos.sort_values('gasto_total',ascending=False).head(20)
ind = np.arange(len(lista_ordenada)) fig = plt.figure(1, (30,30)) ax = fig.add_subplot(1,1,1) width=.5 suelo=0 for i in columnas_gastos: ax.barh(ind,lista_ordenada[i], width, align='center', label=i[0:30],left=suelo) suelo=suelo+lista_ordenada[i] #ax.set_ylabel('Concepto de gasto',size=50) ax.set_xlabel('Acumulado en euros',size=50) ax.set_yticks(ind) ax.set_yticklabels(['{:>100}'.format(x.strip()[:100]) for x in lista_ordenada['MOTIVO']], size=50,rotation=0,color='b') ax.invert_yaxis() ax.get_xaxis().set_major_formatter( matplotlib.ticker.FuncFormatter(lambda x,P: format(int(x), ','))) ax.set_xticks([x for x in range(0,4000,500)]) for item in (ax.get_xticklabels()): item.set_fontsize(50) ax.grid(axis='x') ax.set_title('Eventos',size=50) ax.legend(loc=4,fontsize=50) fig.suptitle(fuente,size=50,x=1,y=0.01) plt.show() fig.savefig('gastos_evento',bbox_inches = 'tight')
Para finalizar juguemos un poco con las fechas..
raw = gastos.sort_values('FECHA')['FECHA'] vals= gastos.sort_values('FECHA')['gasto_total'] fig, ax = plt.subplots() ax.plot_date(raw, vals) date_fmt = '%m-%y' date_formatter = mdates.DateFormatter(date_fmt) ax.xaxis.set_major_formatter(date_formatter) fig.autofmt_xdate() plt.show()
Vemos que hay un gasto del año pasado. Bien por la transparencia al haberse incluido, pero nos deja el gráfico descolocado!. Identifiquemosló para eliminarlo :
gastos[gastos['FECHA']<datetime.datetime.strptime('01/01/2017', "%d/%m/%Y")][['NOM_APELL','PUESTO','FECHA','MOTIVO','gasto_total']]
NOM_APELL | PUESTO | FECHA | MOTIVO | gasto_total | |
---|---|---|---|---|---|
67 | ESTHER GOMEZ | CONCEJAL/A PRESIDENTE/A DE DISTRITO | 2016-05-13 | Rosquillas para los centros municipales de may… | 796.0 |
print (gastos.loc[[67]]['MOTIVO'].values[0])
Rosquillas para los centros municipales de mayores con motivo de las Fiestas de San Isidro
Generemos de nuevo la gráfica eliminando esa entrada :
raw = gastos[gastos['FECHA']>datetime.datetime.strptime('01/01/2017','%d/%m/%Y')].sort_values('FECHA')['FECHA'] vals= gastos[gastos['FECHA']>datetime.datetime.strptime('01/01/2017','%d/%m/%Y')].sort_values('FECHA')['gasto_total'] #fig, ax = plt.subplots() fig = plt.figure(1, (12,7)) ax = fig.add_subplot(1,1,1) ax.plot_date(raw, vals) ax.tick_params(axis='x',length=10) ax.xaxis.set_major_locator(mdates.DayLocator(bymonthday=(1,10,20)) ) date_fmt ='%d-%m' ax.xaxis.set_major_formatter(mdates.DateFormatter(date_fmt)) fig.autofmt_xdate() plt.show()
Ahora queda una gráfica mucho más clara. Sólo por jugar un poco más con ella veamos la acumulación de gastos alrededor del 20 de Abril. Para ello filtramos los datos a los días entre el 18 y el 22 de April.
inicio=datetime.datetime.strptime('18/04/2017','%d/%m/%Y') final=datetime.datetime.strptime('22/04/2017','%d/%m/%Y') raw = gastos[(gastos['FECHA']>inicio) & (gastos['FECHA']<final)].sort_values('FECHA')['FECHA'] vals= gastos[(gastos['FECHA']>inicio) & (gastos['FECHA']<final)].sort_values('FECHA')['gasto_total'] #fig, ax = plt.subplots() fig = plt.figure(1, (10,7)) ax = fig.add_subplot(1,1,1) ax.plot_date(raw, vals) ax.tick_params(axis='x',length=10) ax.xaxis.set_major_locator(mdates.DayLocator(interval=1) ) date_fmt ='%d-%m' ax.xaxis.set_major_formatter(mdates.DateFormatter(date_fmt)) fig.autofmt_xdate() plt.show()
Efectivamente vemos que el día 20 se reportaron varios gastos. Identifiquémoslos en una tabla :
gastos[gastos['FECHA']==datetime.datetime.strptime('20/04/2017', "%d/%m/%Y")][['NOM_APELL','PUESTO','FECHA','MOTIVO','gasto_total']]
NOM_APELL | PUESTO | FECHA | MOTIVO | gasto_total | |
---|---|---|---|---|---|
28 | MANUELA CARMENA | ALCALDE/SA | 2017-04-20 | Adquisición de flores para el acto protocolari… | 432.00 |
29 | MANUELA CARMENA | ALCALDE/SA | 2017-04-20 | Gasto suplido por adquisición de flores para e… | 75.00 |
30 | MANUELA CARMENA | ALCALDE/SA | 2017-04-20 | Atención protocolaria con motivo de la visita … | 45.75 |
31 | MANUELA CARMENA | ALCALDE/SA | 2017-04-20 | Recital de guitarra como atención protocolaria… | 605.00 |
32 | MANUELA CARMENA | ALCALDE/SA | 2017-04-20 | Atención protocolaria de carácter instituciona… | 654.50 |
80 | YOLANDA RODRIGUEZ | CONCEJAL/A PRESIDENTE/A DE DISTRITO | 2017-04-20 | Acto Inauguración Jardín Combatientes de La Nu… | 120.00 |
87 | MAURICIO VALIENTE | CONCEJAL PRESIDENTE DE DISTRITO | 2017-04-20 | Cóctel inauguración Centro Socio Comunitario C… | 952.00 |
Hemos terminado…hemos visto como usar Python3, Pandas y MathPlotLib para importar una tabla de Datos Abiertos, ver el formato, realizar unos arreglos para preparala y empezar a sacar resultados presentándolos en modo tabla y gráficos. Reitero el agradecimiento al Ayuntamiento de Madrid por este ejercicio de transparencia.
He repasado los resultados varias veces. Si aun así detectan algún error ruego que me lo comuniquen (mharias@me.com) y lo subsanaré lo más urgente que pueda. Pido de antemano disculpas si encuentran algo incorrecto.
Debe estar conectado para enviar un comentario.