金牌厨师Pandas:听说Excel处理数据分行快得很?

↑ 关注 + 星标 ~ 有趣的不像个技术号

每晚九点,我们准时相约  


大家好,我是HeoiJin

作者简介:立志透过数据看清世界的产品策划,专注爬虫、数据分析、产品策划领域。

万物皆营销 | 资本永不眠 | 数据恒真理

CSDN:https://me.csdn.net/weixin_40679090

一、前言

最近收到一个小朋友(无中生友)发过来的需求,要将多列数据转化成多行数据,并提取指定列的数据。

但因为数据结构有点丑,而且数据量大,不好通过excel公式进行清洗,希望我利用python帮他清洗下。

那么这位小朋友碰上了什么幺蛾子,接下来一起一探究竟吧。

二、项目准备

语言:Python 3.7

IDE:Pycharm

相关库:Pandas、re、xlrd、xlwt

三、项目特色

利用ExcelFile方法读取单个Excel文件中的多个sheets

利用explode方法为dataframe中嵌套的列表解嵌套为多行数据

四、项目需求

拿到样本数据和最终效果图的那一刻,有句话想跟设计表格的大佬说,不知当讲不当讲...各位先品一品这堆数据。

吐槽归吐槽,金牌厨师胖大师表示:“这波问题不大,接下来我要展示我王者水平的操作!”

(点击可放大本图)

五、核心厨具介绍

pandas.DateFrame.explode能将dataframe的嵌套列表拆分成多行,并会复制同一行的其他元素。

方法参数详解
DataFrame.explode(self, column: Union[str, Tuple]) → 'DataFrame'

column:要进行操作的列名,可以传入字符串或者元组

注意列名应该是唯一的,否则会引发ValueError

返回dataframe(如果整个dataframe仅有一列,会自动在转换为series)

六、烹饪开始

6.1 确认烹饪思路

  1. 遍历所有sheet

  2. 筛选出核心的房号、姓名、电话信息

  3. 将信息拼接成为列表

  4. 将列表拆分为多行数据

  5. 输出为csv

6.2 筛选核心食材(获取特定的columns)

观察可知,三个sheets的表头顺序都不一样,如果只利用简单粗暴的切片方式,并不能精准地获取到需要的表头。但庆幸表头名称都相同,派出正则表达式这把利刃便能轻松地完成任务。

def get_new_columns(df):
    '''
    >> 利用正则匹配出目标columns
    >> df.columns=['栋数', '户型', '姓名', '性别', '电话', '房号', '姓名.1', '性别.1', '电话.1', '房号.1','姓名.2', '性别.2', '电话.2', '房号.2']
    >> 当我们的columns重复的时候,pandas会自动帮我们在重复的columns后面加上.编号。
    :param df:
    :return:
    '''
    # 提取columns对应的字段
    pattern_name=r',(姓名.?\d?),'
    pattern_room=r',(房号.?\d?),'
    pattern_phoone=r',(电话.?\d?),'
    # 通过前后增加逗号,确保正则的精准匹配
    columns_str=','+','.join(df.columns.to_list())+','
    columns_name=re.findall(pattern_name,columns_str)
    columns_room=re.findall(pattern_room,columns_str)
    columns_phone=re.findall(pattern_phoone,columns_str)
    target_columns=[]
    # 将每一行的数据变为一个一层嵌套的列表
    for i in range(len(columns_name)):
        target_columns+=[columns_room[i],columns_name[i],columns_phone[i]]
    return target_columns

6.3 调制酱料(多列数据合并为一列)

这里定义一个函数,用于将每行的元素合并成一个有一层嵌套列表的series。

# 用于rebuild_df的apply
def merge_cols(Series):
    # 获取非空项
    Series=Series[Series.notna()]
    # 获取当行所有数据
    value=Series.values
    result=[]
    # 将每一行的数据变为一个一层嵌套的列表
    for idx in range(0,len(value),3):
        result.append([value[idx],value[idx+1],value[idx+2]])
    return result

6.4 大火爆炒,加料调味(拆分嵌套为多行,拼接其他数据)

食材和配料我们都准备好了,下面就可以开火下锅制作佳肴

烹饪流程:

  1. 获取楼层、户型信息

  2. 利用apply方法,拼接每行数据

  3. 利用explode方法展开数据

  4. 拆分每组数据

def rebuild_df(df,merge_columns):
    # 获取表格头部通用信息
	# merge_columns=['房号', '姓名', '电话', '房号.1', '姓名.1', '电话.1', '房号.2', '姓名.2', '电话.2']
    df_new=df.iloc[:,:2]
    # 调用merge_cols函数对数据进行合并
    # 注意:使用apply调用函数时不用加括号
    df_new['merge']=df.loc[:,merge_columns].apply(merge_cols,axis=1)
    # 通过explode变成多行
    df=df_new.explode('merge')
    # 拆分merge列的列表
    df['房号']=df['merge'].str[0]
    df['姓名']=df['merge'].str[1]
    df['电话']=df['merge'].str[2]
    df.drop('merge',axis=1,inplace=True)
    return df

6.5 跑堂的,上菜!

我们的食材有多个sheets,通过ExcelFile方法读取所有sheets名,并在输出的文件名中添加sheets名来区分文件。

def open_file(sheets_name):
    df=pd.read_excel('数据集/多行转多列数据集.xlsx',sheet_name=sheets_name)
    return df

if __name__ == '__main__':
    sheets_name_list=pd.ExcelFile('数据集/多行转多列数据集.xlsx').sheet_names
    for sheets_name in sheets_name_list:
        df=open_file(sheets_name)
        merge_columns=get_new_columns(df)
        df=rebuild_df(df,merge_columns)
        df.to_excel(f'数据集/{sheets_name}.xls', index=False,sheet_name=sheets_name,encoding='utf-8')

ok,数据非常快就清洗完了,打开其中一个表格检查下效果,小老板搞得不丑~

七、后记

本文核心思路:

  • 利用ExcelFile读取多个sheet

  • 通过explode方法,将横版的数据转换为竖版

完整代码及数据集请移步至文末github地址或阅读原文

(PS.数据集为脚本随机生成的虚拟数据)

后续将推出一篇食材来自”垃圾场“的清洗实战,究竟都多脏?

先看看群友们对这份数据的看法吧~

欲知后事如何,请您下回分解~

github地址:https://github.com/heoijin/Date-Clean

参考资料:

  1. pandas原文档:

    https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.explode.html

近期文章,点击图片即可查看

后台回复关键词「进群」,即刻加入读者交流群~

送大家一个小福利

留言点赞前三名中,小五随机抽取一名送书

时间截止到明天3.22日晚9点

朱小五

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章