首页 > 解决方案 > Openpyxl - 将两个表的匹配行组合成一个长行

问题描述

在 Excel 文件中,我有两个大表。表 A(“解剖”,409 行 x 25 列)包含唯一条目,每个条目由唯一 ID 分隔。表 B(“解剖”,234 行 x 39 列)在第一个单元格中使用表 A 的 ID 并对其进行扩展。要在 Minitab 中分析数据,所有数据必须位于一个长行中,这意味着“Damage”的值必须遵循“Dissection”。整个事情看起来像这样:

Table A - i.e. Dissection
- ID1 [valueTabA] [valueTabA]
- ID2 [valueTabA] [valueTabA]
- ID3 [valueTabA] [valueTabA]
- ID4 [valueTabA] [valueTabA]

Table B - i.e. Damage
- ID1 [valueTabB1] [valueTabB1]
- ID1 [valueTabB2] [valueTabB2]
- ID4 [valueTabB] [valueTabB]

他们应该结合这样的东西:

Table A
- ID1 [valueTabA] [valueTabA] [valueTabB1] [valueTabB1] [valueTabB2] [valueTabB2]
- ID2 [valueTabA] [valueTabA]
- ID3 [valueTabA] [valueTabA]
- ID4 [valueTabA] [valueTabA] [valueTabB] [valueTabB]

最好的方法是什么?


下面介绍我的两种方法。两者都在相同的表中使用相同的数据,但在两个不同的文件中,以便能够测试两种方案。

第一种方法使用一个文件,两个表都在同一个工作表中,第二种方法使用一个文件,两个表都在不同的工作表中。


  1. 场景:两个表都在同一个工作表中,我试图将行作为一个范围移动
current_row = 415 # start without headers of table A
current_line = 2 # start without headers of table B


for row in ws.iter_rows(min_row=415, max_row=647):
    # loop through damage

    id_A = ws.cell(row=current_row, column=1).value
    max_col = 25

    for line in ws.iter_rows(min_row=2, max_row=409):
        # loop through dissection

        id_B = ws.cell(row=current_line, column=1).value

        if id_A == id_B:
            copy_range = ((ws.cell(row=current_line, column=2)).column_letter + str(current_line) + ":" +
                          (ws.cell(row=current_line, column=39)).column_letter + str(current_line))

            ws.move_range(copy_range, rows=current_row, cols=max_col+1)
            print("copied range: " + copy_range +" to: " + str(current_row) + ":"+str(max_col+1))
            count += 1
            break

        if current_line > 409:
            current_line = 2
        else:
            current_line += 1

    current_row += 1

-> 在这里,我正在努力将范围附加到表 A 的右行,而不覆盖前一行(参见上面的示例 ID1)


  1. 场景:两个表都位于单独的工作表中
    dissection = wb["Dissection"]
    damage = wb["Damage"]
    recovery = wb["Recovery"]
    
    current_row, current_line = 2, 2
    
    for row in damage.iter_rows():
        # loop through first table
    
        id_A = damage.cell(row=current_row, column=1).value
    
        for line in dissection.iter_rows():
            # loop through second table
    
            id_B = dissection.cell(row=current_line, column=1).value
            copyData = []
    
            if id_A == id_B:
    
                for col in range(2, 39):
                    # add data to the list, skipping the ID
                    copyData.append(damage.cell(row=current_line, column=col).value)
    
                # print(copyData) for debugging purposes
    
                for item in copyData:
                    column_count = dissection.max_column
    
                    dissection.cell(row=current_row, column=column_count).value = item
                    column_count += 1
    
                current_row += 1
                break
    
            if not current_line > 409:
                # prevent looping out of range
                current_line += 1
            else:
                current_line = 2

-> 与 1. 中的问题相同,在某些时候它不再添加损坏值,copyData而是None,最后它只是不粘贴项目(单元格保持空白)


我已经尝试了所有我能找到的与excel相关的东西,但不幸的是没有任何效果。熊猫在这里会更有用还是我只是没有看到什么?

感谢您抽时间阅读 :)

标签: pythonpython-3.xexcelpandasopenpyxl

解决方案


我强烈建议pandas在这种情况下使用。仍然有点不清楚您的数据在excel文件中的格式,但考虑到您的第二个选项,我假设这些表都位于excel文件的不同工作表上。我还假设第一行包含表格标题(例如Table A - i.e. Dissection)。如果不是这种情况,只需删除skiprows=1

import pandas as pd

df = pd.concat(pd.read_excel("filename.xlsx", sheet_name=None, skiprows=1, header=None), axis=1, ignore_index=True)
df.to_excel('combined_data.xlsx) #save to excel

read_excelexcel文件加载到pandas数据框中。sheet_name=None表示所有工作表都应加载到OrderedDict数据框中。pd.concat将这些数据帧连接成一个数据帧(axis=1表示轴)。您可以使用 探索数据df.head(),或使用 将数据框保存exceldf.to_excel


推荐阅读