Estimate the mean of a DataFrameGroupBy by only considering values in a percentile range










4















I need to estimate the mean of a pandas DataFrameGroupBy by only considering the values between a given percentile range.



For instance, given the snippet



import numpy as np
import pandas as pd
a = np.matrix('1 1; 1 2; 1 4; 2 1; 2 2; 2 4')
data = pd.DataFrame(a)
groupby = data.groupby(0)
m1 = groupby.mean()


the result is



m1 = 1
0
1 2.333333
2 2.333333


However, if a percentile range is picked to exclude the maximum and minimum values the result should be



m1 = 1
0
1 2
2 2


How can I filter, for each group, the values between an arbitrary percentile range before estimating the mean? For instance, only considering the values between the 20th and 80th percentiles.










share|improve this question




























    4















    I need to estimate the mean of a pandas DataFrameGroupBy by only considering the values between a given percentile range.



    For instance, given the snippet



    import numpy as np
    import pandas as pd
    a = np.matrix('1 1; 1 2; 1 4; 2 1; 2 2; 2 4')
    data = pd.DataFrame(a)
    groupby = data.groupby(0)
    m1 = groupby.mean()


    the result is



    m1 = 1
    0
    1 2.333333
    2 2.333333


    However, if a percentile range is picked to exclude the maximum and minimum values the result should be



    m1 = 1
    0
    1 2
    2 2


    How can I filter, for each group, the values between an arbitrary percentile range before estimating the mean? For instance, only considering the values between the 20th and 80th percentiles.










    share|improve this question


























      4












      4








      4








      I need to estimate the mean of a pandas DataFrameGroupBy by only considering the values between a given percentile range.



      For instance, given the snippet



      import numpy as np
      import pandas as pd
      a = np.matrix('1 1; 1 2; 1 4; 2 1; 2 2; 2 4')
      data = pd.DataFrame(a)
      groupby = data.groupby(0)
      m1 = groupby.mean()


      the result is



      m1 = 1
      0
      1 2.333333
      2 2.333333


      However, if a percentile range is picked to exclude the maximum and minimum values the result should be



      m1 = 1
      0
      1 2
      2 2


      How can I filter, for each group, the values between an arbitrary percentile range before estimating the mean? For instance, only considering the values between the 20th and 80th percentiles.










      share|improve this question
















      I need to estimate the mean of a pandas DataFrameGroupBy by only considering the values between a given percentile range.



      For instance, given the snippet



      import numpy as np
      import pandas as pd
      a = np.matrix('1 1; 1 2; 1 4; 2 1; 2 2; 2 4')
      data = pd.DataFrame(a)
      groupby = data.groupby(0)
      m1 = groupby.mean()


      the result is



      m1 = 1
      0
      1 2.333333
      2 2.333333


      However, if a percentile range is picked to exclude the maximum and minimum values the result should be



      m1 = 1
      0
      1 2
      2 2


      How can I filter, for each group, the values between an arbitrary percentile range before estimating the mean? For instance, only considering the values between the 20th and 80th percentiles.







      python pandas dataframe group-by pandas-groupby






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 13 '18 at 10:16









      jpp

      100k2161111




      100k2161111










      asked Nov 13 '18 at 9:07









      w4bow4bo

      1005




      1005






















          5 Answers
          5






          active

          oldest

          votes


















          1














          You can use a custom function with either np.percentile or pd.Series.quantile. The performance difference is marginal. The below example includes values only above the 20th and below the 80th percentile in calculating groupwise mean.



          import pandas as pd
          import numpy as np

          a = np.matrix('1 1; 1 2; 1 4; 2 1; 2 2; 2 4')
          data = pd.DataFrame(a)

          def jpp_np(df):
          def meaner(x, lowperc, highperc):
          low, high = np.percentile(x, [lowperc, highperc])
          return x[(x > low) & (x < high)].mean()
          return df.groupby(0)[1].apply(meaner, 20, 80).reset_index()

          def jpp_pd(df):
          def meaner(x, lowperc, highperc):
          low, high = x.quantile([lowperc/100, highperc/100]).values
          return x[x.between(low, high, inclusive=False)].mean()
          return df.groupby(0)[1].apply(meaner, 20, 80).reset_index()

          data = pd.concat([data]*10000)

          assert np.array_equal(jpp_np(data), jpp_pd(data))

          %timeit jpp_np(data) # 11.2 ms per loop
          %timeit jpp_pd(data) # 12.5 ms per loop





          share|improve this answer






























            0














            You can define a function to calculate this mean for a dataframe, then do use the apply method. Something like :



            def mean_percent(df,per1,per2):
            #Write meaningful code here

            data = pd.DataFrame(a)
            groupby = data.groupby(0)
            m1 = groupby.apply(lambda df: mean_percent(df,20,80))


            This will calculate mean with value in 20-80 percentile range for each group.
            If you need help writing the first function, feel free to ask in the comment, and i'll edit this answer.






            share|improve this answer























            • Yep, implementing the mean_percent function will improve the self-containment of the answer :) Please also note that in pandas percentiles are included in [0, 1].

              – w4bo
              Nov 13 '18 at 9:31


















            0














            One approach is to filter the dataframe before using groupby. You can sort the dataframe by the column of interest and then exclude the first and last rows.



            data = data.sort_values(1).iloc[1:-1,:]
            groupby = data.groupby(0)
            m1 = groupby.mean()


            Another side note: it's best practice to not use the same variable name as a common method such as 'groupby'. If you can change that to some other name, that would be highly recommended.






            share|improve this answer






























              0














              try



              data.sort_values(by=1).groupby(by=0).agg(['first','last']).mean()


              OR



              data.sort_values(by=1).groupby(by=0).agg(['min','max']).mean()





              share|improve this answer
































                0














                Use np.percentile or np.quantile with groupby+apply:



                a = np.matrix('1 1 2; 1 2 3; 1 4 4; 2 1 6; 2 2 8; 2 4 16;7 8 45;9 10 9;11 12 3')
                df = pd.DataFrame(a,columns=['a','b','c'])
                #drop column which is key for grouping
                min_val,max_val = np.percentile(df.drop('a',1).values,[20,80],axis=0)
                #alternative np.quantile(df.drop('a',1).values,[0.2,0.8],axis=0)
                df1 = df.groupby('a').apply(lambda x: x[(x<max_val)&(x>min_val)].mean())

                print(df1)
                b c
                a
                1 3.0 4.0
                2 3.0 7.0
                7 8.0 NaN
                9 NaN 9.0
                11 NaN NaN





                share|improve this answer
























                  Your Answer






                  StackExchange.ifUsing("editor", function ()
                  StackExchange.using("externalEditor", function ()
                  StackExchange.using("snippets", function ()
                  StackExchange.snippets.init();
                  );
                  );
                  , "code-snippets");

                  StackExchange.ready(function()
                  var channelOptions =
                  tags: "".split(" "),
                  id: "1"
                  ;
                  initTagRenderer("".split(" "), "".split(" "), channelOptions);

                  StackExchange.using("externalEditor", function()
                  // Have to fire editor after snippets, if snippets enabled
                  if (StackExchange.settings.snippets.snippetsEnabled)
                  StackExchange.using("snippets", function()
                  createEditor();
                  );

                  else
                  createEditor();

                  );

                  function createEditor()
                  StackExchange.prepareEditor(
                  heartbeatType: 'answer',
                  autoActivateHeartbeat: false,
                  convertImagesToLinks: true,
                  noModals: true,
                  showLowRepImageUploadWarning: true,
                  reputationToPostImages: 10,
                  bindNavPrevention: true,
                  postfix: "",
                  imageUploader:
                  brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
                  contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
                  allowUrls: true
                  ,
                  onDemand: true,
                  discardSelector: ".discard-answer"
                  ,immediatelyShowMarkdownHelp:true
                  );



                  );













                  draft saved

                  draft discarded


















                  StackExchange.ready(
                  function ()
                  StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53277378%2festimate-the-mean-of-a-dataframegroupby-by-only-considering-values-in-a-percenti%23new-answer', 'question_page');

                  );

                  Post as a guest















                  Required, but never shown

























                  5 Answers
                  5






                  active

                  oldest

                  votes








                  5 Answers
                  5






                  active

                  oldest

                  votes









                  active

                  oldest

                  votes






                  active

                  oldest

                  votes









                  1














                  You can use a custom function with either np.percentile or pd.Series.quantile. The performance difference is marginal. The below example includes values only above the 20th and below the 80th percentile in calculating groupwise mean.



                  import pandas as pd
                  import numpy as np

                  a = np.matrix('1 1; 1 2; 1 4; 2 1; 2 2; 2 4')
                  data = pd.DataFrame(a)

                  def jpp_np(df):
                  def meaner(x, lowperc, highperc):
                  low, high = np.percentile(x, [lowperc, highperc])
                  return x[(x > low) & (x < high)].mean()
                  return df.groupby(0)[1].apply(meaner, 20, 80).reset_index()

                  def jpp_pd(df):
                  def meaner(x, lowperc, highperc):
                  low, high = x.quantile([lowperc/100, highperc/100]).values
                  return x[x.between(low, high, inclusive=False)].mean()
                  return df.groupby(0)[1].apply(meaner, 20, 80).reset_index()

                  data = pd.concat([data]*10000)

                  assert np.array_equal(jpp_np(data), jpp_pd(data))

                  %timeit jpp_np(data) # 11.2 ms per loop
                  %timeit jpp_pd(data) # 12.5 ms per loop





                  share|improve this answer



























                    1














                    You can use a custom function with either np.percentile or pd.Series.quantile. The performance difference is marginal. The below example includes values only above the 20th and below the 80th percentile in calculating groupwise mean.



                    import pandas as pd
                    import numpy as np

                    a = np.matrix('1 1; 1 2; 1 4; 2 1; 2 2; 2 4')
                    data = pd.DataFrame(a)

                    def jpp_np(df):
                    def meaner(x, lowperc, highperc):
                    low, high = np.percentile(x, [lowperc, highperc])
                    return x[(x > low) & (x < high)].mean()
                    return df.groupby(0)[1].apply(meaner, 20, 80).reset_index()

                    def jpp_pd(df):
                    def meaner(x, lowperc, highperc):
                    low, high = x.quantile([lowperc/100, highperc/100]).values
                    return x[x.between(low, high, inclusive=False)].mean()
                    return df.groupby(0)[1].apply(meaner, 20, 80).reset_index()

                    data = pd.concat([data]*10000)

                    assert np.array_equal(jpp_np(data), jpp_pd(data))

                    %timeit jpp_np(data) # 11.2 ms per loop
                    %timeit jpp_pd(data) # 12.5 ms per loop





                    share|improve this answer

























                      1












                      1








                      1







                      You can use a custom function with either np.percentile or pd.Series.quantile. The performance difference is marginal. The below example includes values only above the 20th and below the 80th percentile in calculating groupwise mean.



                      import pandas as pd
                      import numpy as np

                      a = np.matrix('1 1; 1 2; 1 4; 2 1; 2 2; 2 4')
                      data = pd.DataFrame(a)

                      def jpp_np(df):
                      def meaner(x, lowperc, highperc):
                      low, high = np.percentile(x, [lowperc, highperc])
                      return x[(x > low) & (x < high)].mean()
                      return df.groupby(0)[1].apply(meaner, 20, 80).reset_index()

                      def jpp_pd(df):
                      def meaner(x, lowperc, highperc):
                      low, high = x.quantile([lowperc/100, highperc/100]).values
                      return x[x.between(low, high, inclusive=False)].mean()
                      return df.groupby(0)[1].apply(meaner, 20, 80).reset_index()

                      data = pd.concat([data]*10000)

                      assert np.array_equal(jpp_np(data), jpp_pd(data))

                      %timeit jpp_np(data) # 11.2 ms per loop
                      %timeit jpp_pd(data) # 12.5 ms per loop





                      share|improve this answer













                      You can use a custom function with either np.percentile or pd.Series.quantile. The performance difference is marginal. The below example includes values only above the 20th and below the 80th percentile in calculating groupwise mean.



                      import pandas as pd
                      import numpy as np

                      a = np.matrix('1 1; 1 2; 1 4; 2 1; 2 2; 2 4')
                      data = pd.DataFrame(a)

                      def jpp_np(df):
                      def meaner(x, lowperc, highperc):
                      low, high = np.percentile(x, [lowperc, highperc])
                      return x[(x > low) & (x < high)].mean()
                      return df.groupby(0)[1].apply(meaner, 20, 80).reset_index()

                      def jpp_pd(df):
                      def meaner(x, lowperc, highperc):
                      low, high = x.quantile([lowperc/100, highperc/100]).values
                      return x[x.between(low, high, inclusive=False)].mean()
                      return df.groupby(0)[1].apply(meaner, 20, 80).reset_index()

                      data = pd.concat([data]*10000)

                      assert np.array_equal(jpp_np(data), jpp_pd(data))

                      %timeit jpp_np(data) # 11.2 ms per loop
                      %timeit jpp_pd(data) # 12.5 ms per loop






                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Nov 13 '18 at 10:06









                      jppjpp

                      100k2161111




                      100k2161111























                          0














                          You can define a function to calculate this mean for a dataframe, then do use the apply method. Something like :



                          def mean_percent(df,per1,per2):
                          #Write meaningful code here

                          data = pd.DataFrame(a)
                          groupby = data.groupby(0)
                          m1 = groupby.apply(lambda df: mean_percent(df,20,80))


                          This will calculate mean with value in 20-80 percentile range for each group.
                          If you need help writing the first function, feel free to ask in the comment, and i'll edit this answer.






                          share|improve this answer























                          • Yep, implementing the mean_percent function will improve the self-containment of the answer :) Please also note that in pandas percentiles are included in [0, 1].

                            – w4bo
                            Nov 13 '18 at 9:31















                          0














                          You can define a function to calculate this mean for a dataframe, then do use the apply method. Something like :



                          def mean_percent(df,per1,per2):
                          #Write meaningful code here

                          data = pd.DataFrame(a)
                          groupby = data.groupby(0)
                          m1 = groupby.apply(lambda df: mean_percent(df,20,80))


                          This will calculate mean with value in 20-80 percentile range for each group.
                          If you need help writing the first function, feel free to ask in the comment, and i'll edit this answer.






                          share|improve this answer























                          • Yep, implementing the mean_percent function will improve the self-containment of the answer :) Please also note that in pandas percentiles are included in [0, 1].

                            – w4bo
                            Nov 13 '18 at 9:31













                          0












                          0








                          0







                          You can define a function to calculate this mean for a dataframe, then do use the apply method. Something like :



                          def mean_percent(df,per1,per2):
                          #Write meaningful code here

                          data = pd.DataFrame(a)
                          groupby = data.groupby(0)
                          m1 = groupby.apply(lambda df: mean_percent(df,20,80))


                          This will calculate mean with value in 20-80 percentile range for each group.
                          If you need help writing the first function, feel free to ask in the comment, and i'll edit this answer.






                          share|improve this answer













                          You can define a function to calculate this mean for a dataframe, then do use the apply method. Something like :



                          def mean_percent(df,per1,per2):
                          #Write meaningful code here

                          data = pd.DataFrame(a)
                          groupby = data.groupby(0)
                          m1 = groupby.apply(lambda df: mean_percent(df,20,80))


                          This will calculate mean with value in 20-80 percentile range for each group.
                          If you need help writing the first function, feel free to ask in the comment, and i'll edit this answer.







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Nov 13 '18 at 9:13









                          Statistic DeanStatistic Dean

                          41311




                          41311












                          • Yep, implementing the mean_percent function will improve the self-containment of the answer :) Please also note that in pandas percentiles are included in [0, 1].

                            – w4bo
                            Nov 13 '18 at 9:31

















                          • Yep, implementing the mean_percent function will improve the self-containment of the answer :) Please also note that in pandas percentiles are included in [0, 1].

                            – w4bo
                            Nov 13 '18 at 9:31
















                          Yep, implementing the mean_percent function will improve the self-containment of the answer :) Please also note that in pandas percentiles are included in [0, 1].

                          – w4bo
                          Nov 13 '18 at 9:31





                          Yep, implementing the mean_percent function will improve the self-containment of the answer :) Please also note that in pandas percentiles are included in [0, 1].

                          – w4bo
                          Nov 13 '18 at 9:31











                          0














                          One approach is to filter the dataframe before using groupby. You can sort the dataframe by the column of interest and then exclude the first and last rows.



                          data = data.sort_values(1).iloc[1:-1,:]
                          groupby = data.groupby(0)
                          m1 = groupby.mean()


                          Another side note: it's best practice to not use the same variable name as a common method such as 'groupby'. If you can change that to some other name, that would be highly recommended.






                          share|improve this answer



























                            0














                            One approach is to filter the dataframe before using groupby. You can sort the dataframe by the column of interest and then exclude the first and last rows.



                            data = data.sort_values(1).iloc[1:-1,:]
                            groupby = data.groupby(0)
                            m1 = groupby.mean()


                            Another side note: it's best practice to not use the same variable name as a common method such as 'groupby'. If you can change that to some other name, that would be highly recommended.






                            share|improve this answer

























                              0












                              0








                              0







                              One approach is to filter the dataframe before using groupby. You can sort the dataframe by the column of interest and then exclude the first and last rows.



                              data = data.sort_values(1).iloc[1:-1,:]
                              groupby = data.groupby(0)
                              m1 = groupby.mean()


                              Another side note: it's best practice to not use the same variable name as a common method such as 'groupby'. If you can change that to some other name, that would be highly recommended.






                              share|improve this answer













                              One approach is to filter the dataframe before using groupby. You can sort the dataframe by the column of interest and then exclude the first and last rows.



                              data = data.sort_values(1).iloc[1:-1,:]
                              groupby = data.groupby(0)
                              m1 = groupby.mean()


                              Another side note: it's best practice to not use the same variable name as a common method such as 'groupby'. If you can change that to some other name, that would be highly recommended.







                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Nov 13 '18 at 9:23









                              K ZhaoK Zhao

                              213




                              213





















                                  0














                                  try



                                  data.sort_values(by=1).groupby(by=0).agg(['first','last']).mean()


                                  OR



                                  data.sort_values(by=1).groupby(by=0).agg(['min','max']).mean()





                                  share|improve this answer





























                                    0














                                    try



                                    data.sort_values(by=1).groupby(by=0).agg(['first','last']).mean()


                                    OR



                                    data.sort_values(by=1).groupby(by=0).agg(['min','max']).mean()





                                    share|improve this answer



























                                      0












                                      0








                                      0







                                      try



                                      data.sort_values(by=1).groupby(by=0).agg(['first','last']).mean()


                                      OR



                                      data.sort_values(by=1).groupby(by=0).agg(['min','max']).mean()





                                      share|improve this answer















                                      try



                                      data.sort_values(by=1).groupby(by=0).agg(['first','last']).mean()


                                      OR



                                      data.sort_values(by=1).groupby(by=0).agg(['min','max']).mean()






                                      share|improve this answer














                                      share|improve this answer



                                      share|improve this answer








                                      edited Nov 13 '18 at 9:30

























                                      answered Nov 13 '18 at 9:21









                                      pygopygo

                                      3,0551619




                                      3,0551619





















                                          0














                                          Use np.percentile or np.quantile with groupby+apply:



                                          a = np.matrix('1 1 2; 1 2 3; 1 4 4; 2 1 6; 2 2 8; 2 4 16;7 8 45;9 10 9;11 12 3')
                                          df = pd.DataFrame(a,columns=['a','b','c'])
                                          #drop column which is key for grouping
                                          min_val,max_val = np.percentile(df.drop('a',1).values,[20,80],axis=0)
                                          #alternative np.quantile(df.drop('a',1).values,[0.2,0.8],axis=0)
                                          df1 = df.groupby('a').apply(lambda x: x[(x<max_val)&(x>min_val)].mean())

                                          print(df1)
                                          b c
                                          a
                                          1 3.0 4.0
                                          2 3.0 7.0
                                          7 8.0 NaN
                                          9 NaN 9.0
                                          11 NaN NaN





                                          share|improve this answer





























                                            0














                                            Use np.percentile or np.quantile with groupby+apply:



                                            a = np.matrix('1 1 2; 1 2 3; 1 4 4; 2 1 6; 2 2 8; 2 4 16;7 8 45;9 10 9;11 12 3')
                                            df = pd.DataFrame(a,columns=['a','b','c'])
                                            #drop column which is key for grouping
                                            min_val,max_val = np.percentile(df.drop('a',1).values,[20,80],axis=0)
                                            #alternative np.quantile(df.drop('a',1).values,[0.2,0.8],axis=0)
                                            df1 = df.groupby('a').apply(lambda x: x[(x<max_val)&(x>min_val)].mean())

                                            print(df1)
                                            b c
                                            a
                                            1 3.0 4.0
                                            2 3.0 7.0
                                            7 8.0 NaN
                                            9 NaN 9.0
                                            11 NaN NaN





                                            share|improve this answer



























                                              0












                                              0








                                              0







                                              Use np.percentile or np.quantile with groupby+apply:



                                              a = np.matrix('1 1 2; 1 2 3; 1 4 4; 2 1 6; 2 2 8; 2 4 16;7 8 45;9 10 9;11 12 3')
                                              df = pd.DataFrame(a,columns=['a','b','c'])
                                              #drop column which is key for grouping
                                              min_val,max_val = np.percentile(df.drop('a',1).values,[20,80],axis=0)
                                              #alternative np.quantile(df.drop('a',1).values,[0.2,0.8],axis=0)
                                              df1 = df.groupby('a').apply(lambda x: x[(x<max_val)&(x>min_val)].mean())

                                              print(df1)
                                              b c
                                              a
                                              1 3.0 4.0
                                              2 3.0 7.0
                                              7 8.0 NaN
                                              9 NaN 9.0
                                              11 NaN NaN





                                              share|improve this answer















                                              Use np.percentile or np.quantile with groupby+apply:



                                              a = np.matrix('1 1 2; 1 2 3; 1 4 4; 2 1 6; 2 2 8; 2 4 16;7 8 45;9 10 9;11 12 3')
                                              df = pd.DataFrame(a,columns=['a','b','c'])
                                              #drop column which is key for grouping
                                              min_val,max_val = np.percentile(df.drop('a',1).values,[20,80],axis=0)
                                              #alternative np.quantile(df.drop('a',1).values,[0.2,0.8],axis=0)
                                              df1 = df.groupby('a').apply(lambda x: x[(x<max_val)&(x>min_val)].mean())

                                              print(df1)
                                              b c
                                              a
                                              1 3.0 4.0
                                              2 3.0 7.0
                                              7 8.0 NaN
                                              9 NaN 9.0
                                              11 NaN NaN






                                              share|improve this answer














                                              share|improve this answer



                                              share|improve this answer








                                              edited Nov 13 '18 at 10:27

























                                              answered Nov 13 '18 at 10:12









                                              Sandeep KadapaSandeep Kadapa

                                              7,008830




                                              7,008830



























                                                  draft saved

                                                  draft discarded
















































                                                  Thanks for contributing an answer to Stack Overflow!


                                                  • Please be sure to answer the question. Provide details and share your research!

                                                  But avoid


                                                  • Asking for help, clarification, or responding to other answers.

                                                  • Making statements based on opinion; back them up with references or personal experience.

                                                  To learn more, see our tips on writing great answers.




                                                  draft saved


                                                  draft discarded














                                                  StackExchange.ready(
                                                  function ()
                                                  StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53277378%2festimate-the-mean-of-a-dataframegroupby-by-only-considering-values-in-a-percenti%23new-answer', 'question_page');

                                                  );

                                                  Post as a guest















                                                  Required, but never shown





















































                                                  Required, but never shown














                                                  Required, but never shown












                                                  Required, but never shown







                                                  Required, but never shown

































                                                  Required, but never shown














                                                  Required, but never shown












                                                  Required, but never shown







                                                  Required, but never shown







                                                  Popular posts from this blog

                                                  Use pre created SQLite database for Android project in kotlin

                                                  Darth Vader #20

                                                  Ondo