<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          實(shí)踐應(yīng)用|pandas+PyQt5制作數(shù)據(jù)(分組)透視處理工具

          共 8113字,需瀏覽 17分鐘

           ·

          2020-09-15 23:18


          這位才哥真的硬核,源碼在文末

          由于在工作中需要處理很多日志文件數(shù)據(jù),這些數(shù)據(jù)并不存在于數(shù)據(jù)庫(kù),而是以每日1個(gè)單文件的形式存在,為了讓我們?cè)谌粘?shù)據(jù)處理中更方便的進(jìn)行一些基礎(chǔ)的數(shù)據(jù)合并、清洗篩選以及簡(jiǎn)單的分組或數(shù)據(jù)透視處理,結(jié)合PyQt5與pandas庫(kù),制作了一個(gè)簡(jiǎn)單的數(shù)據(jù)處理可視化工具。

          數(shù)據(jù)處理工具

          執(zhí)行效果

          我們運(yùn)行腳本打包后的 exe 可執(zhí)行文件,設(shè)定相關(guān)參數(shù)后點(diǎn)擊“數(shù)據(jù)處理并導(dǎo)出”即可等待處理~

          以下是29文件共1400余萬(wàn)行數(shù)據(jù)的處理結(jié)果,差不多用了10分鐘合并并處理導(dǎo)出所需結(jié)果~

          效果展示

          1.窗體可視化設(shè)計(jì)

          采用PyQt5進(jìn)行可視化界面設(shè)計(jì),具體設(shè)計(jì)過(guò)程可以直接在QT designer中進(jìn)行操作,然后轉(zhuǎn)化為可視化界面的py文件。

          具體這里不做更多的介紹,大家可以關(guān)注留意后續(xù)更新(專門針對(duì)PyQt5的學(xué)習(xí)筆記)。

          界面效果如下圖:

          窗體可視化設(shè)計(jì)

          對(duì)于我們的操作界面,支持以下功能:

          • 選擇原始數(shù)據(jù)所在的文件夾

          • 選擇需要vlookup的文件所在的文件夾

          • 選擇處理后結(jié)果導(dǎo)出的文件夾

          • 輸入結(jié)果導(dǎo)出的文件名

          • 在原始數(shù)據(jù)中用于過(guò)濾篩選的字段

          • 在原始數(shù)據(jù)中用于過(guò)濾篩選的條件

          • 如果做數(shù)據(jù)透視的行(index)

          • 數(shù)據(jù)透視的列(column)

          • 用于計(jì)算的字段

          • 用于計(jì)算的方法

          2.多文件合并(concat)

          由于我們拿到的原始數(shù)據(jù)是以日期為文件名的csv文件,如果需要處理多天的數(shù)據(jù),需要進(jìn)行簡(jiǎn)單的數(shù)據(jù)合并后再做相關(guān)數(shù)據(jù)處理操作。

          這一步其實(shí)有4個(gè)操作:
          ①獲取文件夾下的文件列表
          ②根據(jù)文件類型進(jìn)行文件讀取
          ③對(duì)讀取的文件進(jìn)行簡(jiǎn)單的數(shù)據(jù)清洗
          ④合并清洗后的數(shù)據(jù)

          2.1.獲取文件夾下的文件列表

          獲取文件夾下文件列表可以使用os.walk方法,產(chǎn)生3-元組 (dirpath, dirnames, filenames)【文件夾路徑, 文件夾名字, 文件名】。

          根據(jù)文件夾路徑+文件名即可組成改文件的絕對(duì)路徑,用于后續(xù)文件讀取。

          In??[1]:?import?os
          ????...:?
          ????...:?location?=?r'F:\數(shù)據(jù)處理工具\(yùn)測(cè)試數(shù)據(jù)'
          ????...:?filenames?=?os.walk(location)
          ????...:?
          ????...:?#獲取文件夾下全部文件的絕對(duì)路徑
          ????...:?for?fileName?in?os.walk(location):
          ????...:?????for?table?in?fileName[2]:
          ????...:?????????path?=?fileName[0]?+?'\\'?+?table
          ????...:?????????print(path)
          F:\數(shù)據(jù)處理工具\(yùn)測(cè)試數(shù)據(jù)\1.csv
          F:\數(shù)據(jù)處理工具\(yùn)測(cè)試數(shù)據(jù)\2.csv
          F:\數(shù)據(jù)處理工具\(yùn)測(cè)試數(shù)據(jù)\3.csv
          F:\數(shù)據(jù)處理工具\(yùn)測(cè)試數(shù)據(jù)\4.csv
          F:\數(shù)據(jù)處理工具\(yùn)測(cè)試數(shù)據(jù)\5.csv
          F:\數(shù)據(jù)處理工具\(yùn)測(cè)試數(shù)據(jù)\6.csv
          F:\數(shù)據(jù)處理工具\(yùn)測(cè)試數(shù)據(jù)\7.csv
          F:\數(shù)據(jù)處理工具\(yùn)測(cè)試數(shù)據(jù)\8.csv
          F:\數(shù)據(jù)處理工具\(yùn)測(cè)試數(shù)據(jù)\9.csv
          文件列表

          2.2.根據(jù)文件類型進(jìn)行文件讀取

          由于在實(shí)際操作過(guò)程中,可能存在原始文件是csv壓縮包zip格式,或者xlsx格式。我們需要根據(jù)文件名后綴進(jìn)行判斷,然后選擇對(duì)應(yīng)的讀取文件數(shù)據(jù)方法。

          采用os.path.splitext(“文件路徑”) 分離文件名與擴(kuò)展名,默認(rèn)返回(fname,fextension)元組。

          這里我們只考慮兩種情況:csv(含zip)以及xlsx(含xls):

          if?filetype?==?'.csv'or?filetype?==?'.zip':
          ????Li?=?pd.read_csv(path,?header=0)????????????????????????
          elif?filetype?==?'.xlsx'?or?filetype?==?'.xls':
          ????Li?=?pd.read_excel(path,?header=0)
          else:
          ????log?=?'不是支持的文件類型,該工具暫時(shí)只支持csv、xlsx和xls文件類型'
          ????print(log)

          2.3.對(duì)讀取的文件夾下簡(jiǎn)單的數(shù)據(jù)清洗

          對(duì)于讀取的文件數(shù)據(jù),并不是所有的數(shù)據(jù)都是我們需要用到的,或者說(shuō)我們需要用到的數(shù)據(jù)可能是需要滿足指定條件的。

          比如對(duì)于下面這個(gè)情況,讀取 9.csv 文件后,我們看到 usernum 每個(gè)值出現(xiàn)的次數(shù),然后我希望取滿足uesrnum為10的數(shù)據(jù)。

          In?[2]:?df?=?pd.read_csv(r'F:\數(shù)據(jù)處理工具\(yùn)測(cè)試數(shù)據(jù)\9.csv')
          In?[3]:?df.groupby('usernum').count()
          Out[3]:?
          ?????????@timestamp???appid??...??truedmgtohero??victory
          usernum??????????????????????...????????????????????????
          1????????????516999??516999??...?????????516999???516999
          2?????????????33970???33970??...??????????33970????33970
          3?????????????36819???36819??...??????????36819????36819
          4??????????????6917????6917??...???????????6917?????6917
          5??????????????7855????7855??...???????????7855?????7855
          6?????????????15416???15416??...??????????15416????15416
          8??????????????1220????1220??...???????????1220?????1220
          10????????????75420???75420??...??????????75420????75420

          [8?rows?x?71?columns]

          我們用到布爾索引即可df[df['usernum']==10]

          In?[4]:?df_10?=?df[df['usernum']==10]
          In?[5]:?df_10.groupby('usernum').count()
          Out[5]:?
          ?????????@timestamp??appid??...??truedmgtohero??victory
          usernum?????????????????????...????????????????????????
          10????????????75420??75420??...??????????75420????75420

          [1?rows?x?71?columns]

          但是,因?yàn)槲覀兊暮Y選字段及條件都是通過(guò)可視化操作界面進(jìn)行輸入的,輸入的數(shù)據(jù)類型在程序中是字符串,所以我們需要將其處理成為可以用于條件篩選的形式。而且,我們?cè)谶M(jìn)行清洗的時(shí)候字段及條件可能是多個(gè)的。

          比如我輸入的字段為:usernum/victory;輸入的條件為:>=6/==1。

          那我們實(shí)際上需要進(jìn)行的清洗過(guò)程是df = df[df['usernum']>=6] 和 df = df[df['victory']==1],為實(shí)現(xiàn)這個(gè)效果,可以用最簡(jiǎn)單的字符拼接的形式?s = f"Li['{checkli[0]}']{conditionli[0]}",然后進(jìn)行eval(s)轉(zhuǎn)化。

          #獲取輸入的篩選字段(用‘/’分割),我們用'/'拆分為列表
          checkli?=?self.lineEditcheck.text().split('/')
          #獲取輸入的條件參數(shù)(用‘/’分割),我們用'/'拆分為列表
          conditionli?=?self.lineEditcondition.text().split('/')
          for?inum?in?range(len(checkli)):
          ????s?=?f"Li['{checkli[0]}']{conditionli[0]}"
          ????Li?=?Li[eval(s)]

          關(guān)于數(shù)據(jù)清洗處理,我們會(huì)在pandas學(xué)習(xí)筆記中進(jìn)行詳細(xì)介紹~

          2.4.合并清洗后的數(shù)據(jù)

          這一步就比較簡(jiǎn)單了,直接將需要合并的數(shù)據(jù)添加的列表中,然后concat合并即可。不過(guò),需要做個(gè)簡(jiǎn)單的判斷,如果原始只有1個(gè)文件,直接就取改文件即可;超過(guò)1個(gè)文件情況下,才需要執(zhí)行合并操作。

          ????#...讀取并清洗數(shù)據(jù)...
          ????fileList.append(Li)

          if?len(fileList)>1:
          ????data_result?=?pd.concat(fileList,?ignore_index=True)
          else:
          ????data_result?=?fileList[0]

          3.多文件拼接(merge)

          這個(gè)其實(shí)也比較簡(jiǎn)單,我們事先把需要用于橫向拼接的文件放到指定目錄后,讀取文件列表逐一和第2節(jié)中的處理過(guò)的原始數(shù)據(jù)進(jìn)行merge處理。

          基于第2節(jié)中介紹過(guò)的文件夾下文件列表讀取,這里只介紹merge處理。

          還是一樣的邏輯,先判斷是否有需要merge的文件,然后再執(zhí)行后續(xù)操作,我們需要用到左連接方式處理。

          ????#...讀取需要用于merge的文件組合成列表...
          ????fileList.append(Li)
          for?i?in?range(0,len(fileList)):
          ????data?=?pd.merge(data,fileList[i],how?=?'left')

          4.數(shù)據(jù)處理(pivot_table和groupby)

          數(shù)據(jù)處理中我們可以用到pivot_table方法或者數(shù)據(jù)透視分組統(tǒng)計(jì)groupby方法,具體根據(jù)自己的需求選擇。

          這一部分我們?cè)诤罄m(xù) pandas學(xué)習(xí)筆記中也會(huì)詳細(xì)介紹~

          4.1.數(shù)據(jù)透視(pivot_table)

          pandas.pivot_table(data, values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All', observed=False)

          以下舉例,簡(jiǎn)單介紹下其使用方式

          In??[6]:?df?=?pd.DataFrame({"A":?["foo",?"foo",?"foo",?"foo",?"foo",
          ????...:??????????????????????????"bar",?"bar",?"bar",?"bar"],
          ????...:????????????????????"B":?["one",?"one",?"one",?"two",?"two",
          ????...:??????????????????????????"one",?"one",?"two",?"two"],
          ????...:????????????????????"C":?["small",?"large",?"large",?"small",
          ????...:??????????????????????????"small",?"large",?"small",?"small","large"],
          ????...:????????????????????"D":?[1,?2,?2,?3,?3,?4,?5,?6,?7],
          ????...:????????????????????"E":?[2,?4,?5,?5,?6,?6,?8,?9,?9]})
          In?[7]:?df
          Out[7]:?
          ?????A????B??????C??D??E
          0??foo??one??small??1??2
          1??foo??one??large??2??4
          2??foo??one??large??2??5
          3??foo??two??small??3??5
          4??foo??two??small??3??6
          5??bar??one??large??4??6
          6??bar??one??small??5??8
          7??bar??two??small??6??9
          8??bar??two??large??7??9

          #?values是需要用于計(jì)算的字段,index是索引,columns是列,aggfunc是統(tǒng)計(jì)方式
          In??[8]:?table?=?pd.pivot_table(df,?values='D',?index=['A',?'B'],
          ????...:?????????????????????columns=['C'],?aggfunc='sum')
          In?[9]:?table
          Out[9]:?
          C????????large??small
          A???B????????????????
          bar?one????4.0????5.0
          ????two????7.0????6.0
          foo?one????4.0????1.0
          ????two????NaN????6.0

          #如果aggfunc指定了多個(gè)統(tǒng)計(jì)方式,其會(huì)對(duì)計(jì)算的字段values中每個(gè)字段進(jìn)行多個(gè)統(tǒng)計(jì)計(jì)算
          In?[10]:?table?=?pd.pivot_table(df,?values=['D',?'E'],?index=['A',?'C'],
          ????...:?????????????????????aggfunc={'mean','sum'})
          In?[11]:?table
          Out[11]:?
          ??????????????????D???????????????E??????
          ???????????????mean???sum??????mean???sum
          A???C????????????????????????????????????
          bar?large??5.500000??11.0??7.500000??15.0
          ????small??5.500000??11.0??8.500000??17.0
          foo?large??2.000000???4.0??4.500000???9.0
          ????small??2.333333???7.0??4.333333??13.0

          #我們可以通過(guò)給aggfunc傳遞字典的形式指定每個(gè)用于計(jì)算字段的統(tǒng)計(jì)方式,這也是我們本次需要用到的
          In?[12]:?table?=?pd.pivot_table(df,?values=['D',?'E'],?index=['A',?'C'],
          ????...:?????????????????????aggfunc={'D':?'mean','E':?'sum'})
          In?[12]:?table
          Out[12]:?
          ??????????????????D???E
          A???C??????????????????
          bar?large??5.500000??15
          ????small??5.500000??17
          foo?large??2.000000???9
          ????small??2.333333??13

          4.2.分組統(tǒng)計(jì)(groupby)

          DataFrame.groupby([]).agg(dict)

          分組統(tǒng)計(jì)是pandas很大的模塊,這里也不做過(guò)多的介紹,大家可以關(guān)注后續(xù) pandas學(xué)習(xí)筆記系列。

          簡(jiǎn)單舉個(gè)例子:

          In?[13]:?df
          Out[13]:?
          ?????A????B??????C??D??E
          0??foo??one??small??1??2
          1??foo??one??large??2??4
          2??foo??one??large??2??5
          3??foo??two??small??3??5
          4??foo??two??small??3??6
          5??bar??one??large??4??6
          6??bar??one??small??5??8
          7??bar??two??small??6??9
          8??bar??two??large??7??9

          In?[14]:?df.groupby('A')['D'].mean()
          Out[14]:?
          A
          bar????5.5
          foo????2.2
          Name:?D,?dtype:?float64

          #agg傳字段參數(shù)更合適,可以和pivot_table統(tǒng)一化
          In?[15]:?df.groupby(['A']).agg({'D':'mean','E':'sum'})
          Out[15]:?
          ???????D???E
          A???????????
          bar??5.5??32
          foo??2.2??22

          4.3.數(shù)據(jù)處理函數(shù)

          由于行列以及計(jì)算字段和方法都是在可視化操作界面輸入,我們需要對(duì)獲取參數(shù)后進(jìn)行字符串有關(guān)處理,從而組合成為最終的計(jì)算方式。

          #獲取輸入的行、列、計(jì)算字段和方法
          hang?=?self.lineEditHang.text().split(',')
          lie?=?self.lineEditLie.text().split(',')?if?len(self.lineEditLie.text())!=0?else?[]
          ziduan?=?self.lineEditJisuan.text().split(',')
          fangfa?=?self.lineEditJisF.text().split(',')

          將計(jì)算字段和計(jì)算方法進(jìn)行組合成為字典

          dic?=?{}
          for?i?in?range(len(fangfa)):
          ????#需要注意,這里對(duì)于非重復(fù)計(jì)數(shù),其組合形式有點(diǎn)特別,不能用引號(hào)
          ???????if?fangfa[i]?==?'pd.Series.nunique':
          ????????dic[ziduan[i]]?=?eval(fangfa[i])
          ???????else:
          ???????????dic[ziduan[i]]?=?fangfa[i]??

          判斷在可視化操作界面是否選中了數(shù)據(jù)透視操作,然后執(zhí)行數(shù)據(jù)處理

          if?self.radioButton_toushi.isChecked():
          ????result?=?pd.pivot_table(df,?values=ziduan,
          ??????????????????aggfunc=dic,?
          ??????????????????columns=lie,
          ??????????????????index=hang,
          ??????????????????).reset_index()
          else:
          ????result?=?df.groupby(hang).agg(dic).reset_index()??

          5.總結(jié)

          以上主要三部分:

          • 先創(chuàng)建好可視化操作界面,

          • 然后編寫功能槽函數(shù)和可視化操作界面功能進(jìn)行關(guān)聯(lián),

          • 最后就是打包源代碼成可執(zhí)行文件exe。

          在進(jìn)行每一步的操作時(shí),最好都能加上邊界條件處理,避免出現(xiàn)異常報(bào)錯(cuò)導(dǎo)致程序崩潰的情況。

          每個(gè)槽函數(shù)其實(shí)都是利用到的python基礎(chǔ)知識(shí)或者pandas基礎(chǔ)數(shù)據(jù)處理知識(shí),熟練掌握后便可很方便理解和實(shí)現(xiàn)。

          源碼領(lǐng)取鏈接:https://yihang.cowtransfer.com/s/4ad1355a06fc4c


          推薦閱讀

          (點(diǎn)擊標(biāo)題可跳轉(zhuǎn)閱讀)

          我是如何純靠技術(shù)在大學(xué)月入上萬(wàn),收獲人生第一個(gè)10W

          十大最受數(shù)據(jù)科學(xué)歡迎的Python庫(kù)

          21張讓你代碼能力突飛猛進(jìn)的速查表(神經(jīng)網(wǎng)絡(luò)、機(jī)器學(xué)習(xí)、可視化等)


          轉(zhuǎn)了嗎
          ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ??
          ? ? ? ? ? ? ? ? ? ? ? ? ? ?贊了嗎
          在看嗎
          瀏覽 66
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  超清无码在线网上 | 久热在线视频 | 日皮太爽了我要看免费视频 | 208操逼视频 | 淫淫五月天 |