Search

Más agrupaciones de datos en Python…sin Pandas

Continuando con mi post anterior, vamos a realizar otra agrupación de datos. Si en el post anterior agrupábamos los datos por el día del mes calculando su suma, ahora vamos a complicarlo un poquito y agrupar por la zona, la planta y el día del mes.

Lo primero los datos, aquí.

La tabla contiene las mismas columnas que en el post anterior:

  • ZONA: Zona geográfica donde está situada la planta correspondiente.
  • PLANTA: Nombre de la planta.
  • DIA_MES: Día del mes del que se han obtenido los datos.
  • HORAS_TRABAJO: Las horas de los trabajos que se han ido realizando en la planta.

Con Pandas sería algo trivial:

import pandas as pd

df = pd.read_csv('trabajos_02.csv', sep=";", decimal=",")

grouped_df = df.groupby(['ZONA','PLANTA','DIA_MES']).sum().reset_index()

print (grouped_df)

     ZONA  PLANTA  DIA_MES  HORAS_TRABAJO
0   NORTE  GORBEA        1      21.783333
1   NORTE  GORBEA        2       5.950000
2   NORTE  GORBEA        4      14.283333
3   NORTE  GORBEA        5      14.366667
4   NORTE  GORBEA        6      23.000000
...
23  NORTE  GORBEA       25      14.983333
24  NORTE  GORBEA       26      15.150000
25  NORTE  GORBEA       27      13.833333
26  NORTE  GORBEA       28      19.583333
27  NORTE  GORBEA       29      14.333333
...
28    SUR  TARIFA        1       8.016667
29    SUR  TARIFA        4      24.166667
30    SUR  TARIFA        5      12.016667
31    SUR  TARIFA        6       7.516667
32    SUR  TARIFA        7       8.016667
...
42    SUR  TARIFA       24       2.250000
43    SUR  TARIFA       25      11.950000
44    SUR  TARIFA       27       8.033333
45    SUR  TARIFA       28       3.433333
46    SUR  TARIFA       29       7.850000

Ahora vamos a obtener el mismo resultado, pero sin usar Pandas.

Importamos las librerías que vamos a necesitar:

import csv
from itertools import groupby
from operator import itemgetter

1.- Leemos el archivo csv. Esta vez vamos a colocarlo en una lista de diccionarios, para poder usar las claves a la hora de agrupar.

csv_rdr = csv.reader(open('trabajos_02.csv'), delimiter=';')

trabajos_lista_dict = []
for index, row in enumerate(csv_rdr):
    if index == 0:
        encabezado = row
    else:
        row[3] = float(row[3].replace(",", "."))
        d = {}
        for index, value in enumerate(row):
            key = encabezado[index]
            d[key] = value
        trabajos_lista_dict.append(d)

Vamos a sacar el primer elemento de la lista, a ver que pinta tiene:

print (trabajos_lista_dict[0])

{'DIA_MES': '01', 'ZONA': 'NORTE', 'PLANTA': 'GORBEA', 'HORAS_TRABAJO': 0.8666666666666667}

Como en el post anterior utilizaremos dos métodos. Primero utilizando la clase groupby y despues usando la clase defaultdict.

1.- Con groupby:

Declaramos una variable tipo lista para ir añadiendo en ella los resultados.

result = []

Creamos el objeto grouper con las claves por las que queremos agrupar

grouper = itemgetter("ZONA", "PLANTA", "DIA_MES")

Utilizamos la clase groupby, con los argumentos nuestra lista de diccionarios ordenada, y la clave para agrupar.

for key, grp in groupby(sorted(trabajos_lista_dict, key = grouper), grouper):
    temp_dict = dict(zip(["ZONA", "PLANTA", "DIA_MES"], key))
    temp_dict["HORAS_TRABAJO"] = sum(item["HORAS_TRABAJO"] for item in grp)
    result.append(temp_dict)

Aquí hay una novedad en el código con respecto al anterior post.

Las keys de la clase groupby van a tener esta pinta:

('NORTE', 'GORBEA', '01')
('NORTE', 'GORBEA', '02')
('NORTE', 'GORBEA', '04')
...
('SUR', 'TARIFA', '01')
('SUR', 'TARIFA', '04')
('SUR', 'TARIFA', '05')

Como vamos a querer como resultado final una lista de diccionarios,  vamos a utilizar la función zip para crear los elementos clave-valor para un diccionario temporal para cada grp. Haremos un zip con esta pinta:

zip(["ZONA", "PLANTA", "DIA_MES"], ('NORTE', 'GORBEA', '01')))

Una vez hecho el zip obtenenos un diccionario con esta pinta:

{'PLANTA': 'GORBEA', 'ZONA': 'NORTE', 'DIA_MES': '01'}

El paso siguiente es añadir al diccionario temporal la clave HORAS_TRABAJO, que tendrá como valor la suma de los items del iterador grp, en este caso un diccionario, correspondientes a la clave HORAS_TRABAJO. Luego solo resta añadir el diccionario a la lista result.

Para ver el resultado obtenido podemos hacer:

print ("{:<7}{:<9}{:<11}{:<13}".format("ZONA","PLANTA","DIA_MES","HORAS_TRABAJO"))
for element in result:
    zona, planta, dia_mes, horas_trabajo = element['ZONA'],element['PLANTA'],element['DIA_MES'],element['HORAS_TRABAJO']
    print ("{:<7}{:<9}{:<11}{:<13}".format(zona, planta, dia_mes, str(horas_trabajo)))

ZONA PLANTA DIA_MES HORAS_TRABAJO
NORTE GORBEA 01 21.783333333333328
NORTE GORBEA 02 5.95 
NORTE GORBEA 04 14.283333333333335
NORTE GORBEA 05 14.366666666666664
NORTE GORBEA 06 23.0 
...
NORTE GORBEA 25 14.98333333333333
NORTE GORBEA 26 15.15 
NORTE GORBEA 27 13.833333333333332
NORTE GORBEA 28 19.583333333333336
NORTE GORBEA 29 14.333333333333336
...
SUR TARIFA 01 8.016666666666666
SUR TARIFA 04 24.166666666666664
SUR TARIFA 05 12.016666666666667
SUR TARIFA 06 7.516666666666667
SUR TARIFA 07 8.016666666666666
...
SUR TARIFA 24 2.25 
SUR TARIFA 25 11.950000000000003
SUR TARIFA 27 8.033333333333333
SUR TARIFA 28 3.433333333333333
SUR TARIFA 29 7.85

El resultado coincide con lo obtenido con Pandas.

2.- Con defaultdict.
res_dd = []
d = defaultdict(list)
for row in trabajos_lista_dict:
    d[row['ZONA'] + '|' + row['PLANTA'] + '|' + row['DIA_MES']].append(float(row['HORAS_TRABAJO']))
for k, v in sorted(d.items()):
    res_dd.append([k, sum(v)])

Con la línea de código 4 nos vamos construyendo las keys, concatenando los valores correspondientes a la zona, la planta y el día del mes.

Vemos el resultado.

print("{:<7}{:<9}{:<11}{:<13}".format("ZONA", "PLANTA", "DIA_MES", "HORAS_TRABAJO"))
for row in res_dd:
    zona, planta, dia_mes = row[0].split('|')
    print("{:<7}{:<9}{:<11}{:<13}".format(zona, planta, dia_mes, str(row[1])))

ZONA PLANTA DIA_MES HORAS_TRABAJO
NORTE GORBEA 01 21.783333333333328
NORTE GORBEA 02 5.95 
NORTE GORBEA 04 14.283333333333335
NORTE GORBEA 05 14.366666666666664
NORTE GORBEA 06 23.0
...
NORTE GORBEA 25 14.98333333333333
NORTE GORBEA 26 15.15 
NORTE GORBEA 27 13.833333333333332
NORTE GORBEA 28 19.583333333333336
NORTE GORBEA 29 14.333333333333336
...
SUR TARIFA 01 8.016666666666666
SUR TARIFA 04 24.166666666666664
SUR TARIFA 05 12.016666666666667
SUR TARIFA 06 7.516666666666667
SUR TARIFA 07 8.016666666666666
...
SUR TARIFA 24 2.25 
SUR TARIFA 25 11.950000000000003
SUR TARIFA 27 8.033333333333333
SUR TARIFA 28 3.433333333333333
SUR TARIFA 29 7.85

Que también coincide con los anteriores.

Puedes descargarte el código de mi 

 

Deja una respuesta

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.