2011-05-03 43 views
6

Ahora estoy usando PyExcelerator para leer archivos de Excel, pero es extremadamente lento. Como siempre necesito abrir archivos de Excel de más de 100MB, me lleva más de veinte minutos cargar solo un archivo.¿Cómo abrir rápidamente el archivo Excel en Python?

La funcionalidad que necesito son:

  • abrir archivos de Excel, seleccionar tablas específicas, y cargarlos en un objeto Dict o Lista.
  • A veces: Seleccione columnas específicas y solo cargue líneas completas que tengan las columnas específicas en valores específicos.
  • Lea archivos Excel con contraseña protegida.

Y el código que estoy utilizando ahora es:

book = pyExcelerator.parse_xls(filepath) 
parsed_dictionary = defaultdict(lambda: '', book[0][1]) 
number_of_columns = 44 
result_list = [] 
number_of_rows = 500000 
for i in range(0, number_of_rows): 
    ok = False 
    result_list.append([]) 
    for h in range(0, number_of_columns): 
     item = parsed_dictionary[i,h] 
     if type(item) is StringType or type(item) is UnicodeType: 
      item = item.replace("\t","").strip() 
     result_list[i].append(item) 
     if item != '': 
      ok = True 
    if not ok: 
     break 

¿Alguna sugerencia?

+0

¿Ha probado otras bibliotecas todavía? (No tengo ningún conocimiento técnico sobre este tema, solo estoy interesado) – Trufa

+0

Sí, lo intenté, pero esos siempre no tienen funcionalidad para escribir xls. Después de leer el gran xlses tengo que hacer algunos cálculos y guardar los resultados en un pequeño xls también. –

+0

@FelixYan: Está bien saberlo, ¡espero que tengas buenas respuestas! – Trufa

Respuesta

5

pyExcelerator parece no mantenerse. Para escribir archivos xls, use xlwt, que es un fork de pyExcelerator con correcciones de errores y muchas mejoras. La capacidad de lectura de xls (muy básica) de pyExcelerator fue erradicada de xlwt. Para leer archivos xls, use xlrd.

Si se tardan 20 minutos en cargar un archivo xls de 100MB, debe usar uno o más de: una computadora lenta, una computadora con muy poca memoria disponible o una versión anterior de Python.

Ni pyExcelerator ni xlrd leen archivos protegidos con contraseña.

Aquí está a link that covers xlrd and xlwt.

Descargo de responsabilidad: soy el autor de xlrd y maintainer de xlwt.

+0

Gracias y probaré estos dos. De hecho, estoy usando AMD Phenom II X4 945 con 4G RAM y 2G o más de ellos son gratuitos, SSD y Python 2.7 en un sistema operativo Linux x86_64. El proceso de lectura puede ser incluso más lento en otro lugar. –

2

xlrd es bastante bueno para leer archivos y xlwt es bastante bueno para escribir. Ambos superiores a pyExcelerator en mi experiencia.

1

Se podría tratar de asignar previamente la lista de su tamaño en una sola instrucción en lugar de añadir un artículo en un momento como este: (una gran asignación de memoria debe ser más rápido que muchos pequeños)

book = pyExcelerator.parse_xls(filepath) 
parsed_dictionary = defaultdict(lambda: '', book[0][1]) 
number_of_columns = 44 
number_of_rows = 500000 
result_list = [] * number_of_rows 
for i in range(0, number_of_rows): 
    ok = False 
    #result_list.append([]) 
    for h in range(0, number_of_columns): 
     item = parsed_dictionary[i,h] 
     if type(item) is StringType or type(item) is UnicodeType: 
      item = item.replace("\t","").strip() 
     result_list[i].append(item) 
     if item != '': 
      ok = True 
    if not ok: 
     break 

Si al hacerlo se obtiene un aumento apreciable del rendimiento, también se podría intentar preasignar cada elemento de la lista con el número de columnas y luego asignarlas por índice en lugar de agregar un valor a la vez. He aquí un fragmento que crea un 10x10, lista de dos dimensiones en un único estado con un valor inicial de 0:

L = [[0] * 10 for i in range(10)] 

Así doblado en su código, podría funcionar algo como esto:

book = pyExcelerator.parse_xls(filepath) 
parsed_dictionary = defaultdict(lambda: '', book[0][1]) 
number_of_columns = 44 
number_of_rows = 500000 
result_list = [[''] * number_of_rows for x in range(number_of_columns)] 
for i in range(0, number_of_rows): 
    ok = False 
    #result_list.append([]) 
    for h in range(0, number_of_columns): 
     item = parsed_dictionary[i,h] 
     if type(item) is StringType or type(item) is UnicodeType: 
      item = item.replace("\t","").strip() 
     result_list[i,h] = item 
     if item != '': 
      ok = True 
    if not ok: 
     break 
+0

El problema es que no sé el tamaño del archivo xls. Entonces la variable 'number_of_rows' es solo el tamaño máximo, supongo. Entonces ... ¿la preasignación llevará demasiada memoria? –

+0

¿Conoce el número de columnas pero no las filas? ¿El conteo de la columna es fijo? En cualquier caso, podría valer la pena intentarlo. Haga una comparación de rendimiento de subconjuntos con los dos algoritmos diferentes, por ejemplo, 1000 filas. Puedes medir desde allí. –

+0

Gracias. Vale la pena probar, por supuesto: P. Y tiene razón, el recuento de columnas es fijo, y no sé el número de filas. –

1

Sin relación con su pregunta: Si usted está tratando de comprobar si ninguna de las columnas son cadena vacía, a continuación, establece ok = True inicialmente, y hacer esto en su lugar en el bucle interno (ok = ok and item != ''). Además, puede usar isinstance(item, basestring) para probar si una variable es cadena o no.

Versión revisada

for i in range(0, number_of_rows): 
    ok = True 
    result_list.append([]) 
    for h in range(0, number_of_columns): 
     item = parsed_dictionary[i,h] 
     if isinstance(item, basestring): 
      item = item.replace("\t","").strip() 
     result_list[i].append(item) 
     ok = ok and item != '' 

    if not ok: 
     break 
+0

¡Gracias! No me he sentido cómodo con el 'tipo (elemento) es StringType o el tipo (elemento) es cosa de UnicodeType' durante tanto tiempo. Pero no creo que el 'ok = ok y el elemento! = ''' Fácil de leer después, solo un poco hacky :) –

Cuestiones relacionadas