es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo se convierte un rango de win32com.client en un DataFrame de Pandas?

Estoy escribiendo algunas macros que llaman código de Python para realizar operaciones en rangos de Excel. Es mucho más fácil realizar muchas de las operaciones requeridas con pandas en Python. Como quiero hacer esto mientras la hoja de cálculo está abierta (y es posible que no se haya guardado), estoy utilizando win32com.client para leer un rango de celdas y convertirlo en un dataframe de Pandas. Sin embargo, esto es extremadamente lento, presumiblemente porque la forma en que lo calculo es muy ineficiente:

import datetime
import pytz
import pandas
import time
import win32com.client
def rango_a_tabla(rangoExcel, tsy, tsx, altura, ancho, agregar_referencias_celdas = True):
  ii = 0
  claves = []
  while ii < ancho:
    claves.append(str(rangoExcel[ii]))
    ii += 1
  numerosColumnas = {clave:jj+tsx for jj, clave in enumerate(claves)}
  claves.append('numeroFila')
  midiccionario = {clave:[] for clave in claves}
  while ii < ancho*altura:
    midiccionario[claves[ii%ancho]].append(rangoExcel[ii].value)
    ii += 1
  for yy in range(tsy + 1, tsy + 1 + altura - 1): # sumar 1 para no incluir la cabecera
    midiccionario['numeroFila'].append(yy)
  return (midiccionario, numerosColumnas)
ExcelApp = win32com.client.GetActiveObject('Excel.Application')
wb = ExcelApp.Workbooks('miarchivo.xlsm')
numHoja = [hoja.Nombre for hoja in wb.Hojas].index("nombre_de_mi_hoja") + 1
ws = wb.Worksheets(numHoja)
altura = int(ws.Cells(1, 3)) # obtener altura de la tabla desde la fórmula en la hoja de cálculo de Excel
ancho = int(ws.Cells(1, 2)) # obtener ancho de la tabla desde la fórmula en la hoja de cálculo de Excel
miRango = ws.Range(ws.Cells(2, 1), ws.Cells(2 + altura - 1, 1 + ancho - 1))
df, numerosColumnas = rango_a_tabla(miRango, 1, 1, altura, ancho)
df = pandas.DataFrame.from_dict(df)

Esto funciona, pero la función rango_a_tabla que escribí es extremadamente lenta para tablas grandes, ya que itera sobre cada celda una por una.

Sospecho que probablemente haya una forma mucho mejor de convertir el objeto Range de Excel en un dataframe de Pandas. ¿Conoce alguna forma mejor de hacerlo?

Aquí hay un ejemplo simplificado de cómo se vería mi rango:

enter image description here

Las variables altura y ancho en el código son simplemente tomadas de las celdas inmediatamente arriba de la tabla:

enter image description here

¿Alguna idea aquí, o simplemente tendré que guardar el libro de trabajo y usar Pandas para leer la tabla desde el archivo guardado?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Una posible solución para acelerar la conversión de un objeto de rango de Excel a un dataframe de Pandas es utilizar la biblioteca numpy para crear un arreglo de NumPy a partir del objeto de rango de Excel y luego convertirlo a un dataframe de Pandas. numpy generalmente es más rápido al recorrer arreglos y puede manejar conjuntos de datos más grandes de manera más eficiente. Aquí tienes un ejemplo de implementación:

    import win32com.client
    import pandas as pd
    import numpy as np
    
    ExcelApp = win32com.client.GetActiveObject('Excel.Application')
    wb = ExcelApp.Workbooks('miarchivo.xlsm')
    sheet_num = [sheet.Name for sheet in wb.Sheets].index("nombreamiplantilla") + 1
    ws = wb.Worksheets(sheet_num)
    
    altura = int(ws.Cells(1, 3).Value)
    ancho = int(ws.Cells(1, 2).Value)
    
    rango = ws.Range(ws.Cells(2, 1), ws.Cells(2 + altura - 1, 1 + ancho - 1))
    
    # Crear un arreglo de NumPy a partir del rango de Excel
    arreglo = np.array(rango.Value)
    
    # Eliminar la primera fila, que contiene los encabezados de columna
    arreglo = np.delete(arreglo, 0, axis=0)
    
    # Crear un dataframe de Pandas a partir del arreglo de NumPy
    df = pd.DataFrame(arreglo)
    
    # Agregar los nombres de columna de la primera fila del rango de Excel
    df.columns = list(rango.Rows(1).Value[0])
    
    # Agregar una columna de número de fila
    df.insert(0, "numerofila", range(1, len(df) + 1))
    
    # Opcional: convertir las columnas al tipo de dato adecuado
    df["fecha"] = pd.to_datetime(df["fecha"])
    
    # Imprimir el dataframe de Pandas resultante
    print(df)
    

    Esta implementación utiliza el método np.array para crear un arreglo de NumPy a partir del rango de Excel, elimina la primera fila (que contiene los encabezados de columna) y luego crea un dataframe de Pandas a partir del arreglo de NumPy. Luego agrega los encabezados de columna de la primera fila del rango de Excel y una columna de número de fila. Finalmente, convierte las columnas al tipo de dato adecuado (por ejemplo, una columna de fecha a un objeto datetime de Pandas).

    Este enfoque debería ser más rápido que iterar sobre las celdas del rango de Excel una por una. Sin embargo, es importante tener en cuenta que la velocidad de la conversión dependerá en última instancia del tamaño del rango de Excel y del poder de procesamiento de la computadora en la que se ejecute el código.

Comments are closed.