Es muy habitual trabajar con archivos csv pero en ocasiones disponemos de ficheros de texto con determinado formato o con ancho fijo para las columnas. Hace tiempo ya escribí sobre la lectura de archivos csv con Python y Pandas pero en esta ocasión vamos a leer archivos que no tienen un separador. Evidentemente tienen que darnos el formato del archivo, en este caso, para ilustrar el ejemplo, vamos a pasar un código en R a un código en Python. Necesitamos leer unos datos usados en el libro Non-Life Insurance Pricing with GLM, con R teníamos el siguiente programa:
varib <- c(edad = 2L, sexo = 1L, zona = 1L, clase_moto = 1L, antveh = 2L, bonus = 1L, exposicion = 8L, nsin = 4L, impsin = 8L) varib.classes <- c("integer", rep("factor", 3), "integer", "factor", "numeric", rep("integer", 2)) con <- url("https://staff.math.su.se/esbj/GLMbook/mccase.txt") moto <- read.fwf(con, widths = varib, header = FALSE, col.names = names(varib), colClasses = varib.classes, na.strings = NULL, comment.char = "")
Necesitamos crear ese data frame moto con Python. Evidentemente una lectura a las bravas no tiene sentido:
import pandas as pd data1 = pd.read_fwf("http://staff.math.su.se/esbj/GLMbook/mccase.txt") data1.head(10)
El programa R ya nos define el formato del fichero y es necesario "traducirlo" a Pandas:
#Asignamos columnas = [(0, 2), (2,3), (3,4), (4,5), (5,7), (7,8), (8,16), (16,20), (20,28)] data1 = pd.read_fwf("http://staff.math.su.se/esbj/GLMbook/mccase.txt", colspecs=columnas, header=None) data1.head(10)
Vamos a crear una lista con el ancho de los campos que denominamos columnas, como siempre, en este caso empezamos en 0 no en el 1 y el final del anterior campo será el principio del siguiente, después sumamos a ese principio la longitud del campo que nos han definido. Ahora cuando usemos read_fwf que es la función necesaria para leer files-with-format, ficheros con formato, en colspecs pondremos la lista con las longitudes de los campos y en este caso no tenemos encabezados por lo que es necesario poner header = None. Ya tenemos un data frame al que solo falta asignar los nombres con los campos:
data1.columns = ['edad','sexo','zona','clase_moto', 'antveh', 'bonus', 'exposicion', 'nsin', 'impsin'] data1.head()
El ejemplo os sirve, pero se puede simplificar porque los campos son consecutivos usando widths = lista de longitudes:
data2 = pd.read_fwf("http://staff.math.su.se/esbj/GLMbook/mccase.txt", widths = [2,1,1,1,2,1,8,4,8], header=None) data2.columns = ['edad','sexo','zona','clase_moto', 'antveh', 'bonus', 'exposicion', 'nsin', 'impsin'] data2.head()
Equivale a lo que hemos visto con anterioridad pero es preferible usar el primer método porque es más rápida la lectura. Saludos.