金牌廚師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點

朱小五

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