在对Pandas DataFrame进行分箱后如何获得百分比

3
根据以下模拟DF:
df = pd.DataFrame({'State': {0: "AZ", 1: "AZ", 2:"AZ", 3: "AZ", 4: "AK", 5: "AK", 6 : "AK", 7: "AK"},
                 '# of Boxes': {0: 1, 1: 2, 2:2, 3: 1, 4: 2, 5: 2, 6 : 1, 7: 2},
                 'Price': {0: 2, 1: 4, 2:15, 3: 25, 4: 17, 5: 13, 6 : 3, 7: 3}},
                 columns=['State', '# of Boxes', 'Price'])

print(df)
  State  # of Boxes  Price
0    AZ           1      2
1    AZ           2      4
2    AZ           2     15
3    AZ           1     25
4    AK           2     17
5    AK           2     13
6    AK           1      3
7    AK           2      3

我希望将价格分为(0, 15],(15, 30],然后按盒子和州计算总额的百分比。

State    Box    Price (0,15]    Price (15,30]
 AZ      1        .5             .5
 AZ      2        1              0
 AK      1        1              0
 AK      2        .66            .33

我尝试使用聚合函数进行数据透视,但似乎无法解决问题。

谢谢!


1
你的代码没有在 print 中生成 DataFrame。 - Ami Tavory
你说得完全正确,错别字已经修正。谢谢! - M Arroyo
2个回答

3

我认为你可以使用groupby来按列分组,使用通过cut创建的离散化Series进行聚合,再使用size进行汇总,并通过unstack重新塑形:

print (pd.cut(df['Price'], bins=[0,15,30]))
0     (0, 15]
1     (0, 15]
2     (0, 15]
3    (15, 30]
4    (15, 30]
5     (0, 15]
6     (0, 15]
7     (0, 15]
Name: Price, dtype: category
Categories (2, object): [(0, 15] < (15, 30]

df1 = df.Price.groupby([df['State'],df['# of Boxes'],pd.cut(df['Price'], bins=[0,15,30])])
              .size()
              .unstack(fill_value=0)

print (df1)
Price             (0, 15]  (15, 30]
State # of Boxes                   
AK    1                 1         0
      2                 2         1
AZ    1                 1         1
      2                 2         0

然后使用 div 函数将所有值除以 sum

df1 = df1.div(df1.sum(axis=1), axis=0)
print (df1)
Price              (0, 15]  (15, 30]
State # of Boxes                    
AK    1           1.000000  0.000000
      2           0.666667  0.333333
AZ    1           0.500000  0.500000
      2           1.000000  0.000000

时间:

In [135]: %timeit (jez(df))
100 loops, best of 3: 3.51 ms per loop

In [136]: %timeit (maxu(df))
100 loops, best of 3: 6.21 ms per loop

def jez(df):
    df1 = df.Price.groupby([df['State'],df['# of Boxes'],pd.cut(df['Price'], bins=[0,15,30])]).size().unstack(fill_value=0)
    return  df1.div(df1.sum(1), axis=0)

def maxu(df):    
    pvt = df.assign(bins=pd.cut(df.Price, [0,15,30])).pivot_table(index=['State','# of Boxes'], columns='bins', aggfunc='size', fill_value=0)
    return pvt.apply(lambda x: x/pvt.sum(1))

2

这里有一个使用 pivot_table() 方法的解决方案:

In [57]: pvt = (df.assign(bins=pd.cut(df.Price, [0,15,30]))
   ....:          .pivot_table(index=['State','# of Boxes'],
   ....:                       columns='bins', aggfunc='size', fill_value=0)
   ....:       )

In [58]: pvt
Out[58]:
bins              (0, 15]  (15, 30]
State # of Boxes
AK    1                 1         0
      2                 2         1
AZ    1                 1         1
      2                 2         0

In [59]: pvt.apply(lambda x: x/pvt.sum(1))
Out[59]:
bins               (0, 15]  (15, 30]
State # of Boxes
AK    1           1.000000  0.000000
      2           0.666667  0.333333
AZ    1           0.500000  0.500000
      2           1.000000  0.000000

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接