整合營銷服務商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          用Python數(shù)據(jù)分析時,他將Pandas循環(huán)提速7

          用Python數(shù)據(jù)分析時,他將Pandas循環(huán)提速7萬多倍

          明 編譯整理

          量子位 報道 | 公眾號 QbitAI

          用Python和Pandas進行數(shù)據(jù)分析,很快就會用到循環(huán)。

          但在這其中,就算是較小的DataFrame,使用標準循環(huán)也比較耗時。

          遇到較大的DataFrame時,需要的時間會更長,會讓人更加頭疼。

          現(xiàn)在,有人忍不了了。他是一位來自德國的數(shù)據(jù)分析師,名叫Benedikt Droste。

          他說,當自己花了大半個小時等待代碼執(zhí)行的時候,決定尋找速度更快的替代方案。

          在給出的替代方案中,使用Numpy向量化,與使用標準循環(huán)相比,速度提升了71803倍。



          他是怎么實現(xiàn)的?我們一起來看看~

          標準循環(huán)處理3年足球賽數(shù)據(jù):20.7秒

          DataFrame是具有行和列的Pandas對象。如果使用循環(huán),需要遍歷整個對象。

          Python不能利用任何內(nèi)置函數(shù),而且速度很慢。在Benedikt Droste的提供的示例中,是一個包含65列和1140行的Dataframe,包含了2016-2019賽季的足球賽結果。

          需要解決的問題是:創(chuàng)建一個新的列,用于指示某個特定的隊是否打了平局。可以這樣開始:

          def soc_loop(leaguedf,TEAM,):
           leaguedf['Draws']=99999
           for row in range(0, len(leaguedf)):
           if ((leaguedf['HomeTeam'].iloc[row]==TEAM) & (leaguedf['FTR'].iloc[row]=='D')) | \
           ((leaguedf['AwayTeam'].iloc[row]==TEAM) & (leaguedf['FTR'].iloc[row]=='D')):
           leaguedf['Draws'].iloc[row]='Draw'
           elif ((leaguedf['HomeTeam'].iloc[row]==TEAM) & (leaguedf['FTR'].iloc[row] !='D')) | \
           ((leaguedf['AwayTeam'].iloc[row]==TEAM) & (leaguedf['FTR'].iloc[row] !='D')):
           leaguedf['Draws'].iloc[row]='No_Draw'
           else:
           leaguedf['Draws'].iloc[row]='No_Game'
          



          在這個案例中是阿森納,在實現(xiàn)目標之前要確認阿森納參加了哪些場比賽,是主隊還是客隊。但使用標準循環(huán)非常慢,執(zhí)行時間為20.7秒。

          那么,怎么才能更有效率?

          Pandas 內(nèi)置函數(shù): iterrows ()ー快321倍

          在第一個示例中,循環(huán)遍歷了整個DataFrame。iterrows()為每一行返回一個Series,它以索引對的形式遍歷DataFrame,以Series的形式遍歷感興趣的列。這使得它比標準循環(huán)更快:

          def soc_iter(TEAM,home,away,ftr):
           #team, row['HomeTeam'], row['AwayTeam'], row['FTR']
           if [((home==TEAM) & (ftr=='D')) | ((away==TEAM) & (ftr=='D'))]:
           result='Draw'
           elif [((home==TEAM) & (ftr !='D')) | ((away==TEAM) & (ftr !='D'))]:
           result='No_Draw'
           else:
           result='No_Game'
           return result
          



          代碼運行時間為68毫秒,比標準循環(huán)快321倍。但是,許多人建議不要使用它,因為仍然有更快的選項,而且iterrows()不能跨行保存dtype。

          這意味著,如果你在DataFrame dtypes上使用iterrows(),可以更改它,但這會導致很多問題。

          一定要保存dtypes的話,你還可以使用itertuples()。這里我們不詳細討論 ,你可以在這里找到官方文件:

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

          apply ()方法ー快811倍

          apply 本身并不快,但與DataFrame結合使用時,它具有優(yōu)勢。這取決于 apply 表達式的內(nèi)容。如果可以在 Cython 空間中執(zhí)行,那么apply要快得多,這里的示例就是這種情況。

          大家可以在Lambda函數(shù)中使用apply。所要做的就是指定這個軸。在本文的示例中,想要執(zhí)行按列操作,要使用 axis 1:



          這段代碼甚至比之前的方法更快,完成時間為27毫秒。

          Pandas向量化—快9280倍

          此外,也可以利用向量化的優(yōu)點來創(chuàng)建非常快的代碼。

          重點是避免像之前的示例中的Python級循環(huán),并使用優(yōu)化后的C語言代碼,這將更有效地使用內(nèi)存。只需要稍微修改一下函數(shù):

          def soc_iter(TEAM,home,away,ftr):
           df['Draws']='No_Game'
           df.loc[((home==TEAM) & (ftr=='D')) | ((away==TEAM) & (ftr=='D')), 'Draws']='Draw'
           df.loc[((home==TEAM) & (ftr !='D')) | ((away==TEAM) & (ftr !='D')), 'Draws']='No_Draw'
          

          現(xiàn)在,可以用 Pandas 列作為輸入創(chuàng)建新列:



          在這種情況下,甚至不需要循環(huán)。所要做的就是調(diào)整函數(shù)的內(nèi)容。現(xiàn)可以直接將Pandas 列傳遞給函數(shù),從而獲得巨大的速度增益。

          Numpy向量化—快71803倍

          在上面的示例中,將將Pandas 列傳遞給函數(shù)。通過添加.values,可以得到一個Numpy數(shù)組:



          因為引用了局部性的好處,Numpy數(shù)組的速度非常快,代碼運行時間僅為0.305毫秒,比一開始使用的標準循環(huán)快71803倍。

          誰更強一目了然

          最后,Benedikt Droste對上述方案進行了總結。

          他說,如果你使用Python、Pandas和Numpy進行數(shù)據(jù)分析,總會有改進代碼的空間。

          在對上述五種方法進行比較之后,哪個更快一目了然:



          從這個圖中,可以得出兩個結論:

          • 1、如果要使用循環(huán),則應始終選擇apply方法。
          • 2、否則,使用向量化是最好的,因為它更快!

          原文鏈接:

          https://towardsdatascience.com/how-to-make-your-pandas-loop-71-803-times-faster-805030df4f06

          誠摯招聘

          量子位正在招募編輯/記者,工作地點在北京中關村。期待有才氣、有熱情的同學加入我們!相關細節(jié),請在量子位公眾號(QbitAI)對話界面,回復“招聘”兩個字。

          量子位 QbitAI · 頭條號簽約作者

          ?'?' ? 追蹤AI技術和產(chǎn)品新動態(tài)

          讀:Pandas是一個基于Numpy庫開發(fā)的更高級的結構化數(shù)據(jù)分析工具,提供了Series、DataFrame、Panel等數(shù)據(jù)結構,可以很方便地對序列、截面數(shù)據(jù)(二維表)、面板數(shù)據(jù)進行處理。

          作者:張秋劍 張浩 周大川 常國珍

          來源:華章科技

          • DataFrame是我們常見的二維數(shù)據(jù)表,包含多個變量(列)和樣本(行),通常被稱為數(shù)據(jù)框。
          • Series是一個一維結構的序列,包含指定的索引信息,可以被視作DataFrame中的一列或一行。其操作方法與DataFrame十分相似。
          • Panel是包含序列及截面信息的三維結構,通常被稱為面板數(shù)據(jù)。

          我們可通過限定時間ID和樣本ID獲得對應的Series和DataFrame。

          由于這些對象的常用操作方法十分相似,因此本文主要使用DataFrame進行演示。

          01 讀取文件

          Pandas庫提供了便捷讀取本地結構化數(shù)據(jù)的方法。這里主要以csv數(shù)據(jù)為例,read_csv函數(shù)可以讀取csv數(shù)據(jù),代碼如下:

          import pandas as pd
          csv=pd.read_csv('data/sample.csv')
          csv
          id name scores
          0 1 小明 78.0
          1 2 小紅 87.0
          2 3 小白 99.0
          3 4 小青 99999.0
          4 5 小蘭 NaN

          按照慣例,Pandas會以pd為別名,以read_csv函數(shù)讀取指定路徑下的文件,然后返回一個DataFrame對象。如果在命令行中打印DataFrame對象,可讀性可能會略差一些;如果在Jupyter Notebook中打印的話,可讀性會大幅提升。

          打印出來的DataFrame包含索引(第一列),列名(第一行)及數(shù)據(jù)內(nèi)容(除第一行和第一列之外的部分)。

          此外,read_csv函數(shù)有很多參數(shù)可以設置,如下所示。

          • filepath_or_buffer csv文件的路徑
          • sep=',' 分隔符,默認為逗號
          • header=0 int類型,0代表第一行為列名,若設定為None將使用數(shù)值列名
          • names=[] list,重新定義列名,默認為None
          • usecols=[] list,定義讀取的列,設定后將縮短讀取數(shù)據(jù)的時間,并減小內(nèi)存消耗,適合讀取大量數(shù)據(jù),默認為None
          • dtype={} dict,定義讀取列的數(shù)據(jù)類型,默認為None
          • nrows=None int類型,指定讀取數(shù)據(jù)的前n行,默認為None
          • na_values=... str類型,list或dict,指定缺失值的填充值
          • na_filter=True bool類型,自動發(fā)現(xiàn)數(shù)據(jù)中的缺失值,默認值為True,若確定數(shù)據(jù)無缺失,可以設定值為False,以提高數(shù)據(jù)載入的速度
          • chunksize=1000 int類型,分塊讀取,當數(shù)據(jù)量較大時,可以設定分塊讀取的行數(shù),默認為None
          • encoding='utf-8' str類型,數(shù)據(jù)的編碼,Python3默認編碼為UTF-8,Python2默認編碼為ASCII

          Pandas除了可以直接讀取csv、excel、json、html等文件生成的DataFrame,也可以在列表、元組、字典等數(shù)據(jù)結構中創(chuàng)建DataFrame。

          02 讀取指定行和指定列

          使用參數(shù)usecol和nrows讀取指定的列和前n行,這樣可以加快數(shù)據(jù)讀取速度。讀取原數(shù)據(jù)的兩列、兩行示例如下。

          csv=pd.read_csv('data/sample.csv',\
          usecols=['id','name'],\
          nrows=2) #讀取'id'和'name'兩列,僅讀取前兩行
          csv
          id name
          0 1 小明
          1 2 小紅

          03 分塊讀取

          參數(shù)chunksize可以指定分塊讀取的行數(shù),并返回一個可迭代對象。這里,big.csv是一個4500行、4列的csv數(shù)據(jù),設定chunksize=900,分5塊讀取數(shù)據(jù),每塊900行,4個變量,如下所示:

          csvs=pd.read_csv('data/big.csv',chunksize=900)
          for i in csvs:
          print (i.shape)
          (900, 4)
          (900, 4)
          (900, 4)
          (900, 4)
          (900, 4)

          可以使用pd.concat函數(shù)讀取全部數(shù)據(jù):

          csvs=pd.read_csv('data/big.csv',chunksize=900)
          dat=pd.concat(csvs,ignore_index=True)
          dat.shape
          (4500, 4)

          04 將不合理數(shù)據(jù)讀取為缺失值

          在數(shù)據(jù)sample.csv中,“小青”的分數(shù)中有的取值為99999,這里令其讀取為缺失值,操作如下:

          csv=pd.read_csv('data/sample.csv',
          na_values='99999')
          csv
          id name scores
          0 1 小明 78.0
          1 2 小紅 87.0
          2 3 小白 99.0
          3 4 小青 NaN
          4 5 小蘭 NaN

          05 以指定編碼方式讀取

          讀取數(shù)據(jù)時,亂碼情況經(jīng)常出現(xiàn)。這里需要先弄清楚原始數(shù)據(jù)的編碼形式,再以指定的編碼形式讀取,例如sample.csv編碼為UTF-8,這里以指定編碼(參數(shù)encoding)方式讀取。

          csv=pd.read_csv('data/sample.csv',
          encoding='utf-8')
          csv
          id name scores
          0 1 小明 78.0
          1 2 小紅 87.0
          2 3 小白 99.0
          3 4 小青 99999.0
          4 5 小蘭 NaN

          關于作者:張秋劍,就職于騰訊云金融拓展中心,從事微信財富營銷管理、數(shù)據(jù)中臺、AI應用等解決方案拓展工作,研究方向包括數(shù)字化轉型、創(chuàng)新實踐等。

          張浩,曾任騰訊云金融首席架構師和星環(huán)科技金融行業(yè)技術總監(jiān),主要從事大數(shù)據(jù)、人工智能、云計算、區(qū)塊鏈、聯(lián)邦學習等相關技術研發(fā)與產(chǎn)品設計,具有豐富的企業(yè)架構設計、企業(yè)數(shù)字化戰(zhàn)略轉型運營與業(yè)務咨詢經(jīng)驗。

          周大川,就職于某中央金融企業(yè)金融科技研發(fā)中心,主要從事企業(yè)級數(shù)據(jù)平臺開發(fā)、核心業(yè)務平臺建設、AI賦能金融科技創(chuàng)新等工作,具有豐富的新一代金融業(yè)務系統(tǒng)建設經(jīng)驗。

          常國珍,曾任畢馬威咨詢大數(shù)據(jù)總監(jiān),具有近20年數(shù)據(jù)挖掘、精益數(shù)據(jù)治理、數(shù)字化運營咨詢經(jīng)驗,是金融信用風險、反欺詐和反洗錢算法領域的專家。

          本文摘編自《金融商業(yè)數(shù)據(jù)分析:基于Python和SAS》,經(jīng)出版方授權發(fā)布。(ISBN:9787111695837)

          《金融商業(yè)數(shù)據(jù)分析:基于Python和SAS》

          推薦語:騰訊云等資深數(shù)據(jù)架構師、商業(yè)分析師20年經(jīng)驗,全流程講解金融數(shù)據(jù)分析思路、方法、技巧,快速入門到精通。

          來看一個實例問題。

          ?如下銷售數(shù)據(jù)中展現(xiàn)了三筆訂單,每筆訂單買了多種商品,求每種商品銷售額占該筆訂單總金額的比例。例如第一條數(shù)據(jù)的最終結果為:235.83 / (235.83+232.32+107.97)=40.93%。

          后臺回復“transform”獲取本文全部代碼和pdf版本。

          思路一:

          常規(guī)的解法是,先用對訂單id分組,求出每筆訂單的總金額,再將源數(shù)據(jù)和得到的總金額進行“關聯(lián)”。最后把相應的兩列相除即可。相應的代碼如下:

          1.對訂單id分組,求每筆訂單總額。由于有三個order,因此最終會產(chǎn)生三條記錄表示三個總金額。

          2.數(shù)據(jù)關聯(lián)合并

          為了使每行都出現(xiàn)相應order的總金額,需要使用“左關聯(lián)”。我們使用源數(shù)據(jù)在左,聚合后的總金額數(shù)據(jù)在右(反過來也可)。不指定連接key,則會自動查找相應的關聯(lián)字段。由于是多行對一行的關聯(lián),關聯(lián)上的就會將總金額重復顯示多次,剛好符合我們后面計算的需要。結果如上圖所示。

          3.計算占比

          有了前面的基礎,就可以進行最終計算了:直接用商品金額ext_price除以訂單總額sum_price。并賦值給新的列pct即可。

          4.格式調(diào)整

          為了美觀,可以將小數(shù)形式轉換為百分比形式,自定義函數(shù)即可實現(xiàn)。

          思路二:

          對于上面的過程,pandas中的transform函數(shù)提供了更簡潔的實現(xiàn)方式,如下所示:

          可以看到,這種方法把前面的第一步和第二步合成了一步,直接得到了sum_price列。這就是transform的核心:作用于groupby之后的每個組的所有數(shù)據(jù)。可以參考下面的示意圖幫助理解:

          后面的步驟和前面一致。

          這種方法在需要對多列分組的時候同樣適用。

          多列分組使用transform

          為演示效果,我們虛構了如下數(shù)據(jù),id,name,cls為維度列。

          我們想求:以(id,name,cls)為分組,每組stu的數(shù)量占各組總stu的比例。使用transform處理如下:

          同樣再次計算占比和格式化,得到最終結果:

          總結transform的用法

          transform函數(shù)的官方文檔簽名為:DataFrame.transform(func,axis=0,*args,**kwargs),表示調(diào)用func函數(shù)進行轉換,返回轉換后的值,且返回值與原來的數(shù)據(jù)在相同的軸上具有相同的長度。func可以是函數(shù),字符串,列表或字典。具體可以參考官方文檔:

          https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.transform.html#pandas.DataFrame.transform。

          transform既可以和groupby一起使用,也可以單獨使用。

          1.單獨使用

          此時,在某些情況下可以實現(xiàn)和apply函數(shù)類似的結果。

          2.與groupby一起使用

          此時,transform函數(shù)返回與原數(shù)據(jù)一樣數(shù)量的行,并將函數(shù)的結果分配回原始的dataframe。也就是說返回的shape是(len(df),1)。本文開頭的例子就是這樣。而apply函數(shù)返回聚合后的行數(shù)。例如:

          transform和apply的另一個區(qū)別是,apply函數(shù)可以同時作用于多列,而transform不可以。下面用例子說明:

          上圖中的例子,定義了處理兩列差的函數(shù),在groupby之后分別調(diào)用apply和transform,transform并不能執(zhí)行。如果不采用groupby,直接調(diào)用,也會有問題,參見下面的第二種調(diào)用方式。

          第三種調(diào)用調(diào)用方式修改了函數(shù),transform依然不能執(zhí)行。以上三種調(diào)用apply的方式處理兩列的差,換成transform都會報錯。

          利用transform填充缺失值

          transform另一個比較突出的作用是用于填充缺失值。舉例如下:

          在上面的示例數(shù)據(jù)中,按照name可以分為三組,每組都有缺失值。用平均值填充是一種處理缺失值常見的方式。此處我們可以使用transform對每一組按照組內(nèi)的平均值填充缺失值。

          小結:

          transform函數(shù)經(jīng)常與groupby一起使用,并將返回的數(shù)據(jù)重新分配到每個組去。利用這一點可以方便求占比和填充缺失值。但需要注意,相比于apply,它的局限在于只能處理單列的數(shù)據(jù)。

          后臺回復“transform”獲取本文全部代碼和pdf版本。

          Reference:

          https://www.codenong.com/19966018/

          https://www.cnblogs.com/junge-mike/p/12761227.html

          https://blog.csdn.net/qq_40587575/article/details/81204514

          https://pbpython.com/pandas_transform.html


          主站蜘蛛池模板: 中文字幕AV一区中文字幕天堂| 呦系列视频一区二区三区| av无码精品一区二区三区四区| 风间由美性色一区二区三区| 国产在线精品一区二区在线看| 任你躁国语自产一区在| 日本丰满少妇一区二区三区| 人妻夜夜爽天天爽爽一区| 亚洲高清成人一区二区三区| 精品免费国产一区二区| 天堂资源中文最新版在线一区 | 国产精久久一区二区三区| 亚洲av无码一区二区三区人妖 | 人妻无码一区二区三区AV| 国产精品小黄鸭一区二区三区| 男人的天堂亚洲一区二区三区| 国产自产对白一区| 亚洲一区二区三区国产精品无码| 国产成人精品一区二区三区免费| 国产vr一区二区在线观看| 国产精品99无码一区二区| 精品免费久久久久国产一区 | 亚欧色一区W666天堂| 国产激情视频一区二区三区| 少妇人妻偷人精品一区二区| 熟女少妇丰满一区二区| 中文字幕AV一区中文字幕天堂| 国产在线无码视频一区二区三区 | 亚欧色一区W666天堂| 亚洲福利一区二区三区| 国产精品夜色一区二区三区| 毛片一区二区三区无码| 相泽南亚洲一区二区在线播放 | 69久久精品无码一区二区| 亚洲国产成人精品无码一区二区 | 成人在线一区二区| 91麻豆精品国产自产在线观看一区| 久久久国产一区二区三区 | 亚洲国产欧美国产综合一区| 精品国产福利在线观看一区| 人妻无码一区二区三区|