【问题标题】:Compare columns from different excel files and add a column at the beginning of each with the output比较来自不同 excel 文件的列,并在每个输出的开头添加一列
【发布时间】:2016-09-08 18:11:36
【问题描述】:

首先我想说我不是 Excel 专家,所以我需要一些帮助。

假设我有 3 个 excel 文件:main.xlsx1.xlsx2.xlsx。在所有这些中,我都有一个名为Serial Numbers 的列。我必须:

  • 1.xlsx2.xlsx 中查找所有序列号,并验证它们是否在main.xlsx 中。

如果找到序列号:

  • main.xlsx 的最后一列,与找到写入OK + name_of_the_file_in which_it_was_found序列号 位于同一行。否则,写NOK。同时,如果找到序列号,在最后一栏写上1.xlsx2.xlsxoknok

提及serial number 可以在 1.xlsx2.xlsx 的不同列中

示例:

ma​​in.xlsx

name date serial number phone status
a      b      abcd        c         <-- ok,2.xlsx
b      c      1234        d         <-- ok,1.xlsx
c      d      3456        e         <-- ok,1.xlsx
d      e      4567        f         <-- NOK
e      f                  g         <-- skip,don't write anything to status column

1.xlsx

name date serial number phone status
a      b      1234        c          <-- OK (because is find in main)
b      c      lala        d          <-- NOK (because not find in main)
c      d      3456        e          <-- OK (because find main)
d      e      jjjj        f          <-- NOK (because not find in main)
e      f                  g          <-- skip,don't write anything to status column

2.xlsx

name date serial number phone status
a      b                  c          <-- skip,don't write anything to status column
b      c      abcd        d          <-- OK (because find main)
c      d      4533        e          <-- NOK (because not find in main)
d      e      jjjj        f          <-- NOK (because not find in main)
e      f                  g          <-- skip,don't write anything to status column

现在,我尝试在 Python 中执行此操作,但显然我不知道如何在找到 serial number 的同一行上写入状态列(尝试使用 dataFrames)。任何帮助将非常感激。 (或至少一些指导)

我的问题不是找到重复项,而是跟踪行(在正确的serial number 上写入状态)并在指定列(status 列)写入 excel。

我的尝试:

import pandas as pd

get_main = pd.ExcelFile('main.xlsx')
get_1 = pd.ExcelFile('1.xlsx')
get_2 = pd.ExcelFile('2.xlsx')

sheet1_from_main = get_main.parse(0)
sheet1_from_1 = get_1.parse(0)
sheet1_from_2 = get_2.parse(0)


column_from_main = sheet1_from_main.iloc[:, 2].real
column_from_main_py = []
for x in column_from_main:
    column_from_main_py.append(x)


column_from_1 = sheet1_from_1.iloc[:, 2].real
column_from_1_py = []
for y in column_from_1:
    column_from_1_py.append(y)


column_from_2 = sheet1_from_2.iloc[:, 2].real
column_2_py = []
for z in column_from_2:
    column_2_py.append(z)

建议编辑:

import pandas as pd

get_main = pd.read_excel('main.xls', sheetname=0)
get_1 = pd.read_excel('1.xls', sheetname=0)
get_2 = pd.read_excel('2.xls', sheetname=0)


column_from_main = get_main.ix[:, 'Serial No.'].real
column_from_main_py = column_from_main.tolist()


column_from_1 = get_1.ix[:, 'SERIAL NUMBER'].real
column_from_1_py = column_from_1.tolist()


column_from_2 = get_2.ix[:, 'S/N'].real
column_from_2_py = column_from_2.tolist()

# Tried to put example data at specific column

df = pd.DataFrame({'Data': [10, 20, 30, 20, 15, 30, 45]})
writer = pd.ExcelWriter('first.xlsx', engine='xlsxwriter')
df.to_excel(writer, sheet_name='Sheet1')
workbook = writer.book
worksheet = writer.sheets['Sheet1']
worksheet.set_column('M:M', None, None)
writer.save()

【问题讨论】:

    标签: python excel python-3.x pandas


    【解决方案1】:

    首先,您可以跳过使用 excelfile 并使用 pd.read_excel(filename, sheetname=0) 进行解析。

    就您的列而言,请尝试按名称访问列,而不是按索引。并且不要使用 for 循环来创建列表,而是使用 tolist 方法。因此,您可以说:

    而不是 column_from_main = sheet1_from_main.iloc[:, 2].real
    column_from_main = get_main.ix[:, 'serial number'].real
    column_from_main_py = column_from_main.tolist()
    

    对您的其他文件也执行相同的操作。这将消除序列号列被不同索引的任何问题,并且运行速度更快。

    关于您关于无法正确写入“状态”的评论,您能否展示您尝试过的代码?我非常乐意提供帮助,但很高兴看到您到目前为止所做的一切。

    为了对照其他两个文件检查 main 中的值,您需要遍历您创建的列表并检查主列表中的每个值是否在其他列表中。然后,在该循环中,您可以根据 main 中的序列号是否存在于一个、无或两者中来分配 status 的值:

    get_main['status'] = ''
    get_1['status'] = ''
    get_2['status'] = ''
    for num in column_from_main_py:
        if num not in column_from_1_py and not in column_from_2_py:
            get_main.loc[get_main['serial number'] == num, 'status'] = 'NOK'
        elif num in column_from_1_py and not in column_from_2_py:
            get_main.loc[get_main['serial number'] == num, 'status'] = 'OK,1.xlsx'
            get_1.loc[get_1['serial number'] == num, 'status'] = 'OK'
        elif num not in column_from_1_py and in column_from_2_py:
            get_main.loc[get_main['serial number'] == num, 'status'] = 'OK,2.xlsx'
            get_2.loc[get_2['serial number'] == num, 'status'] = 'OK'
    

    get_main.loc 行是您为状态列设置 OK 或 NOK 值的地方。本质上,它会找到某些条件为真的索引,然后让您更改该索引处特定列的值。浏览完主列表后,您可以查看 1 和 2 的列表以查找不在主列表中的序列号。同样:

    for num in column_from_1_py:
        if num not in column_from_main_py:
            get_1.loc[get_1['serial number'] == num, 'status'] = 'NOK'
    for num in column_from_2_py:
        if num not in column_from_main_py:
            get_2.loc[get_2['serial number'] == num, 'status'] = 'NOK'
    

    这将为您设置 NOK 值,您应该继续将数据帧导出到 excel(或 csv、hdf、sql 等),这样就可以了。

    您可以通过多种方式索引和选择 pandas 中的数据,具体取决于您想要做什么。我建议阅读文档中的Indexing and Selecting Data 页面,因为它对我来说是一个很好的参考。

    【讨论】:

    • 谢谢,到目前为止我已经进行了修改。我将编辑我的答案以显示我尝试过的内容 ^^ 但是我收到了您提出的错误:column_from_1_py = column_from_1.tolistt() AttributeError: 'numpy.ndarray' object has no attribute 'tolistt' 有什么想法吗?
    • Nvm,我只是拼错了^^。其他想法?
    • 而不是将数据放入 excel 文件中的列中,而是在数据框中执行它,一旦您更新了所有内容,然后使用 pd.to_excel() 将其导出回来。我必须出去过夜,但如果还不够清楚,明天应该可以提供更多帮助。
    • 好吧,不用着急。如果我想出一些东西,我会尝试锻炼你的建议并编辑主要帖子。祝你晚安
    • @Dex'ter 编辑应该对您有所帮助。虽然复制和粘贴答案可能有效,但我认为此解决方案稍微优雅一些​​,但这取决于您的口味
    【解决方案2】:

    请注意,问题中提供的输入文件并不是实际使用的输入文件。在获得真实的输入文件后,构建了以下信息/脚本。以下不适用于当前提出的问题。

    要使用以下示例,您首先安装 petl 和 openpyxl(用于您的 xlsx 文件):

    pip install openpyxl
    pip install petl
    

    脚本:

    import petl
    
    main = petl.fromxlsx('main.xlsx')
    one = petl.fromxlsx('1.xlsx', row_offset=1)
    two = petl.fromxlsx('2.xlsx')
    
    non_serial_rows = petl.select(main, lambda rec: rec['serial number'] is None)
    serial_rows = petl.select(main, lambda rec: rec['serial number'] is not None)
    main_join_one = petl.join(serial_rows, petl.cut(one,['serial number']), key='serial number')
    main_join_one_file = petl.addfield(main_join_one, 'file', 'ok, 1.xlsx')
    main_join_two = petl.join(serial_rows, petl.cut(two,['serial number']), key='serial number')
    main_join_two_file = petl.addfield(main_join_two, 'file', 'ok, 2.xlsx')
    stacked_joins = petl.stack(main_join_two_file, main_join_one_file)
    nok_rows = petl.antijoin(serial_rows, petl.cut(stacked_joins, ['serial number']),  key='serial number')
    nok_rows = petl.addfield(nok_rows, 'file', 'NOK')
    output_main = petl.stack(stacked_joins, non_serial_rows, nok_rows)
    main_final = output_main
    
    def main_compare(table):
        non_serial_rows = petl.select(table, lambda rec: rec['serial number'] is None)
        serial_rows = petl.select(table, lambda rec: rec['serial number'] is not None)
        ok_rows = petl.join(serial_rows, petl.cut(main, ['serial number']), key='serial number')
        ok_rows = petl.addfield(ok_rows, 'file', 'OK')
        nok_rows = petl.antijoin(serial_rows, petl.cut(main, ['serial number']), key='serial number')
        nok_rows = petl.addfield(nok_rows, 'file', 'NOK')
        return petl.stack(ok_rows, nok_rows, non_serial_rows)
    
    one_final = main_compare(one)
    two_final = main_compare(two)
    
    petl.toxlsx(main_final, 'mainNew.xlsx')
    print petl.lookall(main_final)
    petl.toxlsx(one_final, '1New.xlsx')
    print petl.lookall(one_final)
    petl.toxlsx(two_final, '2New.xlsx')
    print petl.lookall(two_final)
    

    输出(控制台上的文本,以及实际修改的 xlsx 文件)

    【讨论】:

    • 谢谢 ^^ 不幸的是我得到了这个:petl.errors.FieldSelectionError: selection is not a field or valid field index: 'serial number' 尝试petl.toxlsx(main_final, 'mainNew.xlsx')
    • 您的 xlsx 之一(main、1 或 2)与您的示例中显示的不一样。列序列号的其中一个文件的标题中必须有空格或拼写错误
    • 我的测试文件在这里:filedropper.com/testfiles_2。另外我正在使用 python 2.7
    • @Dex'ter 我稍微修改了脚本以适应格式的变化。存在重大差异会导致代码破坏
    • 哇,这几乎是完美的。但是有一件奇怪的事情:在新的 xlsx 文件中,行数比最初的多。这是为什么 ?基本上,每个输出的文件应该有相同的行数,不是吗?
    猜你喜欢
    • 2021-01-16
    • 2017-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-08
    • 2018-01-09
    • 2017-09-18
    相关资源
    最近更新 更多