按因子分组并返回其他列的第二个最小值

时间:2019-06-24 23:37:36

标签: python pandas

我想将此数据帧按zipcode列中的值进行分组,然后在另一个(称为“速率”)列中返回second lowest速率或lowest速率或{ {1}}率。

例如,来自此df:

max

我希望:

zipcode state   county_code name    rate_area_x plan_id metal_level rate    rate_area_y
36749   AL  1001    Autauga 11  52161YL6358432  Silver  245.82  6
36749   AL  1001    Autauga 11  01100AO4222848  Silver  271.77  5
36749   AL  1001    Autauga 11  24848KC5063721  Silver  264.84  1
36749   AL  1001    Autauga 11  89885YK0256118  Silver  269.11  8
36749   AL  1001    Autauga 11  65392ON5819785  Silver  305.02  12
30165   AL  1019    Cherokee    13  52161YL6358432  Silver  245.82  6
30165   AL  1019    Cherokee    13  01100AO4222848  Silver  271.77  5
30165   AL  1019    Cherokee    13  24848KC5063721  Silver  264.84  1
30165   AL  1019    Cherokee    13  89885YK0256118  Silver  269.11  8
30165   AL  1019    Cherokee    13  65392ON5819785  Silver  305.02  12
30165   AL  1019    Cherokee    13  90884WN5801293  Silver  323.25  2
30165   AL  1019    Cherokee    13  79113BU1788705  Silver  344.81  7

在R中,我这样做是为了获取每个邮政编码组的最小值:

zipcode rate
36749   245.82
30165   245.82

但是如何使用Python的Pandas获得第二低的费率值?

3 个答案:

答案 0 :(得分:4)

编辑:在一般情况下,我会为您提供最小和第二个最小的选择。但是,正如@WenYoBen在评论中提到的那样,您可能只希望倒数第二。在这种情况下,您只需要链接reset_indexdropdrop_duplicates来获得最小或第二个最小,如下所示:

变得最小

df.groupby('zipcode').rate.nsmallest(2).reset_index().drop('level_1',1) \
  .drop_duplicates(subset=['zipcode'])

Out[2108]:
       zipcode    rate
    0    30165  245.82
    2    36749  245.82

获得最小的第二个

df.groupby('zipcode').rate.nsmallest(2).reset_index().drop('level_1',1) \
  .drop_duplicates(subset=['zipcode'], keep='last')

Out[2109]:
   zipcode    rate
1    30165  264.84
3    36749  264.84    

原始

groupby.nsmallest将为您提供每组最小和第二小的

df.groupby('zipcode').rate.nsmallest(2)

Out[2083]:
zipcode
30165    5    245.82
         7    264.84
36749    0    245.82
         2    264.84
Name: rate, dtype: float64

答案 1 :(得分:1)

要将结果放入Dataframe中,可以将group_by方法与to_frame一起使用。请注意,要获得第n个最低值(而不是第[:nth]个最低值),请对df进行排序,然后选择所需的n

import pandas as pd

data="""zipcode state   county_code name    rate_area_x plan_id metal_level rate    rate_area_y
36749   AL  1001    Autauga 11  52161YL6358432  Silver  245.82  6
36749   AL  1001    Autauga 11  01100AO4222848  Silver  271.77  5
36749   AL  1001    Autauga 11  24848KC5063721  Silver  264.84  1
36749   AL  1001    Autauga 11  89885YK0256118  Silver  269.11  8
36749   AL  1001    Autauga 11  65392ON5819785  Silver  305.02  12
30165   AL  1019    Cherokee    13  52161YL6358432  Silver  245.82  6
30165   AL  1019    Cherokee    13  01100AO4222848  Silver  271.77  5
30165   AL  1019    Cherokee    13  24848KC5063721  Silver  264.84  1
30165   AL  1019    Cherokee    13  89885YK0256118  Silver  269.11  8
30165   AL  1019    Cherokee    13  65392ON5819785  Silver  305.02  12
30165   AL  1019    Cherokee    13  90884WN5801293  Silver  323.25  2
30165   AL  1019    Cherokee    13  79113BU1788705  Silver  344.81  7"""

# create dataframe
n_columns = 9
data = [data.split()[x:x+n_columns] for x in range(0, len(data.split()), n_columns)]
df = pd.DataFrame(data[1:], columns=data[0]).apply(pd.to_numeric, errors='ignore')

# ensure the dataframe is sorted
df = df.sort_values(['zipcode','rate'])

min_df = df.groupby('zipcode').rate.min().to_frame(name = 'rate').reset_index()

max_df = df.groupby('zipcode').rate.max().to_frame(name = 'rate').reset_index()

second_lowest_df = df.groupby('zipcode').rate.nth(1).to_frame(name = 'rate').reset_index()

答案 2 :(得分:1)

sort然后groupby + nth。这使您可以灵活地选择任意排名的值(通过传递列表)。如果您不想重复计算相同的值,请删除重复项。

df.sort_values(['rate']).groupby('zipcode').rate.nth([1])
#zipcode
#30165    264.84
#36749    264.84
#Name: rate, dtype: float64

如果您想要最小,第四最小和最大值:

df.sort_values(['rate']).groupby('zipcode').rate.nth([0, 3, -1])
#zipcode
#30165    245.82
#30165    271.77
#30165    344.81
#36749    245.82
#36749    271.77
#36749    305.02
#Name: rate, dtype: float64

超出范围的选择将在不存在的组中被忽略:

df.sort_values(['rate']).groupby('zipcode').rate.nth(5)
#zipcode
#30165    323.25
#Name: rate, dtype: float64

冗余选择器不重复计算(6和-1均指30165中的最大元素)

df.sort_values(['rate']).groupby('zipcode').rate.nth([6, 6, -1])
#zipcode
#30165    344.81
#36749    305.02
#Name: rate, dtype: float64