我正在迭代许多csv文件,其中1000到3000行检查每一行是否在140个字符的文本中继承了70000个关键字之一。我现在的问题是,我的代码运行得非常慢。我猜是因为有很多迭代。我是一个相对较新的程序员,不知道加速的最佳方法是什么。检查整个文件花了2个小时,还有很多我需要经历的。我现在的逻辑是:将csv导入为列表列表 - >对于列表中的每个列表,取第一个元素并搜索每个70000关键字是否被提及。
目前我的代码如下所示:
import re
import csv
def findname(lst_names,text):
for name in lst_names:
name_match = re.search(r'@'+str(name), text)
if name_match:
return name
lst_users = importusr_lst('users.csv') #defined function to import 700000 keywords
lst_successes = []
with open(file, 'rb') as csvfile:
filereader = csv.reader(csvfile, delimiter = ',')
content = []
for row in filereader:
content.append(row)
if len(content)>1:
for row in content:
hit = []
mentioned = findname(lst_names, row[0]) #row[0] is the text of 140 characters
if mentioned:
hit = row[1:7]
hit.append(mentioned)
lst_successes.append(hit)
return lst_successes
输入是包含此推文数据的推文列表。一行包含以下信息:
Tweet_text,Tweet_id,Tweet_date,Tweet_fav_count,Tweet_retweet_count,Replied_to user_id,Replied_to_stats_id,author_name,user_name
一个例子可能是:
"This is an awesome tweet @username.",576819939086041089,2015-03-14,18:59:24,0,2,4,jjwniemzok,jjwniemzok
关键字是Twitter中的用户名。谢谢你的帮助!
答案 0 :(得分:3)
首先,将lst_names
变为set,如果已经是{{3}},则需要进行预期的name in lst_names
次检查。然后对于每条推文,不是遍历所有名称并专门查找它们,而是查找任何名称:
names_set = set(lst_names)
# ...
name_match = re.search('@(\w+)\b', text)
if name_match:
name = name_match.group(1)
if name in names_set:
return name
(我假设这里的推特名称为\w+
。)
您可能还想提前编译正则表达式;见Tomalak的回答。
答案 1 :(得分:0)
我将制作一些测试推文数据。我在这里假设推文用户名前面紧跟着' @'推文文本中的符号,例如推文可能会读到'something cool @someone1 @someone2 something else cool @someone3'
。我将制作一些测试数据:
import numpy as np
import string
tweet_templates = [['askdjaklsd {0} akdjsakd {1}', 2], ['alskalkals {0}',1], ['{0} kadksjdss {1} {2}',3] ]
some_names = array( [ '@'+''.join( random.sample( string.letters , 5) ) for i in xrange( 70000 )] ) # large number of poss user names
template_i = np.random.randint( 0,3,30000 ) # 30000 tweets
tweets = [ tweet_templates[t][0].format( *some_names[ np.random.randint( 0 ,len(some_names ), tweet_templates[t][1] )] ) for t in template_i]
在你从csv加载文本的情况下我会使用numpy.loadtxt(个人选择):
#tweet_data = np.loadtxt( 'tweet_file.csv', delimiter=',', dtype=str)
# there are options to ignore headers etc.
#tweets = tweet_data[:,0] # first column
现在,我们有数据,隔离每行中的名称:
tweets_split = map( lambda x : x.split(), tweets )
tweet_names = map( lambda y: filter( lambda x : x[0] == '@', y ), tweets_split )
print tweet_names
#[['@msUnu', '@KvUqA'], ['@GknKr'], ['@Hxbfe'], ...
tweet_names = map( lambda y: map( lambda x : x.split('@')[-1], y ), tweet_names )
print tweet_names
#[['msUnu', 'KvUqA'], ['GknKr'], ['Hxbfe'],
然后列出每个元素都是子列表[ name, tweet_row]
的列表,其中name
是Twitter用户的名称,tweet_row
是在其中找到名称的行tweets
数据。
tweet_names_info = [ map( lambda n : [ n,ind ] , tweet_names[ind] ) for ind in xrange( len(tweets) ) ]
tweet_names_info = [ sl for sublist in tweet_names_info for sl in sublist]
根据名称对此列表进行分组:
from itertools import groupby
tweet_names_grouped = [ [k, list( np.array(list(g))[:,1].astype(int))] for k,g in groupby( tweet_names_info, lambda x: x[0] ) ]
tweet_names_rows = dict( tweet_names_grouped )
现在你有一个字典,其中键是twitter用户名,值是相应推文的行号。将此字典对象与您的用户列表进行比较应该很容易:
tweeters = tweet_names_rows.keys()
#lst_users = importusr_lst('users.csv')
#^ your function, I assume it loads a 1D array, I will make up some user names
lst_users = array( [ ''.join( random.sample( string.letters , 5) ) for i in xrange( 130000 )] )
users_who_tweeted = list( set(tweeters).intersection(set(lst_users)) )
if users_who_tweeted:
for u in users_who_tweeted:
u_text = [ tweets[i] for i in tweet_names_rows[u] ]
print 'USER %s WAS ON TWITTER:'% u
print '\n'.join( u_text), '\n'
#USER ZeHLA WAS ON TWITTER:
#alskalkals @ZeHLA
#USER jaZuG WAS ON TWITTER:
#@mjLTG kadksjdss @jaZuG @DJNjv
#USER UVzSs WAS ON TWITTER:
#@tnGrH kadksjdss @DOBij @UVzSs
#...
#...