计算列表内主题标签的有效方法 (pandas)
Performatic way to count hashtags inside list (pandas)
我有一个包含 ~7.000.000 行和很多列的数据框。
每一行都是一条推文,我有一列 文本 包含推文的内容。
我专门为文本中的主题标签创建了一个新列:
df['hashtags'] = df.Tweets.str.findall(r'(?:(?<=\s)|(?<=^))#.*?(?=\s|$)')
所以我有一个名为 hashtags 的列,每一行都包含一个列表结构:['#b747', '#test']
.
我想计算每个主题标签的数量,但我有很多行。最有效的方法是什么?
你可以把所有的列表归为一个大列表然后使用collections.Counter:
import pandas as pd
from collections import Counter
df = pd.DataFrame()
df['hashtags'] = [['#b747', '#test'], ['#b747', '#test']]
Counter(sum(df['hashtags'].values, []))
这里有一些不同的方法,以及时间,按速度排序(最快的在前):
# setup
n = 10_000
df = pd.DataFrame({
'hashtags': np.random.randint(0, int(np.sqrt(n)), (n, 10)).astype(str).tolist(),
})
# 1. using itertools.chain to build an iterator on the elements of the lists
from itertools import chain
%timeit Counter(chain(*df.hashtags))
# 7.35 ms ± 58.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# 2. as per @Psidom comment
%timeit df.hashtags.explode().value_counts()
# 8.06 ms ± 19.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# 3. using Counter constructor, but specifying an iterator, not a list
%timeit Counter(h for hl in df.hashtags for h in hl)
# 10.6 ms ± 13.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# 4. iterating explicitly and using Counter().update()
def count5(s):
c = Counter()
for hl in s:
c.update(hl)
return c
%timeit count5(df.hashtags)
# 12.4 ms ± 66.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# 5. using itertools.reduce on Counter().update()
%timeit reduce(lambda x,y: x.update(y) or x, df.hashtags, Counter())
# 13.7 ms ± 10.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# 6. as per @EzerK
%timeit Counter(sum(df['hashtags'].values, []))
# 2.58 s ± 1.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
结论:最快的是#1(使用Counter(chain(*df.hashtags))
),但更直观自然的#2(来自@Psidom 评论)几乎一样快。我可能会同意这一点。 #6(@EzerK 方法)对于大型 df
非常慢,因为我们在将其作为参数传递给 Counter()
.
之前构建一个新的(长)列表
我有一个包含 ~7.000.000 行和很多列的数据框。
每一行都是一条推文,我有一列 文本 包含推文的内容。
我专门为文本中的主题标签创建了一个新列:
df['hashtags'] = df.Tweets.str.findall(r'(?:(?<=\s)|(?<=^))#.*?(?=\s|$)')
所以我有一个名为 hashtags 的列,每一行都包含一个列表结构:['#b747', '#test']
.
我想计算每个主题标签的数量,但我有很多行。最有效的方法是什么?
你可以把所有的列表归为一个大列表然后使用collections.Counter:
import pandas as pd
from collections import Counter
df = pd.DataFrame()
df['hashtags'] = [['#b747', '#test'], ['#b747', '#test']]
Counter(sum(df['hashtags'].values, []))
这里有一些不同的方法,以及时间,按速度排序(最快的在前):
# setup
n = 10_000
df = pd.DataFrame({
'hashtags': np.random.randint(0, int(np.sqrt(n)), (n, 10)).astype(str).tolist(),
})
# 1. using itertools.chain to build an iterator on the elements of the lists
from itertools import chain
%timeit Counter(chain(*df.hashtags))
# 7.35 ms ± 58.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# 2. as per @Psidom comment
%timeit df.hashtags.explode().value_counts()
# 8.06 ms ± 19.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# 3. using Counter constructor, but specifying an iterator, not a list
%timeit Counter(h for hl in df.hashtags for h in hl)
# 10.6 ms ± 13.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# 4. iterating explicitly and using Counter().update()
def count5(s):
c = Counter()
for hl in s:
c.update(hl)
return c
%timeit count5(df.hashtags)
# 12.4 ms ± 66.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# 5. using itertools.reduce on Counter().update()
%timeit reduce(lambda x,y: x.update(y) or x, df.hashtags, Counter())
# 13.7 ms ± 10.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# 6. as per @EzerK
%timeit Counter(sum(df['hashtags'].values, []))
# 2.58 s ± 1.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
结论:最快的是#1(使用Counter(chain(*df.hashtags))
),但更直观自然的#2(来自@Psidom 评论)几乎一样快。我可能会同意这一点。 #6(@EzerK 方法)对于大型 df
非常慢,因为我们在将其作为参数传递给 Counter()
.