如何从包含多个表的 excel 表中解析数据帧(使用 Python,可能是 Pandas)

Jad*_*d S 5 python excel pandas

我正在处理布局不合理的 Excel 表格,我正试图解析这些表格并将其写入数据库。

每个工作表可以有多个表。虽然这些可能的表格的标题是已知的,但哪些表格将出现在任何给定的工作表上,但它们在工作表上的确切位置也不是(表格没有以一致的方式对齐)。我添加了两张可能的工作表布局的图片来说明这一点:此布局有两个表格,而这个布局包含第一个表格的所有表格,但不在同一位置,另外还有一个表格。

我所知道的:

  1. 所有可能的表头,所以每个单独的表都可以通过它的头来识别
  2. 表格由空白单元格分隔。他们不互相接触。

我的问题有没有一种干净的方法可以使用一些 Python 模块(例如 Pandas)来处理这个问题?

我目前的做法

我目前正在转换为 .csv 并解析每一行。我围绕空白单元格拆分每一行,并处理该行的第一部分(应该属于最左边的表格)。该行的其余部分排队,稍后以相同的方式处理。然后我阅读了这个first_part并检查它是否是标题行。如果是,我用它来识别我正在处理哪个表(它存储在一个 global 中current_df)。不是标题行的后续行被送入该表(这里我pandas.DataFrame用于我的表)。

到目前为止的代码如下(大部分不完整且未经测试,但它应该传达上述方法):

class DFManager(object): # keeps track of current table and its headers
    current_df = None
    current_headers = []

    def set_current_df(self, df, headers):
        self.current_headers = headers
        self.current_df = df


def split_row(row, separator):
    while row and row[0] == separator:
       row.pop(0)
    while row and row[-1] == separator:
       row.pop()

    if separator in row:
        split_index = row.index(separator)
        return row[:split_index], row[split_index:]
    else:
        return row, []


def process_df_row(row, dfmgr):
    df = df_with_header(row) # returns the dataframe with these headers

    if df is None: # is not a header row, add it to current df
        df = dfmgr.current_df
        add_row_to_df(row, df)
    else:
        dfmgr.set_current_df(df, row)


# this is passed the Excel sheet
def populate_dataframes(xl_sheet):
    dfmgr = DFManager()
    row_queue = Queue()
    for row in xl_sheet:
        row_queue.put(row)

    for row in iter(row_queue.get, None):
        if not row:
            continue

        first_part, remainder = split_row(row)
        row_queue.put(remainder)

        process_df_row(first_part, dfmgr)
Run Code Online (Sandbox Code Playgroud)

kdd*_*kdd 2

这是一种特殊的情况,可能没有“干净”的方法来使用现成的模块来做到这一点。

一种方法是使用您已经拥有的标头信息来查找每个表的起始索引,类似于此解决方案(Python Pandas - 读取包含多个表的 csv 文件),但也在列方向上有偏移量。

一旦获得每个表的起始位置,您将需要确定宽度(先验已知或通过读取直到下一个空白列发现)并将这些列读入数据帧直到表末尾。

基于索引的方法而不是基于队列的方法的好处是,您不需要重新发现分隔符在每行中的位置,也不需要跟踪哪些行片段属于哪个表。它对于每行是否存在 >2 个表也是不可知的。