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