【问题标题】:Line by line check for large amount of keywords with python使用python逐行检查大量关键字
【发布时间】:2015-07-16 04:48:11
【问题描述】:

我正在遍历许多包含 1000 到 3000 行的 csv 文件,检查每一行是否在 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

一个例子可能是:

“这是一条很棒的推文@username。”,576819939086041089,2015-03-14,18:59:24,0,2,4,jjwniemzok,jjwniemzok

关键字是 Twitter 中的用户名。感谢您的帮助!

【问题讨论】:

  • 这看起来像是一个全文搜索引擎的任务,而不是一个嵌套循环。您能提供示例输入和示例关键字吗?
  • 输入是包含有关此推文数据的推文列表。一行包含以下信息:[Tweet_text, Tweet_id, Tweet_date, Tweet_fav_count, Tweet_retweet_count, Replied to user(id), Replied to stats(id), author_name, user_name]。一个例子可能是:[“这是一条很棒的推文@Tomalak。” ,576819939086041089, 2015-03-14 18:59:24,0,2,4,jjwniemzok,jjwniemzok] 关键字是 Twitter 中的用户名。这有帮助吗?我需要该行的多个单元格。
  • 当您说“为列表中的每个列表获取第一个元素并搜索...”时,这是否意味着您只想针对 csv 文件第一列的每个条目搜索关键字.. 并且这些条目是 140 个字符串?
  • 那么每个 Tweet_text 的长度是 140 个字符吗?并且您正在尝试将用户名与推文匹配?
  • 是的。第一列是 140 个字符的推文。我想知道该推文中是否提到了众多用户中的一个。

标签: python regex list csv


【解决方案1】:

首先,将lst_names 转换为set,如果它还不是一个@,以便有预期的恒定时间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

(我假设 Twitter 名称是\w+)。

您可能还想提前编译正则表达式;请参阅 Tomalak 的回答。

【讨论】:

  • 工作得非常好。我必须做的唯一改变是改进具有多个名称的推文的逻辑:内联name_match = re.findall('@(\w+)', text) if name_match: for name in name_match: if name in lst_names: return name
【解决方案2】:

我会做一些测试推文数据。我在这里假设推文用户名前面紧跟推文文本中的“@”符号,例如一条推文可能是'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 是推特用户的名称,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 
#...
#...

【讨论】:

  • 好主意,您肯定想尝试以某种方式对数据进行排序,这样您就不必进行太多迭代,并且基于用户进行排序是有意义的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-01
  • 1970-01-01
  • 2012-11-01
  • 1970-01-01
  • 2015-01-13
  • 1970-01-01
  • 2019-04-19
相关资源
最近更新 更多