【问题标题】:Faster way to write the following code编写以下代码的更快方法
【发布时间】:2015-06-23 12:23:07
【问题描述】:

我正在解析数据,并将其写入 csv 文件,然后再将它们导入数据库。在解析过程中,我保留了作者姓名列表(往往会重复很多)。我正在生成两个 csv 文件,其中一个有两列:作者 ID(我通过计数器手动生成)和作者姓名。第二个 csv 文件也有两列,author_id 和 publication_id。我可以发布有很多作者,一个作者可以有很多出版物。

现在这是我的问题。我写的代码需要很长时间才能解析。我正在处理超过 200 万条记录,并且以每小时大约 6,000 条记录的速度进行。我认为最大的问题是在我写他之前我必须搜索作者是否以前已经找到过。

这就是我的做法:

#authors_list is a list that has the authors of the current publication I'm parsing. 
#all_authors is a list that has all the authors found so far.

j=0 #keeps track of authors index in all_authors list
flag=0

for a in authors_list:
    #check to see if authors already exists
    allauthors = np.array(all_authors)
    if a in allauthors[:,1]:
         flag = 1
         k = 0 #k gives me current index of found author
         while flag and k<len(allauthors):
             if allauthors[k][1]==a:
                 index = k
                 flag = 0
             else:
                 k+=1
         print "Author exists: ", allauthors[k][1]
         aup.writerow([k,pid])
    else:
         all_authors.append([j,a]) 
         au.writerow([j,a])
         aup.writerow([j,pid]) 

我觉得必须有一种更快的方法来完成这项检查。也许使用熊猫?或者以更好的方式numpy?我对两者都很陌生。

【问题讨论】:

  • 作为第一步,您可以加载第一个 csv,然后删除重复的作者并将其写为干净的 csv,这听起来像是一个混乱的多对多关系,听起来出版物是独特之处,因此您可能希望为每位作者重复发表文章
  • 您正在处理本质上是“外键”的内容,并且处理的记录数量惊人:它已经超出了您应该将其放入 SQL 数据库而不是 CSV 文件的地步。做起来并不难,即使是 Python 内置的 sqlite 也能很好地为你服务。
  • @jsbueno 我最初将它直接插入到 sql 数据库中。但这需要更长的时间。然后有人告诉我,将它整齐地解析成一个 csv 文件并在 sqlite3 上使用 .import 之类的命令将其直接导入我的表中可能会更快。这就是我在这里所做的。
  • 好的-我想出了一些使它需要很长时间的原因-TL; DR:numpy不是您所需要的。我会给出一个可能有用的答案。
  • 即使您无法实施/不喜欢我的回答,我建议您从问题的标题中删除“numpy”。它不是适合这里工作的工具 - 您正在处理文本数据

标签: python python-2.7 csv numpy pandas


【解决方案1】:

这里的主要问题是,对于每篇文章中的每个作者,您都在对迄今为止的所有作者进行线性搜索。

仅此一项就具有 O(N²) 复杂性 - 但更糟糕的是,您正在使用 allauthors = np.array(all_authors) 行为每个作者姓名重新创建数据结构,如果您获得“6000/小时”,您实际上是幸运的(它更多第一个小时可能有 6000 :-))

有时,简单更好。其他时候,简单得多,好多了。 仍然可以直接将内容写入 SQL,避免传递您在此处看到的 CSV 文件,但是您的问题中的上下文太少,无法编写这样的示例。

#authors_list is a list that has the authors of the current publication I'm parsing. 
#all_authors is a list that has all the authors found so far.

last_author_id = 0 #keeps track of authors index in all_authors list
all_authors = {}
for author in authors_list:
    if author in all_authors:
        author_index = all_authors[author]
        print "Author exists: ", author_index
    else:
        last_author_id += 1
        all_authors[author] = author_index = last_author_id
        au.writerow([author_index, author])
    aup.writerow([author_index, pid])

注意主要变化:

  • 根本不使用 Numpy。 Numpy 有很好的数值处理特性——线性文本搜索在使用 numpy 时没有任何改进
  • 不在每个作者姓名上重新创建数据结构
  • 使用 Python 字典(或集合)来存储作者姓名,而不是序列,无论 Numpy 与否,从 O(N) 时间的线性搜索变为 O(1) 时间的固定哈希搜索

这里还有一个可能的问题:我天真地将所有作者和创建的 ID 保存在字典中,在内存中。这对于 ~GB RAM 类服务器/桌面和 200 万条 1 行文本记录应该没问题 - 但如果这些数字发生变化,将所有内容直接写入 SQL 服务器将解决这个问题(任何 DBMS 都应该保持低搜索延迟(如果您有作者姓名的索引),并且以透明的方式正确缓存这样的简单查询)

【讨论】:

  • 你太棒了!我按照你的方法试过了,它快了一百万倍! :))))) 非常感谢你:)))) 旁注:代码中有一个小错误: author_index = all_authors(author) 应该是 author_index = all_authors[author]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-15
  • 1970-01-01
  • 2011-11-19
  • 1970-01-01
  • 1970-01-01
  • 2015-04-21
  • 2013-01-14
相关资源
最近更新 更多