<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知識點(diǎn)-詳解行列級批處理函數(shù)apply

          共 9893字,需瀏覽 20分鐘

           ·

          2022-07-06 09:44

          在Pandas中,DataFrame和Series等對象需要執(zhí)行批量處理操作時,可以借用apply()函數(shù)來實(shí)現(xiàn)。


          apply()的核心功能是實(shí)現(xiàn)“批量”調(diào)度處理,至于批量做什么,由用戶傳入的函數(shù)決定(自定義或現(xiàn)成的函數(shù))。函數(shù)傳遞給apply(),apply()會幫用戶在DataFrame和Series等對象中(按行或按列)批量執(zhí)行傳入的函數(shù)。


          先看一個例子:


          # coding=utf-8
          import pandas as pd

          df = pd.DataFrame({'Col-1': [135], 'Col-2': [246], 'Col-3': [987], 'Col-4': [369]},
                            index=['A''B''C'])
          print(df)
          df_new = df.apply(lambda x: x-1)
          print('-' * 30'\n', df_new, sep='')
             Col-1  Col-2  Col-3  Col-4
          A 1 2 9 3
          B 3 4 8 6
          C 5 6 7 9
          ------------------------------
          Col-1 Col-2 Col-3 Col-4
          A 0 1 8 2
          B 2 3 7 5
          C 4 5 6 8


          從這個例子可以看出,apply的使用非常簡便且優(yōu)雅,一行代碼就對DataFrame中的所有數(shù)據(jù)都執(zhí)行了一遍傳入的匿名函數(shù)。


          apply用法和參數(shù)介紹



          apply(self, func, axis=0, raw=False, result_type=None, args=(), **kwds):


          • func: 應(yīng)用于每一列或每一行的函數(shù),這個函數(shù)可以是Python內(nèi)置函數(shù)、Pandas或其他庫中的函數(shù)、自定義函數(shù)、匿名函數(shù)。

          • axis: 設(shè)置批處理函數(shù)按列還是按行應(yīng)用,0或index表示按列應(yīng)用函數(shù),1或columns表示按行應(yīng)用函數(shù),默認(rèn)值為0。

          • raw: 設(shè)置將列/行作為Series對象傳遞給函數(shù),還是作為ndarray對象傳遞給函數(shù)。raw是bool類型,默認(rèn)為False。

          False: 將列/行作為Series對象傳遞給函數(shù)。
          True: 將列/行作為ndarray對象傳遞給函數(shù)。apply中的func函數(shù)將接收ndarray對象,如果應(yīng)用numpy中的函數(shù),這樣可以提升性能。


          • result_type: 當(dāng)axis=1時,設(shè)置返回結(jié)果的類型和樣式,支持{'expand', 'reduce', 'broadcast', None}四種類型,默認(rèn)為None。

          expand: 列表式的結(jié)果將被轉(zhuǎn)化為列。
          reduce: 如果可能的話,返回一個Series,而不是返回列表式的結(jié)果。這與expand相反。
          broadcast: 結(jié)果將被廣播成DataFrame的原始形狀,DataFrame的原始索引和列將被保留。
          None: 結(jié)果取決于應(yīng)用函數(shù)的返回值,列表式的結(jié)果將以Series形式返回,如果應(yīng)用函數(shù)返回Series將會擴(kuò)展到列。

          • args: 傳給應(yīng)用函數(shù)func的位置參數(shù),args接收的數(shù)據(jù)類型為元組,如果只有一個位置參數(shù)要注意加逗號。


          • **kwds: 如果func中有關(guān)鍵字參數(shù),可以傳給**kwds。


          raw和result_type通常不需要自己設(shè)置,保持默認(rèn)即可。


          下面依次介紹apply()函數(shù)的各種用法。


          傳入不同類型的函數(shù)



          import numpy as np

          df = pd.DataFrame({'Col-1': [135], 'Col-2': [246], 'Col-3': [987], 'Col-4': [369]},
                            index=['A''B''C'])
          print(df)
          df1 = df.apply(max)  # python內(nèi)置函數(shù)
          print('-' * 30'\n', df1, sep='')
          df2 = df.apply(np.mean)  # numpy中的函數(shù)
          print('-' * 30'\n', df2, sep='')
          df3 = df.apply(pd.DataFrame.min)  # pandas中的方法
          print('-' * 30'\n', df3, sep='')
             Col-1  Col-2  Col-3  Col-4
          A 1 2 9 3
          B 3 4 8 6
          C 5 6 7 9
          ------------------------------
          Col-1 5
          Col-2 6
          Col-3 9
          Col-4 9
          dtype: int64
          ------------------------------
          Col-1 3.0
          Col-2 4.0
          Col-3 8.0
          Col-4 6.0
          dtype: float64
          ------------------------------
          Col-1 1
          Col-2 2
          Col-3 7
          Col-4 3
          dtype: int64
          def make_ok(s):
              return pd.Series(['{}ok'.format(d) for d in s])


          df4 = df.apply(make_ok)  # 自定義函數(shù)
          print('-' * 30'\n', df4, sep='')
          ------------------------------
          Col-1 Col-2 Col-3 Col-4
          0 1ok 2ok 9ok 3ok
          1 3ok 4ok 8ok 6ok
          2 5ok 6ok 7ok 9ok


          設(shè)置按行還是按列



          def make_ok(s):
              if isinstance(s, pd.Series):
                  if s.name in df.columns:
                      return pd.Series(['{}ok-列'.format(d) for d in s])
                  else:
                      return pd.Series(['{}ok-行'.format(d) for d in s])
              else:
                  return '{}ok'.format(s)


          df5 = df.apply(make_ok, axis=0)  # 按列處理
          print('-' * 30'\n', df5, sep='')
          df6 = df.apply(make_ok, axis=1)  # 按行處理
          print('-' * 30'\n', df6, sep='')
          ------------------------------
          Col-1 Col-2 Col-3 Col-4
          0 1ok-列 2ok-列 9ok-列 3ok-列
          1 3ok-列 4ok-列 8ok-列 6ok-列
          2 5ok-列 6ok-列 7ok-列 9ok-列
          ------------------------------
          0 1 2 3
          A 1ok-行 2ok-行 9ok-行 3ok-行
          B 3ok-行 4ok-行 8ok-行 6ok-行
          C 5ok-行 6ok-行 7ok-行 9ok-行


          這里推演一下按列和按行的過程,當(dāng)axis參數(shù)為0或index時,按列從DataFrame中取數(shù)據(jù),如上面的例子先取到第一列Col-1:[1, 3, 5],將第一列傳給函數(shù)func,然后取第二列Col-2:[2, 4, 6]...以此類推。當(dāng)axis參數(shù)為1或columns時,按行從DataFrame中取數(shù)據(jù),如上面的例子先取到第一行A:[1, 2, 9, 3],將第一行傳遞給函數(shù)func執(zhí)行后取第二行,以此類推。


          同時,當(dāng)按列應(yīng)用函數(shù)時,DataFrame的index變成了默認(rèn)索引(0開始的自然數(shù)),當(dāng)按行應(yīng)用函數(shù)時,DataFrame的columns變成了默認(rèn)索引,如果要保持與原DataFrame一樣,則需要重新設(shè)置。


          函數(shù)func的參數(shù)



          def yes_or_no(s, answer):
              if answer != 'yes' and answer != 'no':
                  answer = 'yes'
              if isinstance(s, pd.Series):
                  return pd.Series(['{}-{}'.format(d, answer) for d in s])
              else:
                  return '{}-{}'.format(s, answer)


          df7 = df.apply(yes_or_no, args=('yes',))
          df7.index = ['A''B''C']
          print('-' * 30'\n', df7, sep='')
          df8 = df.apply(yes_or_no, args=('no',))
          print('-' * 30'\n', df8, sep='')
          df9 = df.apply(yes_or_no, args=(0,))
          print('-' * 30'\n', df9, sep='')
          ------------------------------
          Col-1 Col-2 Col-3 Col-4
          A 1-yes 2-yes 9-yes 3-yes
          B 3-yes 4-yes 8-yes 6-yes
          C 5-yes 6-yes 7-yes 9-yes
          ------------------------------
          Col-1 Col-2 Col-3 Col-4
          0 1-no 2-no 9-no 3-no
          1 3-no 4-no 8-no 6-no
          2 5-no 6-no 7-no 9-no
          ------------------------------
          Col-1 Col-2 Col-3 Col-4
          0 1-yes 2-yes 9-yes 3-yes
          1 3-yes 4-yes 8-yes 6-yes
          2 5-yes 6-yes 7-yes 9-yes


          在apply()中,func函數(shù)的第一個參數(shù)默認(rèn)會傳入Series對象,這就是前面說的“將列/行作為Series對象傳遞給函數(shù)”,因此函數(shù)func至少要有一個參數(shù),這個參數(shù)相當(dāng)于類方法中的self,不需要在args中傳值。如果func沒有參數(shù),則不能在apply中使用。


          如果func的參數(shù)多于一個,則多出來的參數(shù)通過args傳遞,args接收一個元組,args里只有一個值時,需要加上逗號。如果func中有關(guān)鍵字參數(shù),可以傳到apply中**kwds的位置。


          傳入多個函數(shù)進(jìn)行聚合



          df10 = df.apply([np.max, np.min])
          print('-' * 40'\n', df10, sep='')
          df11 = df.apply({'Col-1': np.mean, 'Col-2': np.min})
          print('-' * 40'\n', df11, sep='')
          df12 = df.apply({'Col-1': [np.mean, np.median], 'Col-2': [np.min, np.mean]})
          print('-' * 40'\n', df12, sep='')
          ----------------------------------------
          Col-1 Col-2 Col-3 Col-4
          amax 5 6 9 9
          amin 1 2 7 3
          ----------------------------------------
          Col-1 3.0
          Col-2 2.0
          dtype: float64
          ----------------------------------------
          Col-1 Col-2
          mean 3.0 4.0
          median 3.0 NaN
          amin NaN 2.0


          當(dāng)在apply中傳入多個函數(shù)時,返回的結(jié)果被聚合成一個新的DataFrame或Series,作用類似于pandas中的聚合函數(shù)DataFrame.agg()。[后續(xù)文章會介紹agg()]


          通過函數(shù)名字符串調(diào)用函數(shù)



          df13 = df.apply('mean', axis=1)
          print('-' * 30'\n', df13, sep='')
          df14 = df.apply(['mean''min'], axis=1)
          print('-' * 30'\n', df14, sep='')
          ------------------------------
          A 3.75
          B 5.25
          C 6.75
          dtype: float64
          ------------------------------
          mean min
          A 3.75 1.0
          B 5.25 3.0
          C 6.75 5.0


          apply()支持函數(shù)名用字符串傳給func,調(diào)用函數(shù)。


          修改DataFrame本身



          df15 = df.copy()
          # 讀取df的一列,將處理結(jié)果添加到原df中,增加一列
          df15['Col-x'] = df15['Col-1'].apply(make_ok)
          print('-' * 40'\n', df15, sep='')
          # 讀取df的一行,將處理結(jié)果添加到原df中,增加一行
          df15.loc['Z'] = df15.loc['A'].apply(yes_or_no, args=('yes',))
          print('-' * 40'\n', df15, sep='')
          ----------------------------------------
          Col-1 Col-2 Col-3 Col-4 Col-x
          A 1 2 9 3 1ok
          B 3 4 8 6 3ok
          C 5 6 7 9 5ok
          ----------------------------------------
          Col-1 Col-2 Col-3 Col-4 Col-x
          A 1 2 9 3 1ok
          B 3 4 8 6 3ok
          C 5 6 7 9 5ok
          Z 1-yes 2-yes 9-yes 3-yes 1ok-yes


          DataFrame增加一列或一行可以直接賦值,修改一個DataFrame后將結(jié)果賦值給本身,這樣相當(dāng)于修改了原始DataFrame。


          Series使用apply



          s0 = df['Col-2'].apply(make_ok)
          print('-' * 20'\n', s0, sep='')
          s = pd.Series(range(5), index=[alpha for alpha in 'abcde'])
          print('-' * 20'\n', s, sep='')
          s1 = s.apply(make_ok)
          print('-' * 20'\n', s1, sep='')
          --------------------
          A 2ok
          B 4ok
          C 6ok
          Name: Col-2, dtype: object
          --------------------
          a 0
          b 1
          c 2
          d 3
          e 4
          dtype: int64
          --------------------
          a 0ok
          b 1ok
          c 2ok
          d 3ok
          e 4ok
          dtype: object


          DataFrame中的一行或一列都是一個Series,所以用DataFrame的列或行調(diào)用apply()就相當(dāng)于Series調(diào)用apply()。


          在DataFrame中,apply()將行/列作為Series傳給func函數(shù),在Series中,apply()將Series中的每一個值傳給func函數(shù)。對于這兩種情況,func接受的參數(shù)類型完全不一樣,因此使用時一定要注意func函數(shù)的參數(shù)類型,否則可能不適用。


          s2 = s.apply(np.mean)
          print('-' * 20'\n', s2, sep='')
          s3 = np.mean(s)
          print('-' * 20'\n', s3, sep='')
          --------------------
          a 0.0
          b 1.0
          c 2.0
          d 3.0
          e 4.0
          dtype: float64
          --------------------
          2.0

          將Series中的每一個值傳給apply()中的函數(shù)func,返回的結(jié)果仍然是一個Series。將Series作為一個整體傳給apply()中的函數(shù)func,有些函數(shù)返回的結(jié)果仍然是Series,如上面的自定義函數(shù),有些函數(shù)返回的結(jié)果不再是Series,而是一個其他類型的數(shù)據(jù),如numpy中的統(tǒng)計(jì)運(yùn)算函數(shù)(mean、max、min)等。


          因此DataFrame經(jīng)過apply()批處理后,可能會變成一個Series,這是由apply()中的函數(shù)func的返回值決定的,與apply()無關(guān)。


          以上就是pandas中的apply()函數(shù)的用法介紹和分析,希望對你有幫助,想要深入的了解apply()函數(shù)的底層原理,可以打個斷點(diǎn),在“Debugger”模式中看運(yùn)行過程,也可以看源碼。如果你有其他的想法或疑問,歡迎加我好友一起交流討論。

          參考文檔: 

          [1] pandas中文網(wǎng):https://www.pypandas.cn/docs/

          瀏覽 35
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  找骚逼18. | 欧美伊人网 | 成人AV一AV二 | 一区二区三区四区五区六区七区八区九区 | 丁香五月天婷国产 |