Imports y globals

Imports

import pymongo
import pandas as pd
import json
import matplotlib.pyplot as plt
import networkx as nx
from NetworkUtils import draw_network

globals

dir_datos = 'd:/datos/licitaciones_compranet'
myclient = pymongo.MongoClient("mongodb://localhost:27017/")
mydb = myclient['dataton2019']

Funciones

Análisis de asociados

Contacpoints

Creación de la base

  • Creamos una base de datos que tenga identificado a cada punto de contacto.
  • Los puntos de contacto se obtienen a partir de los contratistas que tienen información o su dirección.
resultado = mydb.contrataciones.find({},  {'_id': 0, 'parties.contactPoint': 1, 'parties.roles': 1, 'parties.id': 1, 'parties.address': 1})
df_contactos = pd.DataFrame([{**p.get('contactPoint', ''), **p.get('address', ''), 'tenderer_id': p['id'] }
                             for x in resultado for p in x['parties'] if (p['roles'] in [['tenderer'], ['tenderer', 'supplier']]) &
                             ((bool(p.get('address', None))) | (bool(p.get('contactPoint', None))))])
df_contactos.to_pickle(f'{dir_datos}/tenderers_contacpoint.pkl')
df_contactos.head()
name email telephone streetAddress locality region postalCode countryName tenderer_id faxNumber
0 IRAM LIEVANOS VELAZQUEZ laroca.canino@gmail.com 52 722 093749 PASEO DE LA ASUNCION NO. 536 METEPEC MX-MEX 52148 MÉXICO E9C1C827AE1234CCF7AC4D9070BB597C NaN
1 NaN servillantas@prodigy.net.mx 10191684 JOSE MORAN 66 MIGUEL HIDALGO MX-CMX 11850 MÉXICO SCA031118BX7 NaN
2 NaN sportingautoreparaciones@gmail.com 55 56397681 55 54894622 PLUTARCO ELIAS CALLES No. 660. COL. SAN FRANCI... Iztacalco MX-CMX 08230 MÉXICO SAU0505307M9 NaN
3 EDGAR GUSTAVO TREJO KEMPER edgarg_kemper@hotmail.com; balcazar-sol@hotmai... 5543419836 CALZADA VALLEJO NUMERO 1020 AZCAPOTZALCO MX-CMX 02300 MÉXICO SCK070618C21 52 55 55873415 ext 201, 202, 203
4 Daniel Ernesto De la Fuente Barra daniel.delafuente@segurossura.com.mx 5519636830 BLVD ADOLFO LOPEZ MATEOS 2448 ALVARO OBREGON MX-CMX 01060 MÉXICO R&S811221KR6 57237999 Ext. 7965
  • De la base de datos de contrataciones seleccionamos los datos de contacto de los que han ganado licitaciones. Estos tiene datos como nombre de la persona de contacto, email, teléfono, número de fax, dirección y id del proveedor

Uso de la base

df_contactos = pd.read_pickle(f'{dir_datos}/tenderers_contacpoint.pkl')
df_contactos.head()
name email telephone streetAddress locality region postalCode countryName tenderer_id faxNumber
0 IRAM LIEVANOS VELAZQUEZ laroca.canino@gmail.com 52 722 093749 PASEO DE LA ASUNCION NO. 536 METEPEC MX-MEX 52148 MÉXICO E9C1C827AE1234CCF7AC4D9070BB597C NaN
1 NaN servillantas@prodigy.net.mx 10191684 JOSE MORAN 66 MIGUEL HIDALGO MX-CMX 11850 MÉXICO SCA031118BX7 NaN
2 NaN sportingautoreparaciones@gmail.com 55 56397681 55 54894622 PLUTARCO ELIAS CALLES No. 660. COL. SAN FRANCI... Iztacalco MX-CMX 08230 MÉXICO SAU0505307M9 NaN
3 EDGAR GUSTAVO TREJO KEMPER edgarg_kemper@hotmail.com; balcazar-sol@hotmai... 5543419836 CALZADA VALLEJO NUMERO 1020 AZCAPOTZALCO MX-CMX 02300 MÉXICO SCK070618C21 52 55 55873415 ext 201, 202, 203
4 Daniel Ernesto De la Fuente Barra daniel.delafuente@segurossura.com.mx 5519636830 BLVD ADOLFO LOPEZ MATEOS 2448 ALVARO OBREGON MX-CMX 01060 MÉXICO R&S811221KR6 57237999 Ext. 7965
df_contactos.shape
(563693, 10)
  • De todos los contratos encontramos 563693 puntos de contacto. Muchos de estos se repiten porque un contratista que ganó varias veces aparecerá como un contacto por cada contrato ganado.
  • Calculamos todas las combinaciones únicas de telefono y tenderer_id.
  • Luego verificamos si existen casos en los que varios tenderer_id comparten el:
    • teléfono: 700 casos en los que eso ocurre.
    • Email: 839 casos.
    • Nombre: 706 casos
    • Número de fax: 135 casos
    • Dirección de la calle: 172 casos
  • Todos estos son signos de sospecha.
  • En muchos casos hay cuentas de funcionarios públicos. Habría que verificar cuál es su papel.
  • La pregunta relevante es ¿Hay casos en los que contratistas que tienen contactos en común hayan participado en un mismo proceso de licitación?
variables_contacto = ['telephone', 'email', 'name', 'streetAddress', 'faxNumber']
casos = []
for var_duplicated in variables_contacto:
    # Encontramos todos los valores únicos de la variable de contacto y de tenderer_id
    dups_direccion = df_contactos.loc[lambda x: (~x.duplicated(subset=['tenderer_id', var_duplicated])) & (x[var_duplicated].notnull())]\
        .loc[lambda x: (x[var_duplicated].duplicated()) & (~x['name'].str[:22].eq('- (Cuenta administrada')), var_duplicated].unique()
    # Encontramos cuáles son los tenderers_id que comparten un mismo contacto
    tenderers_dup_id = [df_contactos.loc[lambda x: x[var_duplicated].eq(dup)].drop_duplicates(subset=['tenderer_id'])['tenderer_id'].tolist()
                   for dup in dups_direccion]
    # Buscamos los contratos en los que participaron los ids asociados
    queries_dup = [[{'parties.id': i} for i in x] for x in tenderers_dup_id]
    for q in queries_dup:
        resultado = list(mydb.contrataciones.find({'$and': q}, {'_id': 0, 'ocid': 1}))
        if resultado:
            tenderers_id = [x['parties.id'] for x in q]
            ocids = list({x['ocid'] for x in resultado})
            casos.append({'tenderer_ids': tenderers_id, 'contratos_ocid': ocids, 'variable': var_duplicated})
            print(q)
            
with open('datos/casos_colusion.json', 'w', encoding='utf8') as jsonfile:
    json.dump(casos, jsonfile)
  • El resultado que encontramos es que existen 571 casos de contratistas posiblemente relacionados en una misma licitación.
with open('datos/casos_colusion.json', 'r', encoding='utf8') as jsonfile:
    casos = json.load(jsonfile)
casos_ocid = list({c for cas in casos for c in cas['contratos_ocid']})
len(casos_ocid)
571
casos_contratos = list(mydb.contrataciones.find({'ocid': {'$in': casos_ocid}}))
len(casos_contratos)
619
datos_contrato = [{'titulo': c['contracts'][0]['title'],
                   'descr': c['contracts'][0].get('description', ''),
                   'valor': c['contracts'][0]['value']['amount'],
                  'dependencia_id': c['buyer']['id'],
                  'dependencia_nombre': c['buyer']['name'],
                  'uc_id': c['tender']['procuringEntity']['id'],
                  'uc_name': c['tender']['procuringEntity']['name'],
                   'ocid': c['ocid'],
                   'fecha': c['date'],
                  }
                  
                  for c in casos_contratos if c.get('contracts', None)]

df_datos_contratos = pd.DataFrame(datos_contrato).set_index('ocid')
df_datos_contratos.head()
titulo descr valor dependencia_id dependencia_nombre uc_id uc_name fecha
ocid
ocds-07smqs-1317308 Servicio Integral de Suministro, Mantenimiento... Servicio Integral de Suministro, Mantenimiento... 450000.00 CNBV-80 Comisión Nacional Bancaria y de Valores CNB950501PT6-006B00001 CNBV-Dirección General Adjunta de Adquisicione... 2017-03-29T05:13:19Z
ocds-07smqs-1367848 PRESTADOR DE SERVICIOS INTEGRALES PRESTADOR DE SERVICIOS INTEGRALES (HONORARIOS) 44542.62 SAGARPA-261 Secretaría de Agricultura, Ganadería, Desarrol... SAG010710V98-008000995 SAGARPA-Delegacion Chihuahua #008000995 2017-05-22T12:24:14Z
ocds-07smqs-1430619 CONTRATACIÓN ABIERTA DEL SERVICIO DE LECTURA E... CONTRATACIÓN ABIERTA DEL SERVICIO DE LECTURA E... 220000.00 SEP-265 Secretaría de Educación Pública SEP210905778-011000999 SEP-Dirección de Adquisiciones #011000999 2017-07-20T06:22:43Z
ocds-07smqs-1444924 SERVICIO DE MANTENIMIENTO CORRECTIVO AL SISTEM... SERVICIO DE MANTENIMIENTO CORRECTIVO AL SISTEM... 287780.00 CONAGUA-94 Comisión Nacional del Agua CNA890116SF2-016B00009 CONAGUA-Gerencia de Resursos Materiales #016B0... 2017-08-03T01:58:53Z
ocds-07smqs-1452158 SERVICIO DE DIFUSIÓN EN MEDIOS DIGITALES DE LA... SERVICIO DE DIFUSIÓN EN MEDIOS DIGITALES DE LA... 68950.00 CONUEE-98 Comisión Nacional para el Uso Eficiente de la ... CNU800928K31-018E00999 CONUEE-Dirección de Recursos Materiales y Serv... 2017-08-30T04:21:41Z
casos_contratos[0]
{'_id': ObjectId('5dcdb0c10d84ead5c49d2e99'),
 'publisher': {'uid': '27511',
  'name': 'SECRETARÍA DE LA FUNCIÓN PÚBLICA',
  'uri': 'http://www.gob.mx/sfp'},
 'cycle': 2017,
 'ocid': 'ocds-07smqs-1317308',
 'id': 'SFP-1317308-2018-11-12',
 'date': '2017-03-29T05:13:19Z',
 'tag': ['tender', 'award'],
 'initiationType': 'tender',
 'parties': [{'name': 'Comisión Nacional Bancaria y de Valores',
   'id': 'CNBV-80',
   'roles': ['buyer']},
  {'name': 'CNBV-Dirección General Adjunta de Adquisiciones y Contratos #006B00001',
   'id': 'CNB950501PT6-006B00001',
   'identifier': {'id': 'CNB950501PT6-006B00001',
    'legalName': 'CNBV-Dirección General Adjunta de Adquisiciones y Contratos #006B00001',
    'scheme': 'MX-RFC',
    'uri': 'https://portalsat.plataforma.sat.gob.mx/ConsultaRFC'},
   'address': {'streetAddress': 'Av. Insurgentes Sur No. 1971, Torre Sur, Piso 6, Col. Guadalupe Inn',
    'locality': 'Álvaro Obregón',
    'region': 'Ciudad de México',
    'postalCode': '01020',
    'countryName': 'MX'},
   'contactPoint': {'name': 'Jannet Miriam Martínez Sánchez',
    'email': 'jmartinezs@cnbv.gob.mx',
    'telephone': '1454-6537 y 1454-6538'},
   'roles': ['procuringEntity']},
  {'name': 'MARIANA REGALADO SOBERON',
   'id': '3CAB041C0551441CB0A31EAC594B2339',
   'identifier': {'id': '3CAB041C0551441CB0A31EAC594B2339',
    'legalName': 'MARIANA REGALADO SOBERON',
    'scheme': 'MX-RFC',
    'uri': 'https://portalsat.plataforma.sat.gob.mx/ConsultaRFC'},
   'address': {},
   'contactPoint': {},
   'roles': ['tenderer']},
  {'name': 'GRUPO SANMARI SA DE CV',
   'id': 'GSA0310175N4',
   'identifier': {'id': 'GSA0310175N4',
    'legalName': 'GRUPO SANMARI SA DE CV',
    'scheme': 'MX-RFC',
    'uri': 'https://portalsat.plataforma.sat.gob.mx/ConsultaRFC'},
   'address': {'streetAddress': 'AZTECAS 81 LA ROMANA',
    'locality': 'Tlalnepantla de Baz',
    'region': 'MX-MEX',
    'postalCode': '54050',
    'countryName': 'MÉXICO'},
   'contactPoint': {'email': 'rafael@sanmari.com.mx',
    'telephone': '55-52409421'},
   'roles': ['tenderer']},
  {'name': 'HECTOR MANUEL SEGURA TORRE',
   'id': 'E2E9D6DA235621FC08C1A0EFC4201B95',
   'identifier': {'id': 'E2E9D6DA235621FC08C1A0EFC4201B95',
    'legalName': 'HECTOR MANUEL SEGURA TORRE',
    'scheme': 'MX-RFC',
    'uri': 'https://portalsat.plataforma.sat.gob.mx/ConsultaRFC'},
   'address': {},
   'contactPoint': {},
   'roles': ['tenderer']},
  {'name': 'GABRIEL DEL POZO RUIZ',
   'id': 'AA2EEEF597460501F7B8A50B4DE1F671',
   'identifier': {'id': 'AA2EEEF597460501F7B8A50B4DE1F671',
    'legalName': 'GABRIEL DEL POZO RUIZ',
    'scheme': 'MX-RFC',
    'uri': 'https://portalsat.plataforma.sat.gob.mx/ConsultaRFC'},
   'address': {'streetAddress': 'CEIBAS 45',
    'locality': 'NAUCALPAN DE JUAREZ',
    'region': 'MX-MEX',
    'postalCode': '53240',
    'countryName': 'MÉXICO'},
   'contactPoint': {'name': 'GABRIEL DEL POZO RUIZ',
    'email': 'mascontrolmenoscosto@yahoo.com.mx',
    'telephone': '525536259819'},
   'roles': ['tenderer', 'supplier']}],
 'buyer': {'name': 'Comisión Nacional Bancaria y de Valores', 'id': 'CNBV-80'},
 'tender': {'id': '1317308',
  'title': 'Servicio Integral de Suministro, Mantenimiento Plantas y Macetas',
  'description': 'Servicio Integral de Suministro, Mantenimiento y Conservación de Plantas Naturales y Macetas Propiedad de la CNBV',
  'status': 'complete',
  'procuringEntity': {'name': 'CNBV-Dirección General Adjunta de Adquisiciones y Contratos #006B00001',
   'id': 'CNB950501PT6-006B00001'},
  'items': [{'id': '7044016',
    'description': 'Contratación de una Póliza de Seguro de Accidentes Personales para la protección de los participantes en acciones de capacitación del Programa de Apoyo al Empleo 2016.',
    'classification': {'id': '33900006',
     'description': 'Servicios de seguros de gastos medicos mayores'},
    'quantity': 1,
    'unit': {'name': 'Servicio'}}],
  'value': {'amount': 0},
  'procurementMethod': 'direct',
  'procurementMethodRationale': 'Art. 42 párrafo primero',
  'submissionMethod': ['electronicSubmission'],
  'tenderPeriod': {'startDate': '2017-03-29T05:13:19Z'},
  'enquiryPeriod': {'startDate': '2017-03-29T05:13:19Z'},
  'hasEnquiries': False,
  'awardPeriod': {'endDate': '2017-03-30T00:00:00Z'},
  'numberOfTenderers': 4,
  'tenderers': [{'name': 'MARIANA REGALADO SOBERON',
    'id': '3CAB041C0551441CB0A31EAC594B2339'},
   {'name': 'GRUPO SANMARI SA DE CV', 'id': 'GSA0310175N4'},
   {'name': 'GABRIEL DEL POZO RUIZ', 'id': 'AA2EEEF597460501F7B8A50B4DE1F671'},
   {'name': 'HECTOR MANUEL SEGURA TORRE',
    'id': 'E2E9D6DA235621FC08C1A0EFC4201B95'}]},
 'language': 'es',
 'awards': [{'id': '1399908',
   'title': 'Servicio Integral de Suministro, Mantenimiento Plantas y Macetas',
   'description': 'Servicio Integral de Suministro, Mantenimiento y Conservación de Plantas Naturales y Macetas Propiedad de la CNBV',
   'status': 'active',
   'value': {'amount': 450000, 'currency': 'MXN'},
   'suppliers': [{'name': 'GABRIEL DEL POZO RUIZ',
     'id': 'AA2EEEF597460501F7B8A50B4DE1F671'}],
   'items': [{'id': '4645830',
     'description': 'Servicio Integral de Suministro, Mantenimiento Plantas y Macetas',
     'classification': {'scheme': 'CUCOP: Clasificador Único de las Contrataciones Públicas',
      'id': '35900004',
      'description': 'Servicios de jardineria',
      'uri': 'https://compranetinfo.funcionpublica.gob.mx/descargas/CUCOP.xlsx'},
     'quantity': 1,
     'unit': {'name': 'Servicio',
      'value': {'amount': 450000, 'currency': 'MXN'}}}],
   'contractPeriod': {'startDate': '2017-04-14T09:00:00Z',
    'endDate': '2018-06-18T03:59:00Z'}}],
 'contracts': [{'id': 1399908,
   'awardID': '1399908',
   'title': 'Servicio Integral de Suministro, Mantenimiento Plantas y Macetas',
   'description': 'Servicio Integral de Suministro, Mantenimiento y Conservación de Plantas Naturales y Macetas Propiedad de la CNBV',
   'status': 'terminated',
   'period': {'startDate': '2017-04-14T09:00:00Z',
    'endDate': '2018-06-18T03:59:00Z'},
   'value': {'amount': 450000, 'currency': 'MXN'},
   'items': [{'id': '4645830',
     'description': 'Servicio Integral de Suministro, Mantenimiento Plantas y Macetas',
     'classification': {'id': '35900004',
      'description': 'Servicios de jardineria'},
     'quantity': 1,
     'unit': {'name': 'Servicio',
      'value': {'amount': 450000, 'currency': 'MXN'}}}]}]}
participantes_contrato = {c['ocid']: [p['id'] for p in c['parties'] if p['roles'] in [['tenderer'], ['tenderer', 'supplier']]] for c in casos_contratos}
# Número de particpantes que estaban asociados en cada contrato
asociados_contrato = {o: c['tenderer_ids'] for c in casos for o in c['contratos_ocid']}
# ganador contrato
ganadores_contrato = {c['ocid']: [p['id'] for p in c['parties'] if p['roles']==['tenderer', 'supplier']] for c in casos_contratos}
# dataframe
df_asoc = pd.DataFrame([participantes_contrato, asociados_contrato, ganadores_contrato]).T\
    .rename(columns={0: 'part', 1: 'asoc', 2: 'gana'})\
    .assign(N_part=lambda x: x['part'].str.len(),
            N_asoc=lambda x: x['asoc'].str.len(),
            N_gana=lambda x: x['gana'].str.len(),
            prop_asoc_part=lambda x: x['N_asoc'].div(x['N_part']),
            part_mayo=lambda x: x['prop_asoc_part'].ge(0.5),
            asoc_ganadores=lambda x: x.apply(lambda y: list(set(y['gana']).intersection(set(y['asoc']))), axis=1),
            N_asoc_ganadores=lambda x: x['asoc_ganadores'].str.len(),
            part_nogana=lambda x: x.apply(lambda y: list(set(y['part']).difference(set(y['gana']))), axis=1))\
            .join(df_datos_contratos)
df_asoc.to_pickle(f'{dir_datos}/df_asociados.pkl')
df_asoc.head()
part asoc gana N_part N_asoc N_gana prop_asoc_part part_mayo asoc_ganadores N_asoc_ganadores part_nogana titulo descr valor dependencia_id dependencia_nombre uc_id uc_name fecha
ocds-07smqs-1043398 [TME840315KT6, BD03FBE666C3DBA5C57BCDC8BF0AA451] [TME840315KT6, BD03FBE666C3DBA5C57BCDC8BF0AA451] [TME840315KT6, BD03FBE666C3DBA5C57BCDC8BF0AA451] 2 2 2 1.000000 True [BD03FBE666C3DBA5C57BCDC8BF0AA451, TME840315KT6] 2 [] SERVICIO MPLS ATRAVES DE UN ENLACE DEDICADO CO... 169133.00 CIJ-66 Centros de Integración Juvenil, A.C. CIJ731003QK3-012M7K001 CIJ-Departamento de Adquisiciones #012M7K001 2016-04-18T12:02:38Z
ocds-07smqs-1193763 [MLA840208FN5, D73016CAA1F8020E3BAC52068FB0B2D... [D73016CAA1F8020E3BAC52068FB0B2D9, MLA840208FN5] [MLA840208FN5, D73016CAA1F8020E3BAC52068FB0B2D... 4 2 4 0.500000 True [MLA840208FN5, D73016CAA1F8020E3BAC52068FB0B2D9] 2 [] ADQ. DE VIVERES PARA EJERCICIO 2017 ADQ. DE VIVERES PARA EJERCICIO 2017 3880739.50 IMSS-192 Instituto Mexicano del Seguro Social IMS421231I45-050GYR045 IMSS-UMAE Hospital de Especilidades No.71 Dept... 2016-12-09T05:26:28Z
ocds-07smqs-1224403 [89E87098891F04A46318B7F775AD5E48, FAR100921AL... [D73016CAA1F8020E3BAC52068FB0B2D9, MLA840208FN5] [D73016CAA1F8020E3BAC52068FB0B2D9, 9D3346ADF0B... 8 2 5 0.250000 False [MLA840208FN5, D73016CAA1F8020E3BAC52068FB0B2D9] 2 [FAR100921ALA, 89E87098891F04A46318B7F775AD5E4... AA-019GYR026-E221-2016 DESIERTAS VIVERES 671930.69 IMSS-192 Instituto Mexicano del Seguro Social IMS421231I45-050GYR026 IMSS-Coordinación de abastecimiento y equipami... 2016-12-02T05:49:52Z
ocds-07smqs-1240190 [RDO070228V11, ATD061228L34, MEX0301141G6] [RDO070228V11, ATD061228L34] [MEX0301141G6] 3 2 1 0.666667 True [] 0 [RDO070228V11, ATD061228L34] SERVICIO DE RESGUARDO, CUSTODIA, TRASLADO, ENV... SERVICIO DE RESGUARDO, CUSTODIA, TRASLADO, ENV... 116379.72 CPTM-109 Consejo de Promoción Turística de México, S.A.... CPT991022DE7-021W3J001 CPTM-Gerencia de Adquisiciones y Licitaciones ... 2016-12-20T06:52:52Z
ocds-07smqs-1241959 [CGE130930JV2, CDA9601297G9, 23DF515587ED8B3F4... [CDA9601297G9, 23DF515587ED8B3F4A8B1C9E4D725CAD] [] 3 2 0 0.666667 True [] 0 [CGE130930JV2, 23DF515587ED8B3F4A8B1C9E4D725CA... NaN NaN NaN NaN NaN NaN NaN NaN
df_asoc = pd.read_pickle(f'{dir_datos}/df_asociados.pkl')
  • ¿En cuántos de estos casos los contratistas representaban el 50% de los proponentes o más?
print('Los contratistas representaban el 50% de los proponentes o más en', df_asoc.part_mayo.sum(), 'licitaciones')
Los contratistas representaban el 50% de los proponentes o más en 212 licitaciones
  • ¿En cuántos de estos casos los asociados fueron los únicos proponentes?
print('¿En cuántos de estos casos los asociados fueron los únicos proponentes?', df_asoc.prop_asoc_part.eq(1).sum(), 'licitaciones')
¿En cuántos de estos casos los asociados fueron los únicos proponentes? 41 licitaciones
  • De estos casos ¿en cuántas licitaciones los que estaban relacionados ganaron un concurso?
print('En', df_asoc.N_asoc_ganadores.gt(0).sum(), 'licitaciones ganó al menos uno de los contratistas asociados')
En 370 licitaciones ganó al menos uno de los contratistas asociados
  • ¿Cuántos contratistas asociados recibieron un contrato?
print(df_asoc.N_asoc_ganadores.sum(), ' contratistas asociados ganaron una licitación')
552  contratistas asociados ganaron una licitación
  • ¿En qué dependencias, unidades compradoras y servidores públicos ocurre más esto?
df_asoc.groupby(['uc_name'])['part'].count().sort_values(ascending=False)
uc_name
CONALITEG-Dirección de Recursos Materiales y Servicios Generales #011L6J001                                             33
IMSS-Departamento de Adquisición de Bienes y Contratación de Servicios #050GYR033                                       16
IMSS-Coordinación de Abastecimiento y Equipamiento #050GYR009                                                           10
IMSS-Coordinación de Adquisición de Bienes y Contratación de Serv, Dirección de Administración #050GYR047                9
INER-Departamento de Adquisiciones #012NCD001                                                                            9
                                                                                                                        ..
IMSS-UMAE HOSPITAL DE GINECO OBSTETRICIA No 03 DR VICTOR MANUEL ESPINOSA DE LOS REYES SANCHEZ CMN LA RAZA #050GYR050     1
IMSS-Coord. de Abastecimiento y Equipamiento Deleg. Ver. Sur #050GYR022                                                  1
SCT-Centro SCT Chihuahua #009000980                                                                                      1
SCT-CENTRO SCT EN CHIAPAS SUBDIRECCION DE ADMINISTRACION #009000992                                                      1
Tribunales Agrarios-Dirección General de Recursos Materiales #031000001                                                  1
Name: part, Length: 218, dtype: int64
df_asoc.groupby(['dependencia_nombre'])['part'].count().sort_values(ascending=False)
dependencia_nombre
Instituto Mexicano del Seguro Social                                          215
Comisión Nacional de Libros de Texto Gratuitos                                 33
Instituto de Seguridad y Servicios Sociales de los Trabajadores del Estado     32
Comisión Federal de Electricidad                                               24
Comisión Nacional del Agua                                                     15
                                                                             ... 
Hospital Regional de Alta Especialidad de Oaxaca                                1
Exportadora de Sal, S.A. de C.V.                                                1
El Colegio de la Frontera Sur                                                   1
Corporación Mexicana de Investigación en Materiales, S.A. de C.V.               1
Administración Portuaria Integral de Progreso, S.A. de C.V.                     1
Name: part, Length: 92, dtype: int64

Crea red para visualizar

nodos = []
red = 1
for c, vals in df_asoc.iterrows():
    nodos.append({'id': c, 'tipo': 'contrato'})
    for p in vals['part_nogana']:
        nodos.append({'id': p, 'tipo': 'tenderer'})
        links.append({'origen_id': p, 'destino_id': c, 'accion': 'participa', 'red': red})
    for p in vals['gana']:
        nodos.append({'id': p, 'tipo': 'supplier'})
        links.append({'origen_id': p, 'destino_id': c, 'accion': 'gana', 'red': red})
    
    for p1 in vals['asoc']:
        for p2 in vals['asoc']:
            if p1!=p2:
                links.append({'origen_id': p1, 'destino_id': p2, 'accion': 'asociado', 'red': red})
        
    nodos.append({'id': vals['uc_id'], 'tipo': 'uc'})
    links.append({'origen_id': vals['uc_id'], 'destino_id': c, 'accion': 'compra', 'red': red})
    red+=1
df_nodos = pd.DataFrame(nodos)\
    .assign(num=lambda x:x.index)
dicc_nodo_num = {v:k for k,v in df_nodos['id'].to_dict().items()}
df_links = pd.DataFrame(links)\
    .assign(origen_num=lambda x: x['origen_id'].map(dicc_nodo_num),
           destino_num=lambda x: x['destino_id'].map(dicc_nodo_num))\
    .dropna()
df_links.head()
origen_id destino_id accion red origen_num destino_num
25696 TME840315KT6 ocds-07smqs-1043398 gana 1.0 287 0
25697 BD03FBE666C3DBA5C57BCDC8BF0AA451 ocds-07smqs-1043398 gana 1.0 286 0
25698 TME840315KT6 BD03FBE666C3DBA5C57BCDC8BF0AA451 asociado 1.0 287 286
25699 BD03FBE666C3DBA5C57BCDC8BF0AA451 TME840315KT6 asociado 1.0 286 287
25700 CIJ731003QK3-012M7K001 ocds-07smqs-1043398 compra 1.0 284 0
df_nodos.to_csv('datos/asociados_nodos.csv', index=False)
df_links.to_csv('datos/asociados_links.csv', index=False)

Visualziacion networkX

df_nodos_graph = df_nodos.set_index('id')
for red in df_links.red.unique():
    G = nx.from_pandas_edgelist(df_links.query('red==@red'), source='origen_id', target='destino_id', edge_attr=['accion'])
    dicc_color_edges = {'gana': 'green', 'asociado': 'red', 'participa': '#3292a8', 'compra': 'orange'}
    dicc_color_nodos = {'contrato': '#3292a8', 'supplier': 'pink', 'tenderer': 'blue', 'uc': 'orange'}
    color_edges = [dicc_color_edges[e[2]['accion']] for e in G.edges(data=True)]
    color_nodes = [dicc_color_nodos[df_nodos_graph.loc[[i], 'tipo'].tolist()[0]] for i in G.nodes]
    fig, ax = plt.subplots()
    draw_network(G, color_edges=color_edges, color_nodes=color_nodes, axes=ax, labels=[1, 2, 4, 5], text_size=8)
    fig.savefig(f'graficas/redes/red_{red}.png', dpi=200)
    plt.cla()
print(df_asoc.loc[[x for x in df_links.query('red==@red')['destino_id'].unique() if 'ocds' in x][0]])

Tareas:

  • Procesar telefonos

  • procesar múltiples mails

  • Es posible obtener más datos de los contratistas a partir del RUCP, como el sitio web, giro del negocio

Buscar otra anomalía: todos los contratos con métodos abiertos en los que solo participa un proponente. Buscar contratos en los que todos los particpantes reciben contrato.

  • Buscar otra anomalía: todos los contratos con métodos abiertos en los que solo participa un proponente.
  • Buscar contratos en los que todos los particpantes reciben contrato.

Funcionarios que intervienen en contrataciones

mydb.func_contrat.count_documents({})
113795
mydb.func_contrat.find_one()
{'_id': ObjectId('5deb255d723b95da59c6a01b'),
 'id': 'c6dbd706-b539-476f-a400-4dd69ed4a757',
 'fechaCaptura': '',
 'ejercicioFiscal': 2017,
 'periodoEjercicio': {'fechaInicial': '2017/01/01',
  'fechaFinal': '2017/12/31'},
 'idRamo': 6,
 'ramo': 'HACIENDA Y CRÉDITO PÚBLICO',
 'nombres': None,
 'primerApellido': None,
 'segundoApellido': None,
 'genero': None,
 'institucionDependencia': {'siglas': 'CNBV',
  'nombre': 'COMISIÓN NACIONAL BANCARIA Y DE VALORES',
  'clave': '6/B00'},
 'puesto': {'nombre': 'SUBDIRECTOR DE MEJORA A', 'nivel': None},
 'tipoArea': ['R'],
 'nivelResponsabilidad': ['A', 'T'],
 'tipoProcedimiento': 1,
 'tipoActos': 'CONTRATACIONES',
 'superiorInmediato': {'nombres': None,
  'primerApellido': None,
  'segundoApellido': None,
  'puesto': {'nombre': None, 'nivel': None}}}
nombre_func_contrat = [f'{r["nombres"]} {r["primerApellido"]} {r["segundoApellido"]}'
                       for r in mydb.func_contrat.find({}, {'_id':0, 'nombres': 1, 'primerApellido': 1, 'segundoApellido':1}) if all([r["nombres"], r["primerApellido"], r["segundoApellido"]])]

Funcionarios sancionados

mydb.serv_sanc.count_documents({})
3575
mydb.serv_sanc.find_one()
{'_id': ObjectId('5deb27a2432e395ca7ba4a62'),
 'nombres': 'ZACARIAS',
 'primerApellido': 'PEREZ',
 'segundoApellido': 'GARCIA',
 'institucionDependencia': {'nombre': 'PROCURADURIA GENERAL DE LA REPUBLICA',
  'siglas': ' '},
 'autoridadSancionadora': 'ORGANO INTERNO DE CONTROL',
 'expediente': '520/99',
 'resolucion': {'fechaResolucion': '17/11/2000'},
 'tipoSancion': 'INHABILITACION',
 'inhabilitacion': {'fechaInicial': '17/11/2000',
  'fechaFinal': '16/11/2020',
  'observaciones': None},
 'multa': {'monto': None, 'moneda': 'MXN'},
 'causaMotivoHechos': 'ABUSO DE AUTORIDAD',
 'puesto': 'AGENTE DE LA POLICIA JUDICIAL FEDERAL'}
nombre_serv_sanc = [f'{r["nombres"]} {r["primerApellido"]} {r["segundoApellido"]}' for r in mydb.serv_sanc.find({}, {'_id':0, 'nombres': 1, 'primerApellido': 1, 'segundoApellido':1})]
casos_func = [p['contactPoint']['name'] for c in casos_contratos for p in c['parties'] if p['roles']==['procuringEntity']]
set(casos_func).intersection(set(nombre_serv_sanc))
set()
yt = list(set(df_contactos.name.unique().tolist()).intersection(set(nombre_serv_sanc)))
len(yt)
10
yt
['MIGUEL ANGEL TORRES HERNANDEZ',
 'AGUSTIN TOLEDO GADEA',
 'OSCAR CHAVEZ MARTINEZ',
 'JOSE LUIS CHAVEZ FLORES',
 'MARIO HERNANDEZ DIAZ',
 'RODRIGO MALDONADO SAHAGUN',
 'ERIKA BENITEZ GARCIA',
 'FRANCISCO FIERRO SILVA',
 'JOSE LUIS GARCIA RODRIGUEZ',
 'JOSE DE LA CRUZ RAMIREZ']

Particulares sancionados

mydb.part_sanc.count_documents({})
1853
mydb.part_sanc.find_one()
{'_id': ObjectId('5deb27d0715998a251b6be6b'),
 'fechaCaptura': '2019-08-22',
 'expediente': '000270074/2017',
 'nombreRazonSocial': 'CONSTRUCCIÓN ESPECIALIZADA Y TECNOLÓGICA DE MÉXICO, S.A. DE C.V.',
 'rfc': 'ACV990407',
 'telefono': '01 961 61 5 30 09',
 'domicilio': {'clave': 'MX'},
 'tipoSancion': 'ECONOMICA E INHABILITACIÓN',
 'institucionDependencia': {'nombre': 'SECRETARIA DE LA FUNCIÓN PÚBLICA',
  'siglas': 'SFP'},
 'tipoFalta': '',
 'causaMotivoHechos': 'NO ENTREGAR LA OBRA EN LA FECHA COMPROMETIDA PARA ELLO, ESTO ES EL 24 DE SEPTIEMBRE DE 2014',
 'objetoContrato': '',
 'autoridadSancionadora': 'SECRETARIA DE LA FUNCIÓN PÚBLICA',
 'responsableSancion': {'nombres': 'MARÍA GUADALUPE VARGAS ÁLVAREZ',
  'primerApellido': '',
  'segundoApellido': ''},
 'resolucion': {'sentido': 'SANCIONATORIA CON MULTA E INHABILITACIÓN'},
 'fechaNotificacion': '2019-08-14',
 'multa': {'monto': '504675.00', 'moneda': 'MXN'},
 'plazo': {'fechaInicial': '2019-08-23'},
 'observaciones': None}
rfc_sanc = [r['rfc'] for r in mydb.part_sanc.find({'rfc': {'$ne': ''}}, {'_id':0, 'rfc': 1})]

Red Mitchell

result1 = mydb.contrataciones.find({'contracts': {'$exists': True}},
                    ['ocid', 'parties.id', 'parties.roles', 'parties.contactPoint', 'contracts.value.amount', 'date'])

l1 = list(result1)
ocid_tenderer = pd.DataFrame([(c['ocid'], p['id']) for c in l1 for p in c['parties']
                     if p['roles'] in [['tenderer', 'supplier'], ['tenderer']]],
                             columns=['ocid', 'tenderer_id'],
                            ).set_index('ocid')
ocid_tenderer.head()
tenderer_id
ocid
ocds-07smqs-1003803 E9C1C827AE1234CCF7AC4D9070BB597C
ocds-07smqs-1003123 SCA031118BX7
ocds-07smqs-1003123 SAU0505307M9
ocds-07smqs-1003123 SCK070618C21
ocds-07smqs-1009245 R&S811221KR6
ocid_funcionario = pd.DataFrame([(c['ocid'], p['contactPoint'].get('name', ''), p['id'],
                                  c['contracts'][0]['value']['amount'], c['date'])
                                 for c in l1 for p in c['parties']
                     if p['roles']==['procuringEntity']], columns=['ocid', 'funcionario_id', 'uc_id', 'valor_contrato', 'fecha'])\
                .set_index('ocid')

ocid_dependencia = pd.DataFrame([(c['ocid'], p['id'])
                                 for c in l1 for p in c['parties']
                     if p['roles']==['buyer']], columns=['ocid', 'dep_id'])\
                .set_index('ocid')

ocid_funcionario.head()
funcionario_id uc_id valor_contrato fecha
ocid
ocds-07smqs-1003803 José Gabriel Ramos Martínez SAT970701NN3-006E00002 8451072.00 2016-02-19T01:09:18Z
ocds-07smqs-1003123 Ignacio Romero Sánchez PGR850101RC6-017000017 168000.00 2016-02-19T01:49:22Z
ocds-07smqs-1009245 Juan Fernando Meza Zavala STP401231P53-014000999 420689.55 2016-02-26T05:33:08Z
ocds-07smqs-1012355 Luis Eduardo Vega Becerra CNU800928K31-018E00999 20000.00 2016-03-02T01:58:39Z
ocds-07smqs-1025654 Marco Antonio Brito Vidales IAA6210025R4-006A00996 10604000.00 2016-03-18T06:40:28Z
ocid_tender_fun = ocid_tenderer.join([ocid_funcionario, ocid_dependencia])
ocid_tender_fun
tenderer_id funcionario_id uc_id valor_contrato fecha dep_id
ocid
ocds-07smqs-1001024 ELE9012281G2 Evelyn López Valverde LIC950821M84-020VST003 1.152540e+05 2016-03-15T01:02:50Z LICONSA-231
ocds-07smqs-1001040 HIG090519H30 Nicolas Gonzalez Bustos HIM871203BS0-012NBG001 2.603075e+07 2016-02-16T02:44:58Z HIM-163
ocds-07smqs-1001984 282910F3163E9D7DBC543E53CD9347B6 Nicolas Gonzalez Bustos HIM871203BS0-012NBG001 1.071380e+05 2016-02-17T04:42:35Z HIM-163
ocds-07smqs-1002362 IPS040121S66 Nicolas Gonzalez Bustos HIM871203BS0-012NBG001 2.115000e+05 2016-02-17T07:30:57Z HIM-163
ocds-07smqs-1003123 SCA031118BX7 Ignacio Romero Sánchez PGR850101RC6-017000017 1.680000e+05 2016-02-19T01:49:22Z PGR-251
... ... ... ... ... ... ...
ocds-07smqs-999514 CPC131113AT4 Luis Enrique Mendoza Flores IMS421231I45-050GYR026 7.317600e+04 2016-02-12T01:34:46Z IMSS-192
ocds-07smqs-999514 96A74A55F4E5DAEC0797B59049D8EC81 Luis Enrique Mendoza Flores IMS421231I45-050GYR026 7.317600e+04 2016-02-12T01:34:46Z IMSS-192
ocds-07smqs-999514 TGH130612IK1 Luis Enrique Mendoza Flores IMS421231I45-050GYR026 7.317600e+04 2016-02-12T01:34:46Z IMSS-192
ocds-07smqs-999514 SIN011023UC8 Luis Enrique Mendoza Flores IMS421231I45-050GYR026 7.317600e+04 2016-02-12T01:34:46Z IMSS-192
ocds-07smqs-999514 GMC09121623A Luis Enrique Mendoza Flores IMS421231I45-050GYR026 7.317600e+04 2016-02-12T01:34:46Z IMSS-192

726038 rows × 6 columns

ocid_tender_fun.to_csv(f'{dir_datos}/ocid_tender_fun.csv')