使用python

时间:2015-05-06 07:24:44

标签: python regex list csv

我正在迭代许多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中的用户名。谢谢你的帮助!

2 个答案:

答案 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 
#...
#...