Python基于pandas无视表头和备注合并excel表格多个sheet的示例

时间:2024-10-08 12:58:35

首先,我们来看一个表格示例

这是一个excel文件的三个sheet,第一个sheet有表头和没有列名的备注,第二个sheet没有表头,第三个sheet有多级表头。如果用一般的合并excel的方法,在不改动原始数据的情况下无法合并成标准格式。那么,如何把这样的三个sheet合并成一个sheet?这是我的源代码和运行结果:

  1. import pandas
  2. excel = '班级成员信息表.xls'
  3. df = pandas.read_excel(excel, sheet_name=None) # sheet_name参数为None 代表读取所有sheet
  4. sheet_names = list(()) # 获取所有sheet名字,如果read_excel参数不是None,则()为表头
  5. df_empty = (data=None) # 建立一个空DataFrame
  6. for sheet in sheet_names:
  7. df1 = pandas.read_excel(excel, sheet_name=sheet) # 以DataFrame的格式读取文件中名为”sheet“的表
  8. df2 = str(()) # 把df1的列索引转换为列表之后再转换成一个字符串
  9. splits = ('Unnamed') # 把df2以”Unnamed“分割,以列表形式记录
  10. header = 1
  11. # 找到列名所在的行:从第一行开始,逐行检测其中的Unnamed个数。如果Unnamed过多,则说明本行很可能是表头,那就把该行跳过,继续查找第二行中Unnamed的个数。
  12. # 当其个数小于我们所设定的值的时候,说明该行是列名。因此从该行开始读取,把之前的表头信息抛弃。本代码设值为2,意味允许表格有两列的无列名的列。该值可以视情况自行更改。
  13. while len(splits) - 1 >= 2: # len(splits)-1的含义是分割次数,即字符串中Unnamed的个数
  14. df1 = pandas.read_excel(excel, sheet_name=sheet, header=header) # header=2时,以第二行为表头,变相第丢掉了第一行数据
  15. df2 = str(()) # 把df1的列索引转换为列表之后再转换成一个字符串
  16. header += 1
  17. print(df2)
  18. splits = ('Unnamed') # 返回拆分数组
  19. print(splits)
  20. ([df1, df1], sort=False) # sort=False是对合并后列的顺序保持原来的顺序
  21. df_empty = ([df_empty, df1], sort=False) # 把确定好的df1和空表合并
  22. name = 'test' # 保存的新文件名
  23. Sheet_name = '新数据' # 新的sheet名
  24. xlsx = (name + '.xlsx')
  25. df_empty.to_excel(xlsx, Sheet_name, index=False)
  26. xlsx._save() # 保存表格

————————————————————————————————————

如果不了解DataFrame类型数据,可以查看这个帖子,了解清楚DataFrame对于理解本文是很重要的(除非只是打算copy代码用一下)Python 之 Pandas DataFrame 数据类型的简介、创建的列操作_dataframe每列数据类型_虚心求知的熊的博客-****博客

首先说明一下常规方法。我经过查找帖子发现,一般的方法就是把excel表格转换成DataFrame类型,这样它的列索引会变成列名。之后再将多个DataFrame合并为一个,最后再转换回excel表格。这种常规办法无法处理有表头的表格,如果一个sheet有表头,那么在转换成DataFrame类型的时候列索引就不是列名,而是表头加上一堆“Unnamed: 1”这种格式的东西。而我找到的去除表头的方法一般也是固定的跳过表头那行。但是像这种表格,有的sheet没表头,有的有表头,有的甚至还有多级表头,就没法用这种方法解决。此外还有无列名的备注等信息,这样的信息也会在常规方法中添加阻挠。

对于这样的合并,总结难点有两处:一是如何准确识别并去除表头,二是如何正确处理备注信息。我所采用的关键点正是之前说的阻止正常格式的Unnamed。

Unnamed的产生是因为表格有很多列数据,但是表头那行只有一个或两个数据。而列索引必须要以最大列数为准,因此便多了好多个Unnamed来作为默认索引。我的想法是,如果可以从第一行开始遍历表格,如果该行有Unnamed,那么就继续找下一行,直到找到一行没有Unnamed,以该行为列索引。但是这样也有一个问题,就是如果表格中包含没有列名的备注等数据,那么即使在遍历到列名那行的时候依旧会识别到Unnamed。因此,以下是我最终的思路:

依旧是遍历每行,但是要找出每行Unnamed的数量。规定一个值,当数量多于这个值的时候认定其为表头,第一次少于这个值的时候认定其为列名,并从该行开始读取。这个值的含义就是可允许的最大备注列数。比如我前面给出的示例,最大允许两行备注。

————————————————————————————————————

接下来介绍几个本文用到的pandas库的关键方法:

pandas.read_excel(excel, sheet_name=sheet, header=header)  这是把sheet转换为DataFrame的方法,其中的两个参数,sheet_name为sheet的名称,=None时代表读取excel内所有sheet。header是表头,例如当header=2时,以第二行为表头,也就变相第丢掉了第一行数据。

  这个方法会得到DataFrame的列索引。

([df1, df2], sort=False)  这个方法可以把两个DataFrame合并成一个,并且合并后的DataFrame拥有二者所有的列索引。参数sort=False代表合并后的DataFrame的列的顺序保持原来的顺序。

df.to_excel(xlsx, Sheet_name, index=False)  这个方法可以把DataFrame转换成excel表格。第一个参数记录表格的路径和名称,第二个参数记录sheet名称,index是是否保留索引。

还有一个如何识别每行有几个Unnamed的方法:用获得列索引并转换成list,之后再转换成string。用string的split()方法将其分割成列表,那么列表元素的个数就是分割次数+1,也就是Unnamed个数+1。

————————————————————————————————————

最后,由于本文写于旅行之前,写的比较匆忙,如果有错误欢迎大家在评论区指出并探讨交流。