
Hola habrozhiteli! Este libro está dirigido a personas que ya tienen experiencia en uno o más lenguajes de programación y desean aprender los conceptos básicos de Python 3 de la manera más rápida y fácil posible. Se supone que el lector ya está familiarizado con las estructuras de control, OOP, manejo de archivos, manejo de excepciones, etc. e) El libro también será útil para los usuarios de versiones anteriores de Python que necesitan una referencia compacta de Python 3.1.
Te invitamos a leer el extracto "Procesando archivos de datos"
Cómo usar un libro
La Parte 1 proporciona información general sobre Python. Aprenderá a descargar e instalar Python en su sistema. También proporciona una descripción general del lenguaje, que será útil principalmente para programadores experimentados que desean una comprensión de alto nivel de Python.
La parte 2 contiene el material principal del libro. Discute los ingredientes necesarios para adquirir habilidades prácticas en el uso de Python como lenguaje de programación de propósito general. El material de los capítulos fue planeado para que los lectores que recién comienzan a aprender Python puedan avanzar secuencialmente, dominando los puntos clave del lenguaje. Esta parte también contiene secciones más complejas, para que pueda regresar y encontrar toda la información necesaria sobre un determinado diseño o tema en un solo lugar.
La Parte 3 presenta las características avanzadas de Python: elementos de lenguaje que no son absolutamente necesarios, pero que sin duda serán útiles para cualquier programador serio de Python.
La Parte 4 se centra en temas especializados que van más allá de la sintaxis simple del lenguaje. Puede leer estos capítulos u omitirlos según sus necesidades.
Se alienta a los programadores principiantes de Python a comenzar con el capítulo 3 para dar una impresión general, y luego pasar a los capítulos de interés en la parte 2. Introducir ejemplos interactivos para reforzar los conceptos instantáneamente. También puede ir más allá de los ejemplos dados en el texto y buscar respuestas a cualquier pregunta que no esté clara. Este enfoque aumentará la velocidad de aprendizaje y profundizará la comprensión. Si aún no está familiarizado con OOP o no es necesario para su aplicación, puede omitir la mayor parte del capítulo 15.
Los lectores que ya están familiarizados con Python también deben comenzar con el capítulo 3. Proporciona una buena visión general introductoria y una descripción de las diferencias entre Python 3 y las versiones más familiares. También se puede usar para evaluar si está listo para pasar a los capítulos más complejos de las partes 3 y 4 de este libro.
Quizás algunos lectores que no tienen experiencia con Python pero que tengan suficiente experiencia en otros lenguajes de programación puedan obtener la mayor parte de la información necesaria leyendo el Capítulo 3 y mirando los módulos de la biblioteca estándar de Python (Capítulo 19) y el manual de referencia de la biblioteca de Python en la documentación de Python .
Extracto Procesamiento de archivos de datos
La mayoría de los datos se distribuyen en archivos de texto. Puede ser texto no estructurado (por ejemplo, una colección de mensajes o una colección de textos literarios) o datos más estructurados, en los que cada línea es un registro, y los campos están separados por un carácter separador especial: una coma, un carácter de tabulación o una barra vertical (|). Los archivos de texto pueden ser enormes; un conjunto de datos puede ocupar decenas o incluso cientos de archivos, y los datos contenidos en él pueden estar incompletos o distorsionados. Con tal variedad, casi inevitablemente se encontrará con la tarea de leer y usar datos de archivos de texto. Este capítulo presenta las estrategias básicas para resolver este problema en Python.
21.1 Introduciendo ETL
La necesidad de extraer datos de los archivos, analizarlos, convertirlos a un formato conveniente y luego hacer algo apareció casi simultáneamente con los archivos de datos. Además, incluso hay un término estándar para este proceso: ETL (Extract-Transform-Load, es decir, "extracción - transformación - carga"). La recuperación se refiere al proceso de leer una fuente de datos y analizarla si es necesario. La conversión puede implicar limpiar y normalizar datos, así como combinar, dividir y reorganizar los registros que contienen. Finalmente, cargar significa guardar los datos convertidos en un nuevo lugar (en otro archivo o base de datos). Este capítulo trata los conceptos básicos de la implementación de un ETL en Python, desde archivos de datos de texto hasta el almacenamiento de datos convertidos en otros archivos. Los archivos de datos más estructurados se discuten en el capítulo 22, y el almacenamiento de información en una base de datos se discute en el capítulo 23.
21.2 Leer archivos de texto
El primer componente de ETL (extracción) implica abrir un archivo y leer su contenido. A primera vista, parece simple, pero incluso aquí pueden surgir problemas, por ejemplo, el tamaño del archivo. Si el archivo es demasiado grande para caber en la memoria, el código debe estructurarse para que funcione con segmentos más pequeños del archivo (posiblemente una línea).
21.2.1. Codificación de texto: ASCII, Unicode y otros.
Otro posible problema es la codificación. Este capítulo está dedicado a trabajar con archivos de texto y, de hecho, una gran proporción de los datos transmitidos en el mundo real se almacena en archivos de texto. Sin embargo, la naturaleza exacta del texto puede variar según la aplicación, el usuario y, por supuesto, el país.
A veces, el texto lleva información en codificación ASCII, que incluye 128 caracteres, de los cuales solo 95 se clasifican como imprimibles. Afortunadamente, la codificación ASCII es el "múltiplo menos común" de la mayoría de las situaciones de transferencia de datos. Por otro lado, no puede hacer frente a las complejidades de los numerosos alfabetos y sistemas de escritura que existen en el mundo. La lectura de archivos en codificación ASCII conducirá casi con certeza al hecho de que al leer caracteres no compatibles, ya sea alemán ü, portugués ç o casi cualquier carácter de un idioma que no sea inglés, comenzarán los problemas y aparecerán errores.
Estos errores ocurren porque ASCII usa valores de 7 bits, mientras que los bytes en un archivo típico consisten en 8 bits, lo que permite representar 256 valores posibles en lugar de 128 para valores de 7 bits. Estos códigos adicionales se usan generalmente para almacenar valores adicionales, desde signos de puntuación extendidos (como guiones medios y cortos) hasta varios caracteres (marca registrada, signo de copyright y signo de grado) y versiones de caracteres alfabéticos con signos diacríticos. Siempre hubo un problema: al leer un archivo de texto, podía encontrar un carácter que iba más allá del rango ASCII de 128 caracteres, y no podía estar seguro de qué carácter estaba codificado. Supongamos que te encuentras con un personaje con el código 214. ¿Qué es? ¿Una marca de división, la letra Ö o algo más? Sin el código fuente que creó este archivo, es imposible averiguarlo.
Unicode y UTF-8
Para eliminar esta ambigüedad, puede usar Unicode. La codificación Unicode, llamada UTF-8, admite caracteres ASCII básicos sin ningún cambio, pero también permite un conjunto casi ilimitado de otros caracteres y caracteres del estándar Unicode. Debido a su flexibilidad, UTF-8 se utiliza en más del 85% de las páginas web que existían en el momento de este escrito. Esto significa que al leer archivos de texto es mejor enfocarse en UTF-8. Si los archivos contienen solo caracteres ASCII, se leerán correctamente, pero también obtendrá seguro en caso de que otros caracteres estén codificados en UTF-8. Afortunadamente, el tipo de datos de cadena Python 3 está diseñado para admitir Unicode de forma predeterminada.
Incluso con Unicode, las situaciones son posibles cuando aparecen valores en el texto que no se pueden decodificar con éxito. La función abierta en Python recibe un parámetro de errores adicional, que determina cómo lidiar con los errores de codificación al leer o escribir archivos. El valor predeterminado es 'estricto', con el cual se activa un error cada vez que se detecta un error de codificación. Otros valores útiles son 'ignorar' (omitir el carácter que causó el error); 'reemplazar' (un personaje se reemplaza con un marcador especial, ¿generalmente?); 'backslashreplace' (el carácter se reemplaza por la secuencia de escape con \) y 'surrogateescape' (el carácter intruso se convierte en un punto de código Unicode privado cuando se lee y vuelve a la secuencia de bytes original cuando se escribe). La elección del método para procesar o resolver errores de codificación depende de la situación específica.
Considere un breve ejemplo de un archivo que contiene un carácter UTF-8 no válido y vea cómo se procesa este carácter en diferentes modos. Primero escriba el archivo usando bytes y modo binario:
>>> open('test.txt', 'wb').write(bytes([65, 66, 67, 255, 192,193]))
Como resultado del comando, se crea un archivo a partir de los caracteres "ABC", seguido de tres caracteres que no están incluidos en ASCII, que se pueden mostrar de manera diferente según el método de codificación utilizado. Si usa vim para ver el archivo, el resultado se verá así:
ABCÿÀÁ ~
Cuando se crea el archivo, intente leerlo en el modo predeterminado de manejo estricto de errores:
>>> x = open('test.txt').read() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.6/codecs.py", line 321, in decode (result, consumed) = self._buffer_decode(data, self.errors, final) UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 3: invalid start byte
El cuarto byte con un valor de 255 no es un carácter UTF-8 válido en esta posición, por lo que se produce una excepción en modo 'estricto'. Ahora veamos cómo otros modos de manejo de errores manejan el mismo archivo, sin olvidar que los últimos tres caracteres desencadenan un error:
Si desea que los caracteres problemáticos simplemente desaparezcan, use el modo 'ignorar'. El modo 'reemplazar' solo marca las posiciones de los caracteres no válidos, mientras que otros modos intentan guardar de manera diferente los caracteres no válidos sin interpretación.
21.2.2. Texto no estructurado
Los archivos de texto no estructurados se leen más fácilmente, pero también crean la mayoría de los problemas con la extracción de información. El procesamiento de texto no estructurado puede variar ampliamente dependiendo de la naturaleza del texto y de lo que va a hacer con él, por lo que cualquier discusión detallada sobre el procesamiento de texto está más allá del alcance del libro. Sin embargo, un breve ejemplo ayudará a demostrar algunos problemas básicos y sentará las bases para discutir archivos con datos de texto estructurado.
Uno de los problemas más simples es elegir la unidad lógica base en el archivo. Si usa una colección de miles de mensajes de Twitter, texto de Moby Dick o una colección de noticias, debe dividirlos de alguna manera en bloques. En el caso de los tweets, cada bloque se puede colocar en una línea, y la lectura y el procesamiento de cada línea del archivo se organiza de manera bastante simple.
En el caso de Moby Dick e incluso algunas noticias, el problema se está volviendo más complicado. Por supuesto, el texto de la novela e incluso el texto de las noticias generalmente no es deseable considerarlo como una sola unidad. En este caso, debe decidir qué bloques necesita y luego desarrollar una estrategia para dividir el archivo en bloques. Es posible que prefiera procesar el texto párrafo por párrafo. En este caso, debe determinar cómo se organiza el desglose del texto en párrafos del archivo y escribir el código en consecuencia. Si los párrafos coinciden con las líneas de un archivo de texto, esto no será difícil. Sin embargo, a menudo un párrafo de un archivo de texto puede constar de varias líneas en un archivo de texto, y tendrá que trabajar duro.
Ahora considere un par de ejemplos.
Llámame Ismael Hace algunos años, no importa cuánto tiempo, precisamente
Tener poco o nada de dinero en mi cartera y nada en particular
para interesarme en la costa, pensé que navegaría un poco
y ver la parte acuosa del mundo. Es una forma que tengo
de expulsar el bazo y regular la circulación.
Cada vez que me encuentro cada vez más sombrío sobre la boca;
cada vez que es un noviembre húmedo y lluvioso en mi alma; cada vez que yo
me encuentro deteniéndome involuntariamente ante almacenes de ataúdes,
y trayendo la parte trasera de cada funeral que encuentro;
y especialmente cada vez que mis hipos me dominan tanto,
que requiere un fuerte principio moral para evitar que
entrar deliberadamente en la calle y tocar metódicamente
la gente se quitó el sombrero - entonces, considero que ya es hora de llegar al mar
tan pronto como pueda Este es mi sustituto de pistola y pelota.
Con una floritura filosófica, Cato se arroja sobre su espada;
En silencio me llevo al barco. No hay nada sorprendente en esto.
Si ellos lo supieran, casi todos los hombres en su grado, alguna vez
u otro, apreciar casi los mismos sentimientos hacia
El océano conmigo.
Ahora está tu ciudad insular de los Manhattoes, rodeada de muelles
como islas indias junto a los arrecifes de coral: el comercio lo rodea con sus olas.
Derecha e izquierda, las calles te llevan hacia el agua. Su centro extremo
es la batería, donde ese lunar noble es lavado por las olas y enfriado
por la brisa, que unas horas antes estaban fuera de la vista de la tierra.
Mira las multitudes de observadores de agua allí.
En este ejemplo (con el comienzo del texto "Moby Dick"), las líneas se dividen más o menos de la forma en que se paginarían, y los párrafos se indican con una sola línea vacía. Si desea tratar cada párrafo como un todo, debe dividir el texto en líneas en blanco. Afortunadamente, esta tarea se logra fácilmente mediante el método de cadenas split (). Cada nueva línea en el texto está representada por la combinación "\ n". Naturalmente, la última línea de texto de cada párrafo termina con una nueva línea, y si la siguiente línea de texto está vacía, la segunda nueva línea la sigue inmediatamente:

Analizar texto en párrafos es un paso muy simple en el procesamiento de texto no estructurado. Es posible que también deba realizar una normalización adicional del texto antes de seguir procesándolo. Suponga que desea calcular la frecuencia de aparición de cada palabra en un archivo de texto. Si simplemente divide el archivo por omisiones, obtendrá una lista de palabras en el archivo, sin embargo, no será tan fácil calcular con precisión las ocurrencias, porque Esto, esto, esto. y esto, no se considerará la misma palabra. Para que este código funcione correctamente, es necesario normalizar el texto eliminando los signos de puntuación y convirtiendo todo el texto en un caso antes del procesamiento. En el ejemplo de texto anterior, el código para construir una lista normalizada de palabras puede verse así:
21.2.3. Archivos delimitados no estructurados
Los archivos no estructurados se leen de manera muy simple, pero la falta de estructura también es su inconveniente. A menudo es más conveniente definir alguna estructura para un archivo a fin de simplificar la selección de valores individuales. En la versión más simple, el archivo se divide en líneas, y cada línea contiene un elemento de información. Por ejemplo, puede ser una lista de nombres de archivos para procesar, una lista de nombres de personas o una serie de lecturas de temperatura de un sensor remoto. En tales casos, el análisis de los datos se organiza de manera muy simple: lee la línea y, si es necesario, la convierte al tipo deseado. Esto es todo lo que se necesita para preparar el archivo para su uso.
Sin embargo, la situación no es tan simple. Más a menudo necesita agrupar varios elementos de datos interconectados, y su código debería leerlos juntos. Por lo general, para esto, los datos relacionados se colocan en una línea y se separan por un carácter especial. En este caso, al leer cada línea del archivo, se utilizan caracteres especiales para dividir los datos en campos y almacenar los valores de los campos en variables para su posterior procesamiento.
El siguiente archivo contiene datos de temperatura en un formato delimitado:
State|Month Day, Year Code|Avg Daily Max Air Temperature (F)|Record Count for Daily Max Air Temp (F) Illinois|1979/01/01|17.48|994 Illinois|1979/01/02|4.64|994 Illinois|1979/01/03|11.05|994 Illinois|1979/01/04|9.51|994 Illinois|1979/05/15|68.42|994 Illinois|1979/05/16|70.29|994 Illinois|1979/05/17|75.34|994 Illinois|1979/05/18|79.13|994 Illinois|1979/05/19|74.94|994
Los datos en el archivo están separados por una tubería (|). En este ejemplo, consisten en cuatro campos: estado, fecha de observación, temperatura máxima promedio y número de estaciones que suministran datos. Otros delimitadores estándar son un carácter de tabulación y una coma. Quizás la coma se usa con mayor frecuencia, pero el separador puede ser cualquier carácter que no aparezca en los valores (más sobre eso más adelante). Los datos separados por comas son tan comunes que este formato a menudo se denomina CSV (valores separados por comas, es decir, datos separados por comas), y los archivos de este tipo se proporcionan con la extensión .csv como un atributo de formato.
Independientemente del carácter que se use como delimitador, si sabe cuál es el carácter, puede escribir su propio código de Python para dividir la cadena en campos y devolverlos como una lista. En el caso anterior, puede usar el método split () para convertir la cadena en una lista de valores:
>>> line = "Illinois|1979/01/01|17.48|994" >>> print(line.split("|")) ['Illinois', '1979/01/01', '17.48', '994']
Esta técnica es muy fácil de implementar, pero todos los valores se almacenan en forma de cadena, y esto puede ser inconveniente para el procesamiento posterior.
21.2.4. Módulo csv
Si a menudo tiene que procesar archivos de datos delimitados, debería echar un vistazo más de cerca al módulo csv y sus capacidades. Cuando me pidieron que nombrara mi módulo favorito de la biblioteca estándar de Python, llamé al módulo csv más de una vez, no porque se vea espectacular (no lo es), sino porque probablemente me ahorró más tiempo y me salvó de mis posibles errores con más frecuencia que cualquier otro módulo.
El módulo csv es el ejemplo perfecto de la filosofía de "batería incluida" de Python. Aunque puede escribir perfectamente su propio código para leer archivos delimitados (además, no es tan difícil), es mucho más fácil y más confiable usar el módulo Python. El módulo csv ha sido probado y optimizado, y proporciona una serie de características que difícilmente podría implementar usted mismo, pero que, sin embargo, son bastante convenientes y ahorran tiempo.
Eche un vistazo a los datos anteriores y decida cómo los leería con el módulo csv. El código de análisis de datos debe leer cada línea y eliminar el carácter de nueva línea final, y luego dividir la línea por caracteres | y agregue la lista de valores a la lista general de cadenas. La solución podría verse así:
>>> results = [] >>> for line in open("temp_data_pipes_00a.txt"): ... fields = line.strip().split("|") ... results.append(fields) ... >>> results [['State', 'Month Day, Year Code', 'Avg Daily Max Air Temperature (F)', 'Record Count for Daily Max Air Temp (F)'], ['Illinois', '1979/01/01', '17.48', '994'], ['Illinois', '1979/01/02', '4.64', '994'], ['Illinois', '1979/01/03', '11.05', '994'], ['Illinois', '1979/01/04', '9.51', '994'], ['Illinois', '1979/05/15', '68.42', '994'], ['Illinois', '1979/ 05/16', '70.29', '994'], ['Illinois', '1979/05/17', '75.34', '994'], ['Illinois', '1979/05/18', '79.13', '994'], ['Illinois', '1979/05/19', '74.94', '994']]
Si desea hacer lo mismo con el módulo csv, el código podría verse así:
>>> import csv >>> results = [fields for fields in csv.reader(open("temp_data_pipes_00a.txt", newline=''), delimiter="|")] >>> results [['State', 'Month Day, Year Code', 'Avg Daily Max Air Temperature (F)', 'Record Count for Daily Max Air Temp (F)'], ['Illinois', '1979/01/01', '17.48', '994'], ['Illinois', '1979/01/02', '4.64', '994'], ['Illinois', '1979/01/03', '11.05', '994'], ['Illinois', '1979/01/04', '9.51', '994'], ['Illinois', '1979/05/15', '68.42', '994'], ['Illinois', '1979/ 05/16', '70.29', '994'], ['Illinois', '1979/05/17', '75.34', '994'], ['Illinois', '1979/05/18', '79.13', '994'], ['Illinois', '1979/05/19', '74.94', '994']]
En este caso simple, la ganancia en comparación con la implementación independiente de la solución no es tan grande. Sin embargo, el código resultó ser dos líneas más cortas y un poco más claras, y no necesita preocuparse por truncar los caracteres de nueva línea. La verdadera ventaja viene cuando te enfrentas a casos más complejos.
Los datos en este ejemplo son reales, pero en realidad se han simplificado y borrado. Los datos reales de la fuente serán más complejos. Los datos reales contienen más campos, algunos campos se incluirán entre comillas, otros no, y el primer campo puede estar vacío. El original está separado por pestañas, pero para fines de demostración los cito separados por comas:
"Notes","State","State Code","Month Day, Year","Month Day, Year Code",Avg Daily Max Air Temperature (F),Record Count for Daily Max Air Temp (F),Min Temp for Daily Max Air Temp (F),Max Temp for Daily Max Air Temp (F),Avg Daily Max Heat Index (F),Record Count for Daily Max Heat Index (F),Min for Daily Max Heat Index (F),Max for Daily Max Heat Index (F),Daily Max Heat Index (F) % Coverage ,"Illinois","17","Jan 01, 1979","1979/01/ 01",17.48,994,6.00,30.50,Missing,0,Missing,Missing,0.00% ,"Illinois","17","Jan 02, 1979","1979/01/02",4.64,994,- 6.40,15.80,Missing,0,Missing,Missing,0.00% ,"Illinois","17","Jan 03, 1979","1979/01/03",11.05,994,- 0.70,24.70,Missing,0,Missing,Missing,0.00% ,"Illinois","17","Jan 04, 1979","1979/01/ 04",9.51,994,0.20,27.60,Missing,0,Missing,Missing,0.00% ,"Illinois","17","May 15, 1979","1979/05/ 15",68.42,994,61.00,75.10,Missing,0,Missing,Missing,0.00% ,"Illinois","17","May 16, 1979","1979/05/ 16",70.29,994,63.40,73.50,Missing,0,Missing,Missing,0.00% ,"Illinois","17","May 17, 1979","1979/05/ 17",75.34,994,64.00,80.50,82.60,2,82.40,82.80,0.20% ,"Illinois","17","May 18, 1979","1979/05/ 18",79.13,994,75.50,82.10,81.42,349,80.20,83.40,35.11% ,"Illinois","17","May 19, 1979","1979/05/ 19",74.94,994,66.90,83.10,82.87,78,81.60,85.20,7.85%
Nota: algunos campos incluyen comas. De acuerdo con las reglas en tales casos, el campo está entre comillas para indicar que su contenido no está destinado a analizar y buscar delimitadores. En la práctica (como en este caso), solo una fracción de los campos a menudo se encierra entre comillas, especialmente aquellos cuyos valores pueden contener un separador. Sin embargo (como de nuevo en este ejemplo), algunos campos están entre comillas, incluso cuando es poco probable que contengan un separador.
En tales casos, las soluciones de cosecha propia se vuelven demasiado engorrosas. Ahora, simplemente romper una línea por un carácter delimitador ya no funciona; debe asegurarse de usar solo los separadores que no están dentro de las cadenas. Además, debe eliminar las comillas, que pueden estar en una posición arbitraria o no encontrarse en ningún lado. Con el módulo csv, no tiene que cambiar su código en absoluto. Además, dado que la coma se considera el separador predeterminado, ni siquiera necesita especificarse:
>>> results2 = [fields for fields in csv.reader(open("temp_data_01.csv", newline=''))] >>> results2 [['Notes', 'State', 'State Code', 'Month Day, Year', 'Month Day, Year Code', 'Avg Daily Max Air Temperature (F)', 'Record Count for Daily Max Air Temp (F)', 'Min Temp for Daily Max Air Temp (F)', 'Max Temp for Daily Max Air Temp (F)', 'Avg Daily Min Air Temperature (F)', 'Record Count for Daily Min Air Temp (F)', 'Min Temp for Daily Min Air Temp (F)', 'Max Temp for Daily Min Air Temp (F)', 'Avg Daily Max Heat Index (F)', 'Record Count for Daily Max Heat Index (F)', 'Min for Daily Max Heat Index (F)', 'Max for Daily Max Heat Index (F)', 'Daily Max Heat Index (F) % Coverage'], ['', 'Illinois', '17', 'Jan 01, 1979', '1979/01/01', '17.48', '994', '6.00', '30.50', '2.89', '994', '-13.60', '15.80', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'Jan 02, 1979', '1979/01/02', '4.64', '994', '-6.40', '15.80', '-9.03', '994', '-23.60', '6.60', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'Jan 03, 1979', '1979/01/03', '11.05', '994', '- 0.70', '24.70', '-2.17', '994', '-18.30', '12.90', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'Jan 04, 1979', '1979/01/04', '9.51', '994', '0.20', '27.60', '-0.43', '994', '-16.30', '16.30', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'May 15, 1979', '1979/05/15', '68.42', '994', '61.00', '75.10', '51.30', '994', '43.30', '57.00', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'May 16, 1979', '1979/05/ 16', '70.29', '994', '63.40', '73.50', '48.09', '994', '41.10', '53.00', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'May 17, 1979', '1979/05/17', '75.34', '994', '64.00', '80.50', '50.84', '994', '44.30', '55.70', '82.60', '2', '82.40', '82.80', '0.20%'], ['', 'Illinois', '17', 'May 18, 1979', '1979/05/18', '79.13', '994', '75.50', '82.10', '55.68', '994', '50.00', '61.10', '81.42', '349', '80.20', '83.40', '35.11%'], ['', 'Illinois', '17', 'May 19, 1979', '1979/05/19', '74.94', '994', '66.90', '83.10', '58.59', '994', '50.90', '63.20', '82.87', '78', '81.60', '85.20', '7.85%']]
»Se puede encontrar más información sobre el libro en
el sitio web del editor»
Contenidos»
ExtractoCupón de 20% de descuento para vendedores ambulantes -
Python