La biblioteca gratuita de Python más rápida para leer un archivo CSV con 1~3 columnas de números

Estoy buscando la biblioteca de Python más rápida para leer un archivo CSV (si eso importa, 1 o 3 columnas, todos los números enteros o flotantes, ejemplo ) en una matriz de Python (o algún objeto al que pueda acceder de manera similar, con un similar tiempo de acceso). Debería ser gratuito, funcionar en Windows 7 y Ubuntu 12.04, y con Python 2.7 x64.

CSV con 1 columna:

350
750
252
138
125
125
125
112
95
196
105
101
101
101
102
101
101
102
202
104

CSV con 3 columnas:

9,52,1
52,91,0
91,135,0
135,174,0
174,218,0
218,260,0
260,301,0
301,341,0
341,383,0
383,423,0
423,466,0
466,503,0
503,547,0
547,583,0
583,629,0
629,667,0
667,713,0
713,754,0
754,796,0
796,839,1
Coincidentemente, hay una pregunta muy similar publicada hace 2 horas en Super User: superuser.com/q/775893/137286 La primera respuesta sugiere una biblioteca rápida.
¿Has probado con fastcsv, como sugerí a continuación, últimamente? Me interesaría mucho saber cómo funciona con sus datos. Saludos, Daniel

Respuestas (6)

Así que eventualmente escribí un pequeño punto de referencia usando las bibliotecas que Steve Barnes había señalado. Encontré lo mismo al buscarlo mientras escribía la pregunta, así que supongo que esos son los principales. Algunas otras ideas que aún no se han probado: HDF5 para Python , PyTables , IOPro (no gratuito).

En resumen, pandas.io.parsers.read_csvsupera a todos los demás, NumPy loadtxtes impresionantemente lento y NumPy es from_fileimpresionantemente loadrápido.

Datos (debería haberlos generado en el punto de referencia, pero ahora mismo me estoy quedando sin tiempo)

Código:

import csv
import os
import cProfile
import time
import numpy
import pandas
import warnings

# Make sure those files in the same folder as benchmark_python.py
# As the name indicates:
# - '1col.csv' is a CSV file with 1 column
# - '3col.csv' is a CSV file with 3 column
filename1 = '1col.csv'
filename3 = '3col.csv'
csv_delimiter = ' '
debug = False

def open_with_python_csv(filename):
    '''
    https://docs.python.org/2/library/csv.html
    '''
    data =[]
    with open(filename, 'rb') as csvfile:
        csvreader = csv.reader(csvfile, delimiter=csv_delimiter, quotechar='|')
        for row in csvreader:
            data.append(row)    
    return data

def open_with_python_csv_cast_as_float(filename):
    '''
    https://docs.python.org/2/library/csv.html
    '''
    data =[]
    with open(filename, 'rb') as csvfile:
        csvreader = csv.reader(csvfile, delimiter=csv_delimiter, quotechar='|')
        for row in csvreader:
            data.append(map(float, row))    
    return data

def open_with_python_csv_list(filename):
    '''
    https://docs.python.org/2/library/csv.html
    '''
    data =[]
    with open(filename, 'rb') as csvfile:
        csvreader = csv.reader(csvfile, delimiter=csv_delimiter, quotechar='|')
        data = list(csvreader)    
    return data


def open_with_numpy_loadtxt(filename):
    '''
    http://stackoverflow.com/questions/4315506/load-csv-into-2d-matrix-with-numpy-for-plotting
    '''
    data = numpy.loadtxt(open(filename,'rb'),delimiter=csv_delimiter,skiprows=0)
    return data

def open_with_pandas_read_csv(filename):
    df = pandas.read_csv(filename, sep=csv_delimiter)
    data = df.values
    return data    


def benchmark(function_name):  
    start_time = time.clock()
    data = function_name(filename1)       
    if debug: print data[0] 
    data = function_name(filename3)
    if debug: print data[0]
    print function_name.__name__ + ': ' + str(time.clock() - start_time), "seconds"


def benchmark_numpy_fromfile():
    '''
    http://docs.scipy.org/doc/numpy/reference/generated/numpy.fromfile.html
    Do not rely on the combination of tofile and fromfile for data storage, 
    as the binary files generated are are not platform independent.
    In particular, no byte-order or data-type information is saved.
    Data can be stored in the platform independent .npy format using
    save and load instead.
    
    Note that fromfile will create a one-dimensional array containing your data,
    so you might need to reshape it afterward.
    '''
    #ignore the 'tmpnam is a potential security risk to your program' warning
    with warnings.catch_warnings():
        warnings.simplefilter('ignore', RuntimeWarning)
        fname1 = os.tmpnam()
        fname3 = os.tmpnam()
        
    data = open_with_numpy_loadtxt(filename1)
    if debug: print data[0]
    data.tofile(fname1)
    data = open_with_numpy_loadtxt(filename3)
    if debug: print data[0]
    data.tofile(fname3)
    if debug: print data.shape
    fname3shape = data.shape
    start_time = time.clock()
    data = numpy.fromfile(fname1, dtype=numpy.float64) # you might need to switch to float32. List of types: http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html
    if debug: print len(data), data[0], data.shape
    data = numpy.fromfile(fname3, dtype=numpy.float64)
    data = data.reshape(fname3shape)
    if debug: print len(data), data[0], data.shape    
    print 'Numpy fromfile: ' + str(time.clock() - start_time), "seconds"

def benchmark_numpy_save_load():
    '''
    http://docs.scipy.org/doc/numpy/reference/generated/numpy.fromfile.html
    Do not rely on the combination of tofile and fromfile for data storage, 
    as the binary files generated are are not platform independent.
    In particular, no byte-order or data-type information is saved.
    Data can be stored in the platform independent .npy format using
    save and load instead.
    
    Note that fromfile will create a one-dimensional array containing your data,
    so you might need to reshape it afterward.
    '''
    #ignore the 'tmpnam is a potential security risk to your program' warning
    with warnings.catch_warnings():
        warnings.simplefilter('ignore', RuntimeWarning)
        fname1 = os.tmpnam()
        fname3 = os.tmpnam()
        
    data = open_with_numpy_loadtxt(filename1)
    if debug: print data[0]    
    numpy.save(fname1, data)    
    data = open_with_numpy_loadtxt(filename3)
    if debug: print data[0]    
    numpy.save(fname3, data)    
    if debug: print data.shape
    fname3shape = data.shape
    start_time = time.clock()
    data = numpy.load(fname1 + '.npy')
    if debug: print len(data), data[0], data.shape
    data = numpy.load(fname3 + '.npy')
    #data = data.reshape(fname3shape)
    if debug: print len(data), data[0], data.shape    
    print 'Numpy load: ' + str(time.clock() - start_time), "seconds"


def main():
    number_of_runs = 20
    results = []
    
    benchmark_functions = ['benchmark(open_with_python_csv)', 
                           'benchmark(open_with_python_csv_list)',
                           'benchmark(open_with_python_csv_cast_as_float)',
                           'benchmark(open_with_numpy_loadtxt)',
                           'benchmark(open_with_pandas_read_csv)',
                           'benchmark_numpy_fromfile()',
                           'benchmark_numpy_save_load()']
    # Compute benchmark
    for run_number in range(number_of_runs):
        run_results = []
        for benchmark_function in benchmark_functions:
            run_results.append(eval(benchmark_function))
            results.append(run_results)
        
    # Display benchmark's results
    print results
    results = numpy.array(results)
    numpy.set_printoptions(precision=10) # http://stackoverflow.com/questions/2891790/pretty-printing-of-numpy-array
    numpy.set_printoptions(suppress=True)  # suppress suppresses the use of scientific notation for small numbers:
    print numpy.mean(results, axis=0)
    print numpy.std(results, axis=0)    
    
    #Another library, but not free: https://store.continuum.io/cshop/iopro/

if __name__ == "__main__":
    #cProfile.run('main()') # if you want to do some profiling
    main()  

ventanas 7:

Producción:

open_with_python_csv: 1.57318865672 seconds
open_with_python_csv_list: 1.35567931732 seconds
open_with_python_csv_cast_as_float: 3.0801260484 seconds
open_with_numpy_loadtxt: 14.4942111801 seconds
open_with_pandas_read_csv: 0.371965476805 seconds
Numpy fromfile: 0.0130216095713 seconds
Numpy load: 0.0245501650124 seconds

Para instalar todas las bibliotecas: Binarios no oficiales de Windows para paquetes de extensión de Python

Configuración de ventanas:


Ubuntu 12.04:

Producción:

open_with_python_csv: 1.93 seconds
open_with_python_csv_list: 1.52 seconds
open_with_python_csv_cast_as_float: 3.19 seconds
open_with_numpy_loadtxt: 7.47 seconds
open_with_pandas_read_csv: 0.35 seconds
Numpy fromfile: 0.01 seconds
Numpy load: 0.02 seconds

Para instalar todas las bibliotecas:

sudo apt-get install python-pip
sudo pip install numpy
sudo pip install pandas

Si las bibliotecas ya están instaladas pero necesitan actualizarse:

sudo apt-get install python-pip
sudo pip install numpy --upgrade
sudo pip install pandas --upgrade

Configuración de Ubuntu:

  • Ubuntu 12.04 x64
  • Pitón 2.7.3
  • NumPy 1.8.1 ( import numpy; numpy.version.version)
  • Pandas 0.14.0 ( import pandas as pd; pd.__version__)

Obviamente, siéntase libre de mejorar el punto de referencia comentando/editando/etc. Estoy seguro de que hay muchas cosas para mejorar:

  • Asegurarse de que las funciones de carga actuales estén bien optimizadas
  • Pruebe nuevas funciones/bibliotecas como HDF5 para Python , PyTables , IOPro (no gratuito).
  • Genere el CSV en el punto de referencia (para que no tenga que descargar los archivos CSV)
Una interesante comparación de resultados.
me salvaste del mundo oscuro y solitario denumpy.loadtxt
Gran respuesta. Para su información, ejecuté su punto de referencia en un archivo cvs de 2 GB: open_with_python_csv: 153.789445 segundos open_with_python_csv_list: 146.709768 segundos open_with_python_csv_cast_as_float: 86.957046 segundos open_with_numpy_loadtxt: 157.669637 segundos open_with_pandas 66.8v
Esto es genial y he aprendido mucho esta noche de esta publicación. Sin embargo, tu np.fromfileparece terriblemente rápido. Lo que encontré en mis pruebas es que solo funciona en la primera línea, por lo que para hacer todo el archivo tienes que hacer un ciclo que vuelve a ralentizar las cosas a 60 s para mi archivo csv de 20 000 líneas, frente a 0,75 s para Pandas. ¿Estás leyendo todo el archivo con np.fromfile? También pude usarlo np.fromstringcargando todo el archivo csv, replaceing '\ncon ''y luego ejecutando np.fromstring. Las manipulaciones de cadenas fueron rápidas, pero la conversión a números fue lenta. Este método tomó 2.6s.
Probar esto en 2018 en Windows 10 con python 2.7.13 con un archivo de 100000 filas con 19 columnas simplemente probando open_with_python_csv, open_with_python_csv_list y open_with_pandas_read_csv y el método pandas no es más rápido. Los medios csv incorporados son ~ 0.35 y pandas ~ 0.43.
Solo como nota, pandas.read_csv de forma predeterminada realiza una tonelada de procesamiento aleatorio, como reemplazar valores de cadena como "N/A" con valores nulos y convertir cadenas que parecen números a enteros, lo que produce una gran cantidad de pérdida potencial de datos (ya me mordió ).

Me gustaría contribuir con otra biblioteca aquí, con la que tropecé buscando una pregunta similar. Lo probé con el código de referencia de Franck Dernoncourts y supera a Pythons csv estándar y Pandas por millas. No pude probar con numpy, ya que probé con un csv de 24.000 líneas con números y valores de cadena.

Esta biblioteca rápida en realidad se basa en la implementación csv predeterminada, solo usa TextIO , que lo hace más rápido Y maneja las cadenas Unicode correctamente.

Se llama fastcsv y fue desarrollado por Masaya Suzuki. Puede cerrarlo en GitHub o usar Pypi para instalarlo. más simple es:

pip install fastcsv

En http://pythonhosted.org/fastcsv/ puede ver más resultados de Benchmark, pero solo para leer csv, permítame repetir sus resultados aquí:

Benchmark de lectura usando fastcsv

Sería interesante saber cómo funciona esto con sus datos.

"TLDR: esto está en desuso. Use Python3 y el módulo csv estándar. Por lo tanto, no recomiendo usar esta biblioteca". - ¿Nota del autor?
@SebastianPalma La pregunta original especifica Python 2.7

Tiene una amplia variedad según el tamaño y la complejidad de los datos y lo que va a hacer con los datos resultantes:

  1. La csvbiblioteca que viene con Python por defecto.
  2. NumPy - numpy.from_file función - Lee en una matriz NumPy, por lo que es muy potente.
  3. Pandas - pandas.io.parsers.read_csv función - lee un marco de datos de pandas, es muy potente y puede manejar grandes conjuntos de datos.

El primero probablemente será más rápido de importar, mientras que los otros son más potentes. Todos son gratuitos y multiplataforma. El primero ya es parte de su instalación de Python si tiene uno predeterminado.

Hay un nuevo pydatatablepaquete que tiene un lector csv muy rápido basado en la implementación de R data.table fread.
Lea más en https://github.com/h2oai/datatable Si desea que se cargue el objeto pandas, simplemente puede ejecutar

pandas_dataframe = dt.fread(srcfile).to_pandas()

Sugeriría estar atento a la documentación oficial de pandas en IO . La opción de uno sigue cambiando según el ciclo de desarrollo y se agregan nuevos formatos todo el tiempo. También publican el benchmark.

Hay un nuevo paquete de Python para la minería de datos que se llama DaPy . Que tiene una API de E/S simple y lo suficientemente rápida para ti. Según la prueba de rendimiento del autor, DaPy tardó 12,5 segundos en cargar un archivo csv con más de 2 millones de registros, mientras que pandas tardó 4 segundos. Sin embargo, DaPy se basa en algunas estructuras de datos nativas de Python y es más fácil de usar.

cmd: pip install DaPy 
>>> import DaPy as dp
>>> data = dp.read('file.csv')
>>> data.show()