Leyendo archivos .csv

Documentación oficial: https://docs.python.org/3/library/csv.html

Los archivos con extensión csv son las típicas hojas de cálculo que manipulan programas como LibreOffice Calc o Microsoft Excel.

Estos archivos contienen datos separados por comas (csv viene del inglés comma separated values, que significa justamente eso) y por saltos de líneas (los enters al final de cada línea).

En Python se usa el módulo csv para leer y escribir estos archivos.

Como cualquier otro módulo de Python debemos importarlo antes de usarlo; en este caso usando la instrucción import csv (se recomienda siempre poner todas las importaciones de un programa al comienzo del mismo).

Dentro del módulo csv las funciones usadas para leer y escribir archivos csv son csv.reader y csv.writer respectivamente.

Estas funciones tienen un solo parámetro obligatorio que es un archivo, previamente abierto usando la función open. Por cuestiones de compatibilidad debemos abrir el archivo pasando el parámetro newline='' (principalmente para leer archivos provenientes de Windows).

Preparándonos para leer:

import csv
archivo_csv = open("datos.csv", newline='')
reader = csv.reader(archivo_csv)

A partir de acá tenemos el archivo datos.csv, que tiene que residir en la misma carpeta que el script, listo para ser leído usando un for.

En cada iteración del for una línea entera va a ser cargada como una lista, con la cantidad de elementos igual a la cantidad de campos de esa misma línea.

print("Contando campos por línea:")
for linea in reader:
	print(f"Línea con {len(linea)} campos.")

Recordemos que la función len aplicada a listas nos devuelve la cantidad de elementos que posee.

Para acceder al valor de los campos se usa el acceso por índice, igual que con cualquier otra lista. Solo si estamos 100% seguros de que cada línea del archivo contiene N campos podemos acceder directamente a ellos sin hacer ninguna verificación previa de si existen o no. En este caso estamos en presencia de una tabla, y entonces las líneas las llamamos filas y los campos columnas:

Para un archivo donde el tercer campo es siempre una fecha:

print("Mostrando columna fecha:")
for fila in reader:
	print(fila[2])

Notar que como los índices de las listas comienzan en 0, el tercer campo se traduce al índice número 2.

Una salvedad que hay que tener al leer archivos csv es que los valores son siempre leídos como strings. Por ende, para hacer operaciones matemáticas con los valores de una columna numérica debemos previamente convertirlas al tipo numérico de Python. Para enteros se usa la función int y para decimales float.

Supongamos un archivo donde está cargado en la primer columna la cantidad de casas (entero) y en la segunda el total de sus superficies (decimal) por barrio de una localidad:

total_casas = 0
total_superficies = 0
for fila in reader:
	total_casas += int(fila[0])
	total_superficies += float(fila[1])
print(f"La localidad tiene {total_casas} casas, sumando una superficie de {total_superficies} m2")

Hacer esto es bastante inseguro (propenso a errores). Ya que si llega a venir una columna vacía o mal cargada el programa se rompería. Por eso, siempre es conveniente hacer todas las verificaciones posibles.

Reformulando el for anterior:

for fila in reader:
	casas = fila[0]
	if casas.isnumeric():
		total_casas += int(casas)
	else:
		print(f"Cuidado, una fila tiene cantidad de casas inválida: {casas}")
        
	superficies = fila[1]
	try:
		superficies_f = float(superficies)
	except ValueError:
		print(f"Cuidado, una fila tiene el campo superficies inválido: {superficies}")
	else:
		total_superficies += superficies_f

(El código del try continúa por el else solo cuando no hubieron errores, sino salta al except.)

Esto parecería funcionar a priori. Pero para nosotres argentines se nos complica: solemos usar como separador decimal la coma, y no el punto, como Python espera. Entonces, si nuestro archivo tiene números con la coma como separador decimal debemos remplazarlo por punto antes de pasárselo a la función float.

En ese caso, habría que corregir la línea superficies = fila[1] por superficies = fila[1].replace(',', '.').

El script final queda:

import csv

archivo_csv = open("datos.csv", newline='')

reader = csv.reader(archivo_csv)

for fila in reader:
	casas = fila[0]
	if casas.isnumeric():
		total_casas += int(casas)
	else:
		print(f"Cuidado, una fila tiene cantidad de casas inválida: {casas}")
        
	superficies = fila[1].replace(',', '.')
	try:
		superficies_f = float(superficies)
	except ValueError:
		print(f"Cuidado, una fila tiene el campo superficies inválido: {superficies}")
	else:
		total_superficies += superficies_f
        
print(f"La localidad tiene {total_casas} casas, sumando una superficie de {total_superficies} m2")

Existe otra forma de leer archivos csv que es usando csv.DictReader.

Esta función al igual que csv.reader tiene un único parámetro obligatorio que es el archivo. El objeto que devuelve lo recorremos también con un for.

La diferencia está en que por defecto esta función interpreta la primer línea como los encabezados de las columnas (headers en inglés). Así, el for comienza realmente en la segunda línea del archivo, que es donde empiezan los datos, y vamos a poder acceder a las columnas usando los nombres de los encabezados. Es decir las líneas ya no son leídas como listas, sino como diccionarios (que son básicamente como las listas pero con índices no estrictamente númericos).

Veámoslo.

Imaginemos un archivo donde la primer fila contiene nombre,edad y el resto de las filas sus datos correspondientes. Haríamos entonces:

import csv
archivo_csv = open("datos.csv", newline='')
reader = csv.DictReader(archivo_csv)
for fila in reader:
	print(f"La persona {fila['nombre']} tiene {fila['edad']} año(s)")

¡Mucho más cómodo!

Les dejo otro tuto, con más detalles, en inglés: https://realpython.com/python-csv/#reading-csv-files-into-a-dictionary-with-csv

^D


Revision #10
Created Sun, Aug 4, 2019 3:52 PM by wencha
Updated Sun, Aug 4, 2019 8:59 PM by wencha