正如标题所示,我正在处理数百万条推文,其中一个数据点是两个不同的列表中是否存在任何单词(每个列表包含大约500个单词)。这可以理解的很慢,但我会定期这样做,所以我想加快速度。关于我怎么可能的任何想法?
lista = ['word1', 'word2', ... 'word500']
listb = ['word1', 'word2', ..., 'word500']
def token_list_count(df):
for i, t in df.iterrows():
list_a = 0
list_b = 0
for tok in t['tokens']:
if tok in lista: list_a += 1
elif tok in listb: list_b += 1
df.loc[i, 'token_count'] = int(len(t['tokens']))
df.loc[i, 'lista_count'] = int(list_a)
df.loc[i, 'listb_count'] = int(list_b)
if i % 25000 == 0: print('25k more processed...')
return df
编辑:
输入/之前:
输出/之后:
答案 0 :(得分:3)
为了避免迭代数据帧,您可以尝试以下函数。第一行将tokens
列扩展为数据框,其中每个第一个标记将位于第一列中,第二个标记位于第二列中,依此类推。列总数将等于token_count
中的最大df
。从那里可以很容易地使用lista
方法计算listb
和.isin
计数,并对每行进行求和。
从完整tok
制作的df
数据框可能占用大量内存,在这种情况下,可能需要将df
拆分为多个块并单独处理它们。
def token_list_count(df):
tok = df['tokens'].apply(pd.Series)
df['token_count'] = tok.notnull().sum(axis=1)
df['lista_count'] = tok.isin(lista).sum(axis=1)
df['listb_count'] = tok.isin(listb).sum(axis=1)
return df
您的原始功能也有一些改进空间:
df
迭代完整iterrows()
,因为您只需要一列来进行计算。因此,您可以使用df.tokens.iteritems()
代替。这将节省您在每次迭代时创建一个新的Series对象。at
索引器而不是loc
。请参阅pandas docs中的Fast scalar value getting and setting。我不知道这有多大帮助,但可能有些=)。
def token_list_count(df):
for i, tok in df.tokens.iteritems():
list_a = sum((t in lista) for t in tok)
list_b = sum((t in listb) for t in tok)
df.at[i, 'token_count'] = int(len(tok))
df.at[i, 'lista_count'] = int(list_a)
df.at[i, 'listb_count'] = int(list_b)
if i % 25000 == 0: print('25k more processed...')
return df
你也可以在没有for循环但是使用apply
:
df['token_count'] = df.tokens.apply(len)
df['lista_count'] = df.tokens.apply(lambda tok: sum((t in lista) for t in tok))
df['listb_count'] = df.tokens.apply(lambda tok: sum((t in listb) for t in tok))
答案 1 :(得分:2)
使用下面的代码可以给你一些小时间优势。请注意,如果您按原样使用此代码,则listb中的出现次数不正确。
你不会从下面的代码中获得更多的加速,因为创建这些集将消除几乎所有来自更快查找的时间优势,但是如果你重用seta你会节省时间,setb也可以用于另一个查找循环如果进一步编码。
也许您可以安排,直接将您的列表作为集合,这样您可以节省创建集合的时间吗?
lista = ['word1a', 'word2a', 'word500a']
listb = ['word1b', 'word2a', 'word500b']
seta = set(lista)
setb = set(listb)
def token_list_count(df):
dfIterrows = df.iterrows() # TRY THIS !!!
for i, t in dfIterrows: # TRY THIS !!!
list_a = 0
list_b = 0
tTokens = t['tokens'] # TRY THIS !!!
for tok in tTokens: # TRY THIS !!!
if tok in seta: list_a += 1
elif tok in setb: list_b += 1
# why not "if tok in setb: list_b +=1" ???
df.loc[i, 'token_count'] = int(len(t['tokens']))
df.loc[i, 'lista_count'] = int(list_a)
df.loc[i, 'listb_count'] = int(list_b)
if i % 25000 == 0: print('25k more processed...')
return df
如果速度对你很重要,我建议你只使用Python作为框架,使用适当的可执行文件或数据库查询进行查找,以及用于seta和setb中的查找的多处理。< / p>
另一个选择是考虑评论中建议的root
:&#34;&#34;&#34;这里最大的问题是你在一个DataFrame上进行迭代,这几乎应该是永远避免。使用矢量化方法将产生最佳性能改进。 &#34;&#34;&#34;