getting percentage of values meeting conditions within a Pandas group by
<p>I have a dataframe of of <code>People</code>, <code>Days</code>, and <code>Types</code>. The data doesn't really make sense, it's just an example.</p>

<p>I'd like to do a group by first on <code>People</code> then <code>Type</code> and then find the percentage of Days that are less than or equal to 3.</p>

<p>In order to do this, I am created a <code>Boolean</code> column for equal or under 3 days. Then applying a <code>count</code> and <code>sum</code> aggregate. I'm not a big fan of this method because I really only need the <code>count</code> for the <code>Days</code> column and <code>sum</code> for the <code>Under Day Limit</code> column. This method is essentially creating two unnecessary columns and creates a number of extra steps. How can I clean this code up so it runs more efficiently over my larger dataset.</p>

<pre><code>import pandas as pd
# create dataframe
df = pd.DataFrame(data=[['A', 4, 'Type 1'],
                        ['A', 1, 'Type 1'],
                        ['A', 3, 'Type 2'],
                        ['A', 0, 'Type 1'],
                        ['A', 12, 'Type 2'],
                        ['B', 1, 'Type 1'],
                        ['B', 3, 'Type 1'],
                        ['B', 5, 'Type 2']],
                   columns=['Person', 'Days', 'Type'])

df['Under Day Limit'] = df['Days'] &lt;= 3;
print df
df = df.groupby(['Person', 'Type']).agg(['count', 'sum'])

df['Percent under Day Limit'] = df['Under Day Limit']['sum'] / df['Days']['count']
print df
</code></pre>

<p>Ouput:</p>

<pre><code>               Days     Under Day Limit     Percent under Day Limit
              count sum           count sum                        
Person Type                                                        
A      Type 1     3   5               3   2                0.666667
       Type 2     2  15               2   1                0.500000
B      Type 1     2   4               2   2                1.000000
       Type 2     1   5               1   0                0.000000
</code></pre>

<ul>
<li><code>set_index</code> on <code>Person</code> and <code>Type</code></li>
<li>boolean series of <code>Days</code> >= 3</li>
<li><code>groupby</code> levels in index</li>
<li><code>value_counts(normalize=True)</code></li>
</ul>

<hr>

<pre><code>df.set_index(['Person', 'Type']).Days.ge(3).groupby(level=[0, 1]).value_counts(True)

Person  Type    Days 
A       Type 1  False    0.666667
                True     0.333333
        Type 2  True     1.000000
B       Type 1  False    0.500000
                True     0.500000
        Type 2  True     1.000000
Name: Days, dtype: float64
</code></pre>

<hr>

<p><strong><em>With a wee bit more formatting</em></strong></p>

<pre><code>df.set_index(['Person', 'Type']).Days.rename('&gt;= 3').ge(3)  \
  .groupby(level=[0, 1]).value_counts(True).unstack(fill_value=0)
</code></pre>

<p><a href="http://i.stack.imgur.com/i4sSG.png" rel="nofollow"><img src="http://i.stack.imgur.com/i4sSG.png" alt="enter image description here"></a></p>

python python-2.7 pandas