Pandas - 创建具有元素计数和频率的数据帧

4
从下面的数据框 df 开始:
df = pd.DataFrame({'node':[1,2,3,3,3,5,5],'lang':['it','en','ar','ar','es','uz','es']})

我正在尝试构建这个结构:
    node     langs   lfreq
0      1      [it]     [1]
1      2      [en]     [1]
2      3  [ar, es]  [2, 1]
3      5  [uz, es]  [1, 1]

基本上是通过列表将每个节点中的lang元素和频率分组成一行。目前我做的事情:

# Getting the unique langs / node
a = df.groupby('node')['lang'].unique().reset_index(name='langs')

# Getting the frequency of lang / node
b = df.groupby('node')['lang'].value_counts().reset_index(name='lfreq')
c = b.groupby('node')['lfreq'].unique().reset_index(name='lfreq')

然后根据node进行合并:

d = pd.merge(a,c,on='node')

经过这些操作,我得到的结果是:

    node     langs   lfreq
0      1      [it]     [1]
1      2      [en]     [1]
2      3  [ar, es]  [2, 1]
3      5  [uz, es]     [1]

您可能已经注意到,最后一行只有一个 [1] 出现频率的两个 [uz,es],而不是预期的 [1,1] 列表。是否有一种更简洁的方法进行分析,以获得所需的输出?

3个回答

3
我会使用agg函数和tolist()。
df = pd.DataFrame({'node':[1,2,3,3,3,5,5],'lang':['it','en','ar','ar','es','uz','es']})
# Getting the unique langs / node
a = df.groupby('node')['lang'].unique().reset_index(name='langs')

# Getting the frequency of lang / node
b = df.groupby('node')['lang'].value_counts().reset_index(name='lfreq')

替换

c = b.groupby('node')['lfreq'].unique().reset_index(name='lfreq')

使用

c = b.groupby('node').agg({'lfreq': lambda x: x.tolist()}).reset_index()

d = pd.merge(a,c,on='node')

并且,你就可以得到以下结果:
   node     langs   lfreq
0     1      [it]     [1]
1     2      [en]     [1]
2     3  [ar, es]  [2, 1]
3     5  [uz, es]  [1, 1]

2
你可以使用带参数return_counts=Trueapplynp.unique函数:
df = pd.DataFrame({'node':[1,2,3,3,3,5,5],'lang':['it','en','ar','ar','es','uz','es']})
print df
  lang  node
0   it     1
1   en     2
2   ar     3
3   ar     3
4   es     3
5   uz     5
6   es     5

a = df.groupby('node')['lang'].apply(lambda x: np.unique(x, return_counts=True))
                              .reset_index(name='tup')

#split tuples
a[['langs','lfreq']] = a['tup'].apply(pd.Series)
#filter columns
print a[['node','langs','lfreq']]
   node     langs   lfreq
0     1      [it]     [1]
1     2      [en]     [1]
2     3  [ar, es]  [2, 1]
3     5  [es, uz]  [1, 1]

谢谢。相比其他答案,速度如何?我知道对于大型数据框来说,apply的速度较慢(我有近4000万行)。 - Fabio Lamanna

2

因为你在评论中提到了对于拥有4000万行数据而言速度的重要性,所以我建议你看一下以下内容。

df.groupby(['node','lang'])['lang'].count()

node  lang
1     it      1
2     en      1
3     ar      2
      es      1
5     es      1
      uz      1

一般来说,使用更平坦的结构(Python之禅)会更好,特别是你希望你的pandas/numpy列是简单类型(整数和浮点数),而不是对象。
由于pandas方法例如groupby,上述结构应该比存储为列表更容易实现操作,并且几乎可以保证更快,可能快得多。我假设你想要使用这种结构进行进一步处理,但即使不是这样,以这种方式制表数据也会更快。

实际上,在一个有 500,000 行的数据框中,@JohnE 的解决方案比 dmb(64 秒)和 jezrael(136 秒)的解决方案快得多得多(1.5 秒)。 - Fabio Lamanna

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