Skip to main content
 首页 » 编程设计

python之Pandas 的异常计数

2025年05月04日17jillzhang

我有一个数据框 df 看起来像 -

attribute_ids                     attributes_names 
['adr4r','5ty6gh']                ['abc','xyz']  
['fg67y','ty67g','ght43','adr4r'] ['pqr','abc','xyz','abc']  

我想统计每个唯一的atrribute_id存在的次数,并按降序显示。但在结果中我也想显示其相应的 attribute_names。请注意,属性名称不是唯一的,attribute_ids 是。例如:adr4r 和ty67g bith 具有相同的名称“abc”。输出应该看起来像 -

attribute_ids       atribute_names     count 
adr4r               abc                2 
ty67g               abc                1 
5ty6gh              xyz                1 
ght43               xyz                1 
fg67y               pqr                1 

目前只能根据attribute_ids进行统计(不能显示对应的attribute_names):

count=df.attribute_ids.apply(pd.Series).stack().value_counts() 

请您参考如下方法:

选项 1
pir1

  • 将列与 np.concatenate 连接在一起
  • 使用np.unique识别唯一值,以及...
    • 使用参数 return_counts=True 计算这些值的出现次数
    • 首次出现位置的索引,因此我可以使用参数 return_index=True
    • 对 names 进行切片

ids = np.concatenate(df.attribute_ids) 
names = np.concatenate(df.attribute_names) 
 
u, idx, cts = np.unique(ids, return_index=True, return_counts=True) 
 
pd.DataFrame(dict( 
    attribute_ids=u, 
    attribute_names=names[idx], 
    count=cts 
)) 
 
  attribute_ids attribute_names  count 
0        5ty6gh             xyz      1 
1         adr4r             abc      2 
2         fg67y             pqr      1 
3         ght43             xyz      1 
4         ty67g             abc      1 

选项 2
pir2

  • 与选项 1 一样,我们将列展平
  • 然后在 attribute_ids 列上使用分组,然后是 agg

from cytools import concat 
 
d1 = pd.DataFrame(dict( 
    attribute_ids=list(concat(df.attribute_ids.values.tolist())), 
    attribute_names=list(concat(df.attribute_names.values.tolist())) 
)) 
 
d1.groupby('attribute_ids').attribute_names.agg(['first', 'count']) \ 
    .reset_index().rename(columns=dict(first='attribute_names')) 
 
  attribute_ids attribute_names  count 
0        5ty6gh             xyz      1 
1         adr4r             abc      2 
2         fg67y             pqr      1 
3         ght43             xyz      1 
4         ty67g             abc      1 

选项 3
pir3
在元组上使用 pd.factorize。使用 concat 来展平数组。

from cytoolz import concat 
 
i = concat(df.attribute_ids.values.tolist()) 
n = concat(df.attribute_names.values.tolist()) 
f, u = pd.Series(list(zip(i, n))).factorize() 
return pd.DataFrame( 
    u.tolist(), 
    columns=['attribute_ids', 'attribute_names'] 
).assign(count=np.bincount(f)) 
 
  attribute_ids attribute_names  count 
0         adr4r             abc      2 
1        5ty6gh             xyz      1 
2         fg67y             pqr      1 
3         ty67g             abc      1 
4         ght43             xyz      1 

时间

results.div(results.min(1), 0).round(2).pipe(lambda d: d.assign(Best=d.idxmin(1))) 
 
        pir1  pir2  pir3  galt  Best 
N                                    
1       1.00  4.37  1.75  4.07  pir1 
3       1.00  3.84  1.54  4.58  pir1 
10      1.48  2.46  1.00  2.38  pir3 
30      2.42  3.09  1.00  2.86  pir3 
100     5.56  2.42  1.00  2.58  pir3 
300    14.86  2.52  1.00  2.42  pir3 
1000   24.63  1.37  1.00  1.43  pir3 
3000   38.14  1.47  1.00  1.35  pir3 
10000  41.85  1.36  1.00  1.14  pir3 

fig, (a1, a2) = plt.subplots(1, 2, figsize=(6, 6)) 
results.plot(loglog=True, lw=3, ax=a1) 
results.div(results.min(1), 0).round(2).plot.barh(logx=True, ax=a2) 
fig.tight_layout() 

代码

def galt(df): 
    cols = df.columns.tolist() 
    return pd.DataFrame({ 
        c: [v for L in df[c] for v in L] for c in cols 
    }).groupby(cols).size().reset_index(name='count') 
 
def pir1(df): 
    ids = np.concatenate(df.attribute_ids) 
    names = np.concatenate(df.attribute_names) 
 
    u, idx, cts = np.unique(ids, return_index=True, return_counts=True) 
 
    return pd.DataFrame(dict( 
        attribute_ids=u, 
        attribute_names=names[idx], 
        count=cts 
    )) 
 
def pir2(df): 
    d1 = pd.DataFrame(dict( 
        attribute_ids=list(concat(df.attribute_ids.values.tolist())), 
        attribute_names=list(concat(df.attribute_names.values.tolist())) 
    )) 
 
    return d1.groupby('attribute_ids').attribute_names.agg(['first', 'count']) \ 
        .reset_index().rename(columns=dict(first='attribute_names')) 
 
def pir3(df): 
    i = concat(df.attribute_ids.values.tolist()) 
    n = concat(df.attribute_names.values.tolist()) 
    f, u = pd.Series(list(zip(i, n))).factorize() 
    return pd.DataFrame( 
        u.tolist(), 
        columns=['attribute_ids', 'attribute_names'] 
    ).assign(count=np.bincount(f)) 
 
 
results = pd.DataFrame( 
    index=pd.Index([1, 3, 10, 30, 100, 300, 1000, 3000, 10000], name='N'), 
    columns='pir1 pir2 pir3 galt'.split(), 
    dtype=float 
) 
 
for i in results.index: 
    d = pd.concat([df] * i, ignore_index=True) 
    for j in results.columns: 
        stmt = '{}(d)'.format(j) 
        setp = 'from __main__ import d, {}'.format(j) 
        results.set_value(i, j, timeit(stmt, setp, number=10)) 

设置

df = pd.DataFrame(dict( 
    attribute_ids=[['adr4r', '5ty6gh'], ['fg67y', 'ty67g', 'ght43', 'adr4r']], 
    attribute_names=[['abc', 'xyz'], ['pqr', 'abc', 'xyz', 'abc']] 
))