47. Archivos con Python
En los próximos ejercicios vamos a usar frecuentemente archivos de
datos, así que es un buen momento para leer en detalle el capítulo 11
del libro de texto. Las funciones básicas de escritura son muy
sencillas.
f = open('ejemplo.txt', 'w')
f.write('''Esto es un ejemplo de archivo
escrito con Python.
Puedo escribir en varias lineas porque
estoy usando las triples comillas.''')
f.close()
Leer archivos es igual de sencillo.
fi = open('ejemplo.txt', 'r')
for linea in fi:
print(linea,end='')
fi.close()
Esto es un ejemplo de archivo
escrito con Python.
Puedo escribir en varias lineas porque
estoy usando las triples comillas.
Observa que pongo una coma al final del print
. Lo hago porque las
líneas incluyen el caracter terminador de línea si lo hubiera. También
puedo quitarlos con strip
pero observa cómo strip
elimina
también los espacios al principio de la línea:
fi = open('ejemplo.txt', 'r')
for linea in fi:
print(linea.strip())
fi.close()
Esto es un ejemplo de archivo
escrito con Python.
Puedo escribir en varias lineas porque
estoy usando las triples comillas.
Como resumen podemos decir que en la mayoría de los casos solo se
necesitan 3 funciones para manejar archivos (open
, close
y
write
). Hay muchas más y te animo a que leas en detalle el capítulo
11 del libro y la documentación de archivos
oficial.
Lo que leemos o escribimos de/en archivos son cadenas de texto, así que
para usos avanzados tendremos que dominar las cadenas de texto. Repasa
el capítulo 7 del libro de texto y la documentación de cadenas
oficial.
También puede que te resulten útiles los módulos
string
y re.
47.1. Lectura de archivos CSV
Los archivos CSV no son diferentes de los demás, son simples archivos de
texto en los que cada línea corresponde a una fila de una tabla. Cada
campo en una línea se separa con una coma. (El nombre CSV deriva
precisamente de ésto (Comma Separated Values). En Python existe un
módulo csv
que simplifica la lectura de estos archivos. Pero
realmente es muy simple también procesarlos a mano. Esto podría ser un
ejemplo de archivo CSV.
,Ambos sexos,Mujeres
Aragón,"6845.0","3962.0"
Canarias,"11164.0","6181.0"
fi = open('ejemplo.csv', 'r')
for linea in fi:
fila = linea.strip()
celdas = fila.split(',')
for celda in celdas:
print('[{!s:>11}]\t'.format(celda), end='')
print()
fi.close()
[ ] [Ambos sexos] [ Mujeres]
[ Aragón] [ "6845.0"] [ "3962.0"]
[ Canarias] [ "11164.0"] [ "6181.0"]
47.2. Caso de estudio: Censo de viviendas
El INE distribuye datos del Censo de Población y
Viviendas que incluyen
dos archivos interesantes para nuestros propósitos:
Veamos cómo es el diseño de los registros. Es una tabla que indica a
partir de qué posición empieza cada campo y hasta qué posición, así como
la interpretación que tiene cada posible valor. Por ejemplo, para ver si
la vivienda tiene o no Internet habría que consultar el caracter 25
(empezando desde 1). Es decir, si linea
contiene una línea completa
del archivo de microdatos entonces linea[24]
nos indica si tiene o
no Internet esa vivienda.
<tr>
<td style="border-top: 2px solid #000000; border-left: 2px solid #000000; border-right: 1px solid #000000" rowspan=3 height="42" align="left" valign=top bgcolor="#E3E3E3"><b><font size=1>Nombre del campo</font></b></td>
<td style="border-top: 2px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000" rowspan=3 align="left" valign=top bgcolor="#E3E3E3"><b><font size=1>Nombre de la variable</font></b></td>
<td style="border-top: 2px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000" rowspan=3 align="left" valign=top bgcolor="#E3E3E3"><b><font size=1>Longitud del campo</font></b></td>
<td style="border-top: 2px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000" rowspan=3 align="left" valign=top bgcolor="#E3E3E3"><b><font size=1>Inicio</font></b></td>
<td style="border-top: 2px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000" rowspan=3 align="left" valign=top bgcolor="#E3E3E3"><b><font size=1>Fin</font></b></td>
<td style="border-top: 2px solid #000000; border-left: 1px solid #000000; border-right: 2px solid #000000" rowspan=3 align="left" valign=top bgcolor="#E3E3E3"><b><font size=1>Valores validos</font></b></td>
</tr>
<tr>
</tr>
<tr>
</tr>
<tr>
<td style="border-top: 2px solid #000000; border-left: 2px solid #000000" height="26" align="left" bgcolor="#FFD475"><b><font size=1>Identificación</font></b></td>
<td style="border-top: 2px solid #000000" align="left" bgcolor="#FFD475"><font face="Univers" size=1><br></font></td>
<td style="border-top: 2px solid #000000" align="left" bgcolor="#FFD475"><font face="Univers" size=1><br></font></td>
<td style="border-top: 2px solid #000000" align="left" bgcolor="#FFD475"><font face="Univers" size=1><br></font></td>
<td style="border-top: 2px solid #000000" align="left" bgcolor="#FFD475"><font face="Univers" size=1><br></font></td>
<td style="border-top: 2px solid #000000; border-right: 2px solid #000000" align="left" bgcolor="#FFD475"><font face="Univers" size=1><br></font></td>
</tr>
<tr>
<td style="border-left: 2px solid #000000" height="21" align="left" valign=top><font size=1>Código de provincia</font></td>
<td align="left" valign=top><font size=1>CPRO</font></td>
<td align="center" valign=top sdval="2" sdnum="3082;"><font size=1>2</font></td>
<td align="center" valign=top sdval="1" sdnum="3082;"><font size=1>1</font></td>
<td align="center" valign=top sdval="2" sdnum="3082;"><font size=1>2</font></td>
<td style="border-right: 2px solid #000000" align="left" valign=top><font size=1>Desde 1 hasta 52</font></td>
</tr>
<tr>
<td style="border-left: 2px solid #000000" height="94" align="left" valign=top><font size=1>Código o tamaño de municipio</font></td>
<td align="left" valign=top><font size=1>CMUN</font></td>
<td align="center" valign=top sdval="3" sdnum="3082;"><font size=1>3</font></td>
<td align="center" valign=top sdval="3" sdnum="3082;"><font size=1>3</font></td>
<td align="center" valign=top sdval="5" sdnum="3082;"><font size=1>5</font></td>
<td style="border-right: 2px solid #000000" align="left" valign=top><font size=1>Si tamaño de municipio <=2.000, CMUN=991<br>Si 2.001 <=tamaño de municipio <=5.000, CMUN=992<br>Si 5.001 <=tamaño de municipio <=10.000, CMUN=993<br>Si 10.001 <=tamaño de municipio <=20.000, CMUN=994<br>Si tamaño de municipio >20.000, CMUN=Código de municipio</font></td>
</tr>
<tr>
<td style="border-left: 2px solid #000000" height="21" align="left" bgcolor="#FFD475"><b><font size=1>Datos de la vivienda</font></b></td>
<td align="left" bgcolor="#FFD475"><font face="Univers" size=1><br></font></td>
<td align="left" bgcolor="#FFD475"><font face="Univers" size=1><br></font></td>
<td align="left" bgcolor="#FFD475"><font face="Univers" size=1><br></font></td>
<td align="left" bgcolor="#FFD475"><font face="Univers" size=1><br></font></td>
<td style="border-right: 2px solid #000000" align="left" bgcolor="#FFD475"><font face="Univers" size=1><br></font></td>
</tr>
<tr>
<td style="border-left: 2px solid #000000" height="20" align="left" valign=top><font size=1>Factor de elevación de la vivienda</font></td>
<td align="left" valign=top><font size=1>FACTOR</font></td>
<td align="center" valign=top sdval="14" sdnum="3082;"><font size=1>14</font></td>
<td align="center" valign=top sdval="6" sdnum="3082;"><font size=1>6</font></td>
<td align="center" valign=top sdval="19" sdnum="3082;"><font size=1>19</font></td>
<td style="border-right: 2px solid #000000" align="left" valign=top><font size=1 color="#FF0000"><br></font></td>
</tr>
<tr>
<td style="border-left: 2px solid #000000" height="56" align="left" valign=top><font size=1>Clase de vivienda </font></td>
<td align="left" valign=top><font size=1>CVIVIF</font></td>
<td align="center" valign=top sdval="1" sdnum="3082;"><font size=1>1</font></td>
<td align="center" valign=top sdval="20" sdnum="3082;"><font size=1>20</font></td>
<td align="center" valign=top sdval="20" sdnum="3082;"><font size=1>20</font></td>
<td style="border-right: 2px solid #000000" align="left" valign=top><font size=1>1 Vivienda Prinicipal<br>2 Vivienda Secundaria<br>3 Vivienda Vacía</font></td>
</tr>
<tr>
<td style="border-left: 2px solid #000000" height="150" align="left" valign=top><font size=1>Régimen de tenencia</font></td>
<td align="left" valign=top><font size=1>TENEN</font></td>
<td align="center" valign=top sdval="1" sdnum="3082;"><font size=1>1</font></td>
<td align="center" valign=top sdval="21" sdnum="3082;"><font size=1>21</font></td>
<td align="center" valign=top sdval="21" sdnum="3082;"><font size=1>21</font></td>
<td style="border-right: 2px solid #000000" align="left" valign=top><font size=1>1 Propia, por compra, totalmente pagada<br>2 Propia, por compra, con pagos pendientes (hipotecas)<br>3 Propia por herencia o donación<br>4 Alquilada<br>5 Cedida gratis o a bajo precio (por otro hogar, pagada por la empresa...)<br>6 Otra forma<br>Blanco si CVIVIF <> 1 </font></td>
</tr>
<tr>
<td style="border-left: 2px solid #000000" height="113" align="left" valign=top><font size=1>Calefacción </font></td>
<td align="left" valign=top><font size=1>CALE</font></td>
<td align="center" valign=top sdval="1" sdnum="3082;"><font size=1>1</font></td>
<td align="center" valign=top sdval="22" sdnum="3082;"><font size=1>22</font></td>
<td align="center" valign=top sdval="22" sdnum="3082;"><font size=1>22</font></td>
<td style="border-right: 2px solid #000000" align="left" valign=top><font size=1>1 Colectiva o central<br>2 Individual<br>3 No tiene calefacción pero sí algún aparato que permite calentar<br>4 No tiene calefacción<br>Blanco si CVIVIF <> 1 </font></td>
</tr>
<tr>
<td style="border-left: 2px solid #000000" height="56" align="left" valign=top><font size=1>Cuanto de aseo con inodoro</font></td>
<td align="left" valign=top><font size=1>ASEO</font></td>
<td align="center" valign=top sdval="1" sdnum="3082;"><font size=1>1</font></td>
<td align="center" valign=top sdval="23" sdnum="3082;"><font size=1>23</font></td>
<td align="center" valign=top sdval="23" sdnum="3082;"><font size=1>23</font></td>
<td style="border-right: 2px solid #000000" align="left" valign=top><font size=1>1 Sí<br>2 No<br>Blanco si CVIVIF <> 1 </font></td>
</tr>
<tr>
<td style="border-left: 2px solid #000000" height="56" align="left" valign=top><font size=1>Baño o ducha</font></td>
<td align="left" valign=top><font size=1>BADUCH</font></td>
<td align="center" valign=top sdval="1" sdnum="3082;"><font size=1>1</font></td>
<td align="center" valign=top sdval="24" sdnum="3082;"><font size=1>24</font></td>
<td align="center" valign=top sdval="24" sdnum="3082;"><font size=1>24</font></td>
<td style="border-right: 2px solid #000000" align="left" valign=top><font size=1>1 Sí<br>2 No<br>Blanco si CVIVIF <> 1 </font></td>
</tr>
<tr>
<td style="border-left: 2px solid #000000" height="56" align="left" valign=top><font size=1>Acceso a Internet</font></td>
<td align="left" valign=top><font size=1>INTERNET</font></td>
<td align="center" valign=top sdval="1" sdnum="3082;"><font size=1>1</font></td>
<td align="center" valign=top sdval="25" sdnum="3082;"><font size=1>25</font></td>
<td align="center" valign=top sdval="25" sdnum="3082;"><font size=1>25</font></td>
<td style="border-right: 2px solid #000000" align="left" valign=top><font size=1>1 Sí<br>2 No<br>Blanco si CVIVIF <> 1 </font></td>
</tr>
<tr>
<td style="border-left: 2px solid #000000" height="94" align="left" valign=top><font size=1>Sistema de suministro de agua</font></td>
<td align="left" valign=top><font size=1>AGUACOR</font></td>
<td align="center" valign=top sdval="1" sdnum="3082;"><font size=1>1</font></td>
<td align="center" valign=top sdval="26" sdnum="3082;"><font size=1>26</font></td>
<td align="center" valign=top sdval="26" sdnum="3082;"><font size=1>26</font></td>
<td style="border-right: 2px solid #000000" align="left" valign=top><font size=1>1 Agua corriente por abastecimiento público<br>2 Agua corriente por abastecimiento privado o particular del edificio<br>3 No tiene agua corriente<br>Blanco si CVIVIF <> 1 </font></td>
</tr>
<tr>
<td style="border-left: 2px solid #000000" height="38" align="left" valign=top><font size=1>Superficie útil</font></td>
<td align="left" valign=top><font size=1>SUT</font></td>
<td align="center" valign=top sdval="3" sdnum="3082;"><font size=1>3</font></td>
<td align="center" valign=top sdval="27" sdnum="3082;"><font size=1>27</font></td>
<td align="center" valign=top sdval="29" sdnum="3082;"><font size=1>29</font></td>
<td style="border-right: 2px solid #000000" align="left" valign=top><font size=1>Desde 5 hasta 999<br>Blanco si CVIVIF <> 1 </font></td>
</tr>
<tr>
<td style="border-left: 2px solid #000000" height="38" align="left" valign=top><font size=1>Número de habitaciones</font></td>
<td align="left" valign=top><font size=1>NHAB</font></td>
<td align="center" valign=top sdval="2" sdnum="3082;"><font size=1>2</font></td>
<td align="center" valign=top sdval="30" sdnum="3082;"><font size=1>30</font></td>
<td align="center" valign=top sdval="31" sdnum="3082;"><font size=1>31</font></td>
<td style="border-right: 2px solid #000000" align="left" valign=top><font size=1>Desde 1 hasta 99<br>Blanco si CVIVIF <> 1 </font></td>
</tr>
<tr>
<td style="border-left: 2px solid #000000" height="22" align="left" bgcolor="#FFD475"><b>...</b></td>
<td align="left" bgcolor="#FFD475"><font face="Univers" size=1><br></font></td>
<td align="left" bgcolor="#FFD475"><font face="Univers" size=1><br></font></td>
<td align="left" bgcolor="#FFD475"><font face="Univers" size=1><br></font></td>
<td align="left" bgcolor="#FFD475"><font face="Univers" size=1><br></font></td>
<td style="border-right: 2px solid #000000" align="left" bgcolor="#FFD475"><font face="Univers" size=1><br></font></td>
</tr>
Vamos a contestar alguna pregunta de ejemplo. Por ejemplo, ¿cuántas
viviendas secundarias (caracter 20) tienen Internet (caracter 25)?
def viviendas_secundarias_con_internet():
f = open('Microdatos_viviendas.txt', 'r')
c = 0
for linea in f:
if linea[19] == '2' and linea[24] == '1':
c += 1
f.close()
return c
print('{} viviendas secundarias tienen Internet'
.format(viviendas_secundarias_con_internet()))
0 viviendas secundarias tienen Internet
¿Y qué porcentaje de viviendas principales tiene Internet?
def viviendas_1_con_internet():
f = open('Microdatos_viviendas.txt', 'r')
viviendas = 0
internet = 0
for linea in f:
if linea[19] == '1':
viviendas += 1
if linea[24] == '1':
internet += 1
f.close()
return internet*100.0/viviendas
print('El {:.2f}% de las primeras viviendas tienen Internet'
.format(viviendas_1_con_internet()))
El 50.65% de las primeras viviendas tienen Internet
Ese código con tantos niveles de anidamiento no es bonito, vamos a
refactorizarlo un poco.
def viviendas_1_con_internet():
f = open('Microdatos_viviendas.txt', 'r')
viviendas = 0
internet = 0
for linea in f:
viviendas, internet = acum_datos_interes(linea, viviendas, internet)
f.close()
return 100.0 * internet / viviendas
def acum_datos_interes(linea, viviendas, internet):
if linea[19] == '1':
viviendas += 1
if linea[24] == '1':
internet += 1
return viviendas, internet
print ('El {:.2f}% de las primeras viviendas tienen Internet'
.format(viviendas_1_con_internet()))
El 50.65% de las primeras viviendas tienen Internet
Sigue sin ser especialmente elegante pero ya no tiene tantos niveles de
indentación. Aprenderemos a mejorarlo cuando veamos clases.