根据值合并行(熊猫到Excel-xlsxwriter)

时间:2020-04-14 21:57:03

标签: python excel pandas xlsxwriter

我正在尝试使用xlsxwriter将Pandas数据帧输出到excel文件中。但是,我正在尝试应用一些基于规则的格式。特别是试图合并具有相同值的单元格,但是在编写循环时遇到了麻烦。 (这里是Python的新功能!)

有关输出与预期输出的信息,请参见下文:

enter image description here

(您可以根据上图看到,当它们具有相同的值时,我试图合并“名称”列下的单元格)。

这是我到目前为止所拥有的:

componentDidUpdate(prevProps) {
  const { error } = this.props;
  console.log("outside");
  if (error != prevProps.error) {
    console.log("inside");
    if (error.id === 'REGISTER_FAIL') {
      this.setState({ msg: this.props.error.msg })
      console.log("inside error");
    } else if (error.id === null) {
      this.setState({ msg: null })
      console.log("inside login");
      this.props.history.replace("/some");
    }
  }
}

非常感谢您的帮助!

谢谢!

2 个答案:

答案 0 :(得分:2)

您的逻辑几乎是正确的,但是我通过稍微不同的方法来解决您的问题:

1)对列进行排序,确保所有值都分组在一起。

2)重置索引(使用reset_index()并可能通过arg drop = True)。

3)然后,我们必须捕获值为新值的行。为此,请创建一个列表并添加第一行1,因为我们将从此处确定开始。

4)然后开始遍历该列表的行并检查一些条件:

4a)如果只有一行带有一个值,则merge_range方法将出现错误,因为它无法合并一个单元格。在这种情况下,我们需要用write方法替换merge_range。

4b)使用此算法,尝试写入列表的最后一个值时会出现索引错误(因为它正在将其与下一个索引位置中的值进行比较,并且因为它是列表的最后一个值)没有下一个索引位置)。因此,我们需要特别提及的是,如果遇到索引错误(这意味着我们正在检查最后一个值),我们希望合并或写入直到数据帧的最后一行。

4c)最后,我没有考虑列是否包含空白或空单元格。在这种情况下,需要调整代码。

最后的代码可能看起来有些混乱,您必须记住,pandas的第一行的索引为0(标头是单独的),而xlsxwriter的标头的索引为0,而第一行的索引为1。

这是一个可以实际实现您想要做的事的示例:

import pandas as pd

# Create a test df
df = pd.DataFrame({'Name': ['Tesla','Tesla','Toyota','Ford','Ford','Ford'],
                   'Type': ['Model X','Model Y','Corolla','Bronco','Fiesta','Mustang']})

# Create the list where we 'll capture the cells that appear for 1st time,
# add the 1st row and we start checking from 2nd row until end of df
startCells = [1]
for row in range(2,len(df)+1):
    if (df.loc[row-1,'Name'] != df.loc[row-2,'Name']):
        startCells.append(row)


writer = pd.ExcelWriter('test.xlsx', engine='xlsxwriter')
df.to_excel(writer, sheet_name='Sheet1', index=False)
workbook = writer.book
worksheet = writer.sheets['Sheet1']
merge_format = workbook.add_format({'align': 'center', 'valign': 'vcenter', 'border': 2})


lastRow = len(df)

for row in startCells:
    try:
        endRow = startCells[startCells.index(row)+1]-1
        if row == endRow:
            worksheet.write(row, 0, df.loc[row-1,'Name'], merge_format)
        else:
            worksheet.merge_range(row, 0, endRow, 0, df.loc[row-1,'Name'], merge_format)
    except IndexError:
        if row == lastRow:
            worksheet.write(row, 0, df.loc[row-1,'Name'], merge_format)
        else:
            worksheet.merge_range(row, 0, lastRow, 0, df.loc[row-1,'Name'], merge_format)


writer.save()

输出:

enter image description here

答案 1 :(得分:2)

替代方法: 可以使用 unique() 函数查找分配给每个唯一值(在此示例中为汽车名称)的索引。使用上面的测试数据,

import pandas as pd

# Create a test df
df = pd.DataFrame({'Name': ['Tesla','Tesla','Toyota','Ford','Ford','Ford'],
                   'Type': ['Model X','Model Y','Corolla','Bronco','Fiesta','Mustang']})

writer = pd.ExcelWriter('test.xlsx', engine='xlsxwriter')
df.to_excel(writer, sheet_name='Sheet1', index=False)
workbook = writer.book
worksheet = writer.sheets['Sheet1']
merge_format = workbook.add_format({'align': 'center', 'valign': 'vcenter', 'border': 2})

for car in df['Name'].unique():
    # find indices and add one to account for header
    u=df.loc[df['Name']==car].index.values + 1

    if len(u) <2: 
        pass # do not merge cells if there is only one car name
    else:
        # merge cells using the first and last indices
        worksheet.merge_range(u[0], 0, u[-1], 0, df.loc[u[0],'Name'], merge_format)
writer.save()