<p>对于groupby中groupby变量的模式未知的groupby来说,<code>groupby.ngroup</code>似乎是最好的。但是如果groupby变量都是分类的,例如,取值<code>0,1,2,3....</code>,那么我们可以从<code>@saurjog</code>给出的解决方案中得到启发。你知道吗</p>
<p>为了生成组ID,我们可以构建一个数值表达式来计算groupby变量的特殊和。考虑以下功能</p>
<pre class="lang-py prettyprint-override"><code>def gen_groupby_numexpr(cols, numcats):
txt = [cols[0]]
k = numcats[0]
for c,k_ in zip(cols[1:], numcats[1:]):
txt.append('{}*{}'.format(k, c))
k = k*k_
return ' + '.join(txt)
def ngroup_cat(df, by, numcats):
'''
by : list
the categorical (0,1,2,3...) groupby column names
numcats : list
the number of unique values for each column in "by"
'''
expr = gen_groupby_numexpr(by, numcats)
return df.eval(expr)
</code></pre>
<p>函数<code>gen_groupby_numexpr</code>生成数值表达式,<code>ngroup_cat</code>为<code>by</code>中具有唯一值计数<code>numcats</code>的groupby变量生成组id。因此,考虑以下与我们的用例匹配的数据集。它包含3个分类变量,我们将使用它们来形成groupby,其中两个变量在<code>{0,1}</code>中取值,一个变量在<code>{0,1,2}</code>中取值。你知道吗</p>
<pre><code>df2 = pd.DataFrame(np.hstack([np.random.randint(0, 2, (100, 2)),
np.random.randint(0, 3, (100, 1)),
np.random.randint(0, 20, (100, 1))]),
columns=['male', 'mar', 'edu', 'wage'])
</code></pre>
<p>如果我们生成数值表达式,我们得到:</p>
<pre><code>'male + 2*mar + 4*edu'
</code></pre>
<p>总之,我们可以用</p>
<pre><code>df2['group_id'] = ngroup_cat(df2, ['male', 'mar', 'edu'], [2, 2, 3])
</code></pre>
<p>从中我们得到<code>2*2*3=12</code>唯一组ID:</p>
<pre><code>df2[['male', 'mar', 'edu', 'group_id']].drop_duplicates().sort_values(['group_id'])
male mar edu group_id
1 0 0 0 0
13 1 0 0 1
8 0 1 0 2
10 1 1 0 3
4 0 0 1 4
12 1 0 1 5
2 0 1 1 6
6 1 1 1 7
7 0 0 2 8
5 1 0 2 9
44 0 1 2 10
0 1 1 2 11
</code></pre>
<p>当我将上述解决方案与<code>groupby.ngroup</code>作基准时,它在<code>N=10,000,000</code>的数据集上运行速度快了近3倍,并且使用的额外内存明显减少。你知道吗</p>
<p>现在我们可以通过方法来估计这些组,然后将它们映射回整个数据帧来进行转换工作。我计算了一些关于使用<code>transform</code>还是<code>groupby</code>的基准测试,结果不一,那么<code>map</code>更快,占用的内存更少。如果你计算的是多变量组的平均数,那么我认为后者更有效。此外,后者也可以在<code>dask</code>中完成,其中<code>transform</code>还不受支持。你知道吗</p>