Python: 利用pandas包完成多层次表头excel数据的转置操作

问题

因为业务要求,需要将表A转化为表B方便后续关联其他信息,分析商品上货情况。

表A

表B

初级方法

使用的关键函数为:fillna(),MultiIndex.from_product(),stack(),reset_index()

导入数据

导入xlsx使用的是pd.read_excel()

需要注意的是pandas导入xlsx使用的是xlrd包,而只有旧版本的xlrd(1.2.0) 包支持导入xlsx文件,最新版本的xlrd包不支持xlsx而支持xls。

import pandas as pd
df_raw = pd.read_excel(r'XXXXX\practice.xlsx')

观察数据

导入数据之后,需要根据数据呈现出的格式进行相应的操作。
图1
可以看出:

  1. excel中作为列信息的店铺在读取之后变成了行信息;
  2. 合并的单元格被拆分,并且拆分后只有一个单元格有信息。

处理思路及代码

  1. 将产品类别和产品质量字段设置为index,然后设置店铺等级和店铺为多层级columns;
  2. 使用stack()对表格进行转置操作,此时多层次的columns也变为了index;
  3. 使用reset_index()将index恢复为列即完成。

第一步:

from collections import OrderedDict #该包用于生成去重并且顺序不变的列名列表
def remove_duplicates(lst):#定义列表去重并不改变顺序的函数
    return list(OrderedDict.fromkeys(lst))

df = df_raw.copy()
df.fillna(method = 'ffill',inplace = True)
#生成第二层级的列名列表
col_index = remove_duplicates(df.iloc[0,:][df.iloc[0,:].notna()].to_list())
#删除第一行
df = df.drop(0,axis = 0)
#set_index
df = df.set_index(['产品类别','产品质量'])
#添加columns index
col_index2 = [x for x in df.columns.to_list() if 'Unnamed'not in x ]#生成第一层级的列名列表,这一步要在set_index之后,否则会把多余的列名也包含在内
columns_multiindex = pd.MultiIndex.from_product([col_index2,col_index], names=['店铺等级', '店铺'])
df.columns=columns_multiindex

添加完index和多层级columns之后效果如下:
图2
第二三步:

#stack,将column index 转化为index(类比excel里的行列转置操作),然后通过reset_index将所有index恢复为列
df = df.stack(['店铺等级', '店铺']).reset_index()
df

效果:
图3
PS:这么一通操作总算是对dataframe的索引有了更深的了解了,iloc,loc什么的概念也都清楚了。

进阶方法

在实际工作中处理表格数据时,发现上面的方法只适用于以下有包含关系的列名(主要原因是使用了MultiIndex.from_product):示例表头1
而当关系变得更加复杂时……就不适用啦:
示例表头2

导入&观察数据

数据读取结果
还是可以看出:

  1. excel中作为列信息部分在读取之后变成了行信息;
  2. 合并的单元格被拆分,并且拆分后只有最左边的单元格有信息。

处理思路及代码

整体思路和初级方法中的思路类似,依旧是围绕数据框的索引进行操作,在进行stack()之前分别提取和处理行索引、列索引和值,构建新的数据框,整体的步骤和函数反而更加简单。
分别提取各部分

分步操作版:

提取列索引

提取列索引(包括当前列索引)为值,行填充空值。

df_column = df.iloc[0:4,2:]
df_cols = pd.DataFrame([df_column.columns.to_list()],columns = df_column.columns.to_list(),index = [0])
df_column = pd.concat([df_cols,df_column]).reset_index(drop = True)
df_column.loc[0,df_column.loc[0,:].str.contains('Unnamed') == True] = np.nan
df_column.fillna(method = 'ffill',inplace = True,axis = 1)

列索引

提取行索引

提取行索引

df_index = df.loc[:,['列名1','列名2']]
#df_index.fillna(method = 'ffill',inplace = True)
df_index = df_index.drop([0,1,2,3],axis = 0).reset_index(drop = True)
df_index

注:将df切片并且传递给新变量df_index = df.loc[:,['列名1','列名2']]时,需要用iloc或者loc,否则会出现SettingWithCopyWarning。

提取值
df_value = df.iloc[4:,2:]
df_value

在这里插入图片描述

构建新数据框
df_value.index = df_index.T.values.tolist()
df_value.columns = df_column.values.tolist()
df_value.index.names = ['列名1','列名2']#这里命名的是行索引的名称
df_value.columns.names = ['colname1','colname2','colname3','colname4','colname5']#这里命名的是列索引的名称
#行索引名称和列索引名称在最终的结果表中都是作为列名出现

在这里插入图片描述
在jupyter中呈现的结果是这样的,看上去没有对齐可能会造成误解,实际上已经是想要的形式了,可以导出到csv里核实一下:
在这里插入图片描述

转置
df_new = df_value.stack(['colname1','colname2','colname3','colname4','colname5']).reset_index()

还自动剔除了NA行
在这里插入图片描述

函数版:

def multicolumnlevel_to_one(raw_dataframe,row_level_cnt,column_level_cnt,row_index_name,column_index_name):
    #raw_dataframe:待处理表格 dataframe 要求删除不需要的列
    #row_level_cnt:原始表格中行索引列的数量 int
    #column_level_cnt:原始表格中列名层次的数量 int
    #row_index_name:需要设置为行索引的列的列名 list 顺序是从左到右的要作为行索引列的名称
    #column_index_name:列索引名称 list 顺序是从上到下的不同列名
    if column_level_cnt >= 2:
        #step 1 提取列索引
        df_column = raw_dataframe.iloc[:(column_level_cnt-1),row_level_cnt:]
        df_cols = pd.DataFrame([df_column.columns.to_list()],columns = df_column.columns.to_list(),index = [0])
        df_column = pd.concat([df_cols,df_column]).reset_index(drop = True)
        df_column.loc[0,df_column.loc[0,:].str.contains('Unnamed') == True] = np.nan
        df_column.fillna(method = 'ffill',inplace = True,axis = 1)

        #step 2 提取行索引
        df_index = raw_dataframe.loc[:,row_index_name]
        df_index.fillna(method = 'ffill',inplace = True)
        df_index = df_index.drop(list(range(column_level_cnt-1)),axis = 0).reset_index(drop = True)

        #step 3 提取值
        df_value = raw_dataframe.iloc[(column_level_cnt-1):,row_level_cnt:]

        #step 4 构建新数据框
        df_value.index = df_index.T.values.tolist()
        df_value.columns = df_column.values.tolist()
        df_value.index.names = row_index_name
        df_value.columns.names = column_index_name

        #step 5 转置
        df_new = df_value.stack(column_index_name).reset_index()
    else: #如果只有一行的列名
        df_new = raw_dataframe.set_index(row_index_name)
        df_new.columns.name = column_index_name[0]
        df_new = df_new.stack().reset_index()
    return df_new

函数还满足了以下这种表格的转置:
在这里插入图片描述
End
在这里插入图片描述

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Python中,可以使用不同的方法来实现表格转置。其中,一种方法是使用列表推导式来实现转置。可以定义一个函数,接受一个二维列表作为参数,然后使用列表推导式来生成转置后的二维列表。以下是一个示例代码: ```python def transpose_table(table): return \[\[table\[j\]\[i\] for j in range(len(table))\] for i in range(len(table\[0\]))\] ``` 另外,如果你使用的是pandas库,也可以使用该库提供的函数来实现表格转置。可以使用`read_excel`函数读取需要转置的文件,然后使用`T`属性来进行转置,最后使用`to_excel`函数将转置后的表格保存为xlsx文件。以下是一个示例代码: ```python import pandas as pd df = pd.read_excel('input.xlsx') # 读取需要转置的文件 df_transposed = df.T # 转置 df_transposed.to_excel('output.xlsx') # 另存为xlsx文件 ``` 这样,你就可以将一个表格转置为另一个表格,并保存为xlsx文件。希望对你有帮助!\[1\]\[2\] #### 引用[.reference_title] - *1* *3* [chatgpt赋能pythonPython转置列表:一种简单而高效的数据重组方式](https://blog.csdn.net/axuhsssssco/article/details/130908849)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Python-xlsx转置,行转列,列转行](https://blog.csdn.net/zkw_1998/article/details/112616925)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值