↑ 關注 + 星標 ~ 有趣的不像個技術號
每晚九點,我們準時相約
大家好,我是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 確認烹飪思路
遍歷所有sheet
篩選出核心的房號、姓名、電話信息
將信息拼接成爲列表
將列表拆分爲多行數據
輸出爲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 大火爆炒,加料調味(拆分嵌套爲多行,拼接其他數據)
食材和配料我們都準備好了,下面就可以開火下鍋製作佳餚
烹飪流程:
獲取樓層、戶型信息
利用apply方法,拼接每行數據
利用explode方法展開數據
拆分每組數據
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
參考資料:
pandas原文檔:
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.explode.html
近期文章,點擊圖片即可查看
後臺回覆關鍵詞「進羣」,即刻加入讀者交流羣~
五
送大家一個小福利
留言點贊前三名中,小五隨機抽取一名送書
時間截止到明天3.22日晚9點
朱小五