如果组中的任何一行包含某个值,则创建一个新列并分配值

时间:2019-05-02 17:42:01

标签: python pandas pandas-groupby

我正尝试根据以下方式为组中每个组的新列分配值:如果组中的任何行包含特定值,则该组的新列值应为某个值。

到目前为止,我已经尝试使用np.where和pandas dataframe any()并将其应用于分组依据。这适用于非常小的数据集。我的原始数据集包含约180万条记录,而我尝试的方法太慢了,它从未在原始数据集上运行完毕。所以想知道是否有一种有效的方法来实现这一目标。

例如,如果我有一个包含A,B和C列的数据框

     A      B   C
0   alpha   m   t
1   beta    n   r
2   cosine  q   f
3   alpha   m   t
4   beta    m   t
5   alpha   n   r
6   cosine  q   f

对于B和C的组,创建一个新列'D',其值基于'A'。在一个组中,如果A列的任何行中有beta,则该组的“ D”列(D的所有行)应为beta。如果组中的所有行均不包含beta,则下一个层次结构为余弦,即,如果该组中列A的任何行均具有余弦,则该组中列D的所有行均应为余弦。

到目前为止我尝试过的方法:

def test(dft):
    dft['D']=np.where(dft[dft['A']=='beta'].any(),'beta',np.where(dft[dft['A']=='cosine'].any(),'cosine',np.where(dft[dft['A']=='alpha'].any(),'alpha',dft['A'])))
    return dft['D']
dft2=dft.groupby(['B','C']).apply(test)
dft2=dft2.reset_index()

我得到的结果是:

    B   C   level_2    D
0   m   t   0         beta
1   m   t   3         beta
2   m   t   4         beta
3   n   r   1         beta
4   n   r   5         beta
5   q   f   2         cosine
6   q   f   6         cosine

预期结果应如下:

     A      B   C          D
0   alpha   m   t        beta
1   beta    n   r        beta
2   cosine  q   f        cosine
3   alpha   m   t        beta
4   beta    m   t        beta
5   alpha   n   r        beta
6   cosine  q   f        cosine

2 个答案:

答案 0 :(得分:4)

IIUC使用Categorical转换列A,然后进行groupby transform

df.A=pd.Categorical(df.A,categories=['alpha','cosine','beta'],ordered=True)
df.groupby(['B','C']).A.transform('max')
Out[1200]: 
0      beta
1      beta
2    cosine
3      beta
4      beta
5      beta
6    cosine
Name: A, dtype: object
df['D']=df.groupby(['B','C']).A.transform('max')

答案 1 :(得分:1)

脾气暴躁

我想使用Numpy。这主要是出于我的利益,但我想如果有其他人感兴趣,我会与您分享。

# This will assign a factorized version of the combination of `df.B` and `df.C`
# `i` will be the integer factor values
# `u` will have the unique tuples that are the combinations themselves
i, u = pd.factorize([*zip(df.B, df.C)])

# `order` acts as both the labels and the priority ordering
order = np.array(['beta', 'cosine', 'alpha'])
# use Numpy broadcasting to see get a boolean version of one-hot encoded values
conds = df.A.values == order[:, None]

# create a new array that has the same number of rows as the number of unique
# combinations of `'B'` and `'C'`... or `len(u)` and the number of columns equal
# to the number of items in `order`
out = np.zeros((len(u), len(order)), bool)

j = np.tile(i, len(u))
k = np.arange(len(u)).repeat(len(i))

# Surgically place cumulative or evaluations into the `out` array
np.logical_or.at(out, (k, j), conds.ravel())

df.assign(D=np.select(out, order)[i])

        A  B  C       D
0   alpha  m  t    beta
1    beta  n  r    beta
2  cosine  q  f  cosine
3   alpha  m  t    beta
4    beta  m  t    beta
5   alpha  n  r    beta
6  cosine  q  f  cosine