3

我正在使用 Excel 和 xlwings。我有一个 book.xlsm,在第一张纸上有一个分配给以下 vba 代码的按钮:

book.xlsm!ThisWorkbook.get_data

在 VBA 上,我添加了这个,当调用按钮并执行 vba 代码时,它运行:

Sub get_data()
    RunPython ("import my_script; my_script.get_data()")
End Sub

my_script 如下:

import pandas as pd
from xlwings import Workbook, Range

def get_data():
    wb = Workbook.caller()

    df = pd.read_csv("data.csv")
    Range("Sheet2", "A1").value = df

我遇到的问题如下:

pywintypes.com_error: (-2147024882, 'Not enough storage is available to complete this operation.', None, None)

data.csv 文件有 150000 行和 120 行。使用更少的数据,它运行没有错误。

更新:目前没有解决方案,但评论中提供了一种解决方法:https ://github.com/ZoomerAnalytics/xlwings/issues/77

我使用以下内容:

df = pd.read_csv(csv_file, na_values={"", " ", "-"})
df.fillna("-", inplace=True)
startcell = 'A1'
chunk_size = 2500
if len(df) <= (chunk_size + 1):
    Range(sheet_name, startcell, index=False).value = df
else:  # chunk df and and dump each (default is 10k)\n",
    c = re.match(r"([a-z]+)([0-9]+)", startcell, re.I)
    cL = c.group(1)
    cN = int(c.group(2))
    n = 0
    for i in (df[rw:rw + chunk_size] for rw in xrange(0, len(df), chunk_size)):
        if n == 0:
            Range(sheet_name, cL + str(cN+n), index=False).value = i
            cN += chunk_size
        else:
            Range(sheet_name, cL + str(cN+n)).value = i.values
            cN += chunk_size
        n += 1

我遇到的问题是,当我在工作表中插入数据时,在 5002 处有一个空行,在 7503、10004 处再次出现......我意识到我的代码中有错误,但我找不到它。

4

3 回答 3

3

GitHub问题页面上发布了一个解决方法功能。它将 DataFrame 分成更小的块并将它们插入 Excel。不幸的是,正如您所注意到的,该函数存在错误并导致块​​之间出现空行。

我修改了这个功能,现在它工作得很好。

# Dumps a large DataFrame in Excel via xlwings.
# Does not include headers.
def dump_largeDF(df, startcell='A1', chunk_size=100000):
    if len(df) <= (chunk_size + 1):
        Range(startcell, index=False, header=False).value = df
    else: # Chunk df and and dump each
        c = re.match(r"([a-z]+)([0-9]+)", startcell, re.I) # A1
        row = c.group(1) # A
        col = int(c.group(2)) # 1
        for chunk in (df[rw:rw + chunk_size] for rw in
                      range(0, len(df), chunk_size)):
            print("Dumping chunk in %s%s" %(row, col))
            Range(row + str(col), index=False, header=False).value = chunk
            col += chunk_size

对我来说,100k 的块大小就可以了,但是您可以根据需要更改它。

于 2015-01-07T16:20:58.087 回答
0

很抱歉复活一个旧线程。

当我将上述函数作为另一个函数的调用运行时,我会遇到各种错误,主要是在Range项目周围。是否可以“独立”编写此函数以使其包含import和目标wb?我有:

def dump_largeDF(wb, df, sheetName, startcell, chunk_size):
    import pandas as pd
    import xlwings as xw
    import re

    if len(df) <= (chunk_size + 1):
        wb.sheets(sheetName).Range(startcell, index=False, header=False).value = df
    else: # Chunk df and and dump each
        c = re.match(r"([a-z]+)([0-9]+)", startcell, re.I) # A1
        row = c.group(1) # A
        col = int(c.group(2)) # 1
        for chunk in (df[rw:rw + chunk_size] for rw in range(0, len(df), chunk_size)):
            wb.sheets(sheetName).Range(row + str(col), index=False, header=False).value = chunk
            col += chunk_size
于 2016-12-13T21:35:25.110 回答
0

对于热衷于正确处理标头而不依赖 Range 的每个人,我对代码进行了一些修改:

def dumpLargeDf(wb, df, startcell='A1', chunk_size=50000):
    # Dumps a large DataFrame in Excel via xlwings. Takes care of header.
    if len(df) <= (chunk_size + 1):
        wb.sheets.active.range(startcell).options(index=False).value = df
    else:                                       # Chunk df and and dump each
        c = re.match(r"([a-z]+)([0-9]+)", startcell, re.I)      # A1
        row = c.group(1)                                        # A
        col = int(c.group(2))                                   # 1
        useHeader = True
        for chunk in (df[rw:rw + chunk_size] for rw in
                      range(0, len(df), chunk_size)):
            print("Dumping chunk in %s%s" % (row, col))
            wb.sheets.active.range(row + str(col)) \
                .options(index=False, header=useHeader).value = chunk
            useHeader = False
            col += chunk_size
于 2020-10-18T22:14:07.690 回答