<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>

          拯救pandas計劃(5)——獲取DataFrame分組topN數(shù)據(jù)

          共 2895字,需瀏覽 6分鐘

           ·

          2022-04-19 09:54

          拯救pandas計劃(5)——獲取DataFrame分組topN數(shù)據(jù)

          最近發(fā)現(xiàn)周圍的很多小伙伴們都不太樂意使用pandas,轉(zhuǎn)而投向其他的數(shù)據(jù)操作庫,身為一個數(shù)據(jù)工作者,基本上是張口pandas,閉口pandas了,故而寫下此系列以讓更多的小伙伴們愛上pandas。

          系列文章說明:

          系列名(系列文章序號)——此次系列文章具體解決的需求

          平臺:

          • windows 10
          • python 3.8
          • pandas >=1.2.4

          / 數(shù)據(jù)需求

          現(xiàn)有一組數(shù)據(jù),需要根據(jù)name進行分組,以date_col順序排序,獲取每組數(shù)據(jù)的前N項數(shù)據(jù)。

          為考慮比較各方案間的耗時,此次數(shù)據(jù)采用數(shù)據(jù)類別多量小的數(shù)據(jù)集。

          / 需求拆解

          整個數(shù)據(jù)框的前幾行或者后幾行都有相應(yīng)的方法可以調(diào)用,如head()、tail(),分組后的前幾行,只需要把整個數(shù)據(jù)框應(yīng)用到groupby上再對各個分組進行head()即可,而這里需要取得topN,則分組后不一定能夠按順序取得,故而需要對數(shù)據(jù)框進行排序。

          / 需求處理

          方法一

          正如需求拆解里提到過的,使用groupby來完成這部分任務(wù),在取得topN之前是需要對整個數(shù)據(jù)集進行排序的,這可以先嘗試下在groupby之前排序,還是之后排序是否會對整個任務(wù)執(zhí)行時間有影響。

          先排序,后分組

          df.sort_values(['name',?'date_col'],?inplace=True)
          df.groupby(['name']).head(1)

          先分組,后排序

          由于groupby后面不能直接跟sort_values,所以需要調(diào)用apply來對每個分組進行排序。

          分組后排序用時:

          df.groupby(['name']).apply(lambda?x:?x.sort_values('date_col').head(1)).reset_index(drop=True)

          看到這運行時間差了一個數(shù)量級,可能會懷疑是不是sort_values的問題,都知道pandas調(diào)用內(nèi)部函數(shù)時運行效率還算是過的去,怎么在這差了這么多,直接在groupby后面運行head()僅200ms,這會可以看看在apply里調(diào)用head()。在上圖可以看出拖慢運行時間的主要原因不是sort_values,而是apply,雖然apply的工作機制方便了對數(shù)據(jù)框內(nèi)的數(shù)據(jù)進行各種各樣的處理操作,但當存在一種內(nèi)部函數(shù)可以滿足需求時再選擇使用apply就會稍顯雞肋。?

          (手動水?。涸瓌?chuàng)CSDN宿者朽命,https://blog.csdn.net/weixin_46281427?spm=1011.2124.3001.5343,公眾號A11Dot派)?

          簡言之,在這種方式處理上,先排序再分組取topN是能夠較快的得到目標數(shù)據(jù)。

          方法二

          拯救pandas計劃(4)——DataFrame分組條件查找值中有提到過使用drop_duplicates(),同樣在這里分組取topN也可以一試,但有限制條件,其drop_duplicates()內(nèi)的keep參數(shù)決定了,僅能保留首個或尾個或者不保留重復(fù)數(shù)據(jù)。因此當只取top1時,可以試用此種方法,在處理時間上也過得去。

          df.sort_values(['name',?'date_col'],?inplace=True)
          df.drop_duplicates(['name'])??#?默認保留首個

          方法三

          雖然說有內(nèi)部函數(shù)直接能達成結(jié)果的優(yōu)先使用內(nèi)部函數(shù),但在這里不妨想一想如何在不使用groupby的方式求得分組topN。(可以先思考一會兒再繼續(xù)往下看)

          闡述下我的想法,僅做拋磚引玉之用,既然是分組取topN,不就是一種變相的分組排序,取排序靠前的值。以這樣的思路,先對組中的每個類型進行計數(shù),再編號即可取得。

          • 計數(shù):

          除了groupby外對類型進行計數(shù)還有一個好的方法,value_counts,這里需要將sort參數(shù)設(shè)置為False,避免內(nèi)部排序影響外部排序,在計數(shù)前依然是先對整個數(shù)據(jù)框進行排序。

          df.sort_values(['name',?'date_col'],?inplace=True)
          name_count?=?df.value_counts('name',?sort=False)
          • 編號:

          而后對name_count進行編號,使用lambda調(diào)用range(x)。

          name_count.map(lambda?x:?range(x))

          從生成的結(jié)果看來,Series中的values是一個可迭代序列,這種結(jié)果不能直接對原始數(shù)據(jù)框設(shè)置編號,取出values,使用np.hstack以行方向組合,對每個分組編號組合成一個一維數(shù)組。

          import?numpy?as?np

          df.sort_values(['name',?'date_col'],?inplace=True)
          np.hstack(df.value_counts('name',?sort=False).map(lambda?x:?range(x)).values)

          ps: values中的每個值都是一維數(shù)組

          • 取值:

          再對生成的值與想要提取的topN的N進行對比,進行布爾索引提取即可得到想要的topN數(shù)據(jù)。運行結(jié)果如下,時間上也能接受:
          以下是將這段代碼進行封裝成函數(shù):

          import?numpy?as?np
          import?pandas?as?pd


          def?get_data_top(data:?pd.DataFrame,?group_cols:?list,?val_cols:?list,?ascending:?bool?=?True,?k:?int?=?1):
          ????"""
          ????自定義獲取數(shù)據(jù)框topN
          ????:param?data:?pd.DataFrame類型
          ????:param?group_cols:?list,?需要聚合的列名
          ????:param?val_cols:?list,?需要排序的列名
          ????:param?ascending:?排序方式,默認`True`,順序排序,接收bool或這個列表里全部為bool的列表
          ????:param?k:?取前k項值
          ????:return:?返回topN數(shù)據(jù)框
          ????"""

          ????#?為了能返回傳入數(shù)據(jù)框的原index,將index保存至values中
          ????datac?=?data.reset_index().copy()
          ????index_colname?=?datac.columns[0]
          ????#?對原數(shù)據(jù)框進行排序
          ????datac.sort_values(group_cols?+?val_cols,?ascending=ascending,?inplace=True)
          ????#?主要代碼:分組對組內(nèi)進行編號
          ????rank0?=?np.hstack(datac.value_counts(group_cols,?sort=False).map(lambda?x:?range(x)).values)
          ????#?取topN值
          ????datac?=?datac[rank0?????#?取出原index重置為index值
          ????datac.index?=?datac[index_colname].values
          ????#?刪除額外生成的index值的列
          ????del?datac[index_colname]
          ????return?datac

          ps: 參數(shù)冒號后的類型僅做提示,輸入其他類型亦能入?yún)?,但需要傳入正確參數(shù)及類型才能正常輸出。

          / 總結(jié)

          文中使用三種方法來取得數(shù)據(jù)集中的前N項值,過程上略有不同,總的結(jié)果呈現(xiàn)也基本相同,在想法及做法上對個人都一種提升。在寫這篇之前,我一直在詢問我自己,這篇值不值得寫下來,把方法三刪了改,改了刪,起初并沒有使用numpy.hstack,而是直接使用list強轉(zhuǎn)range,偶然一次運行時發(fā)現(xiàn)運行時間竟然比groupby.head短,當時還竊竊自喜,復(fù)盤發(fā)現(xiàn)原來是我的把.head()運用在apply中,在方法一也有提到過這樣做的耗時。經(jīng)過幾番修改,最終采用np.hstack組合編號,效率上能勉強達到方法一水平。

          在書本中,在年長者口中,常常有一種聲音提醒我們現(xiàn)在站在了人生的十字路口,需要仔細思考,斟酌,推斷這樣做會有怎樣的結(jié)果,但現(xiàn)在還需要磨蹭啥呢,未來不是推斷出的未來,是創(chuàng)造的未來,敢于去想,敢于去做!


          于二零二二年元月二十四日作


          瀏覽 85
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  亚洲无码专区区免费 | 色毛片网站 | 尻屄视频在线免费观看 | 欧美一区高清 | 欧美天天好逼 |