【问题标题】:find changes with Multiprocess between 2 huge lists在 2 个巨大的列表之间使用 Multiprocess 查找更改
【发布时间】:2021-09-27 05:05:03
【问题描述】:

我正在尝试比较 2 个巨大的列表并找出哪些行不在第二个列表中。

例如:

列表 1: 一种 b C d

列表2: 一种 G H d

结果: b c

b c 在列表 1 中,但不在列表 2 中。

list1 的大小为 60GB 行。 list2 的大小为 76GB 行。

当尝试加载列表时,进程因内存不足而被终止。

我尝试使用 pandas,但它需要很长时间,我想添加一些多处理来加快速度,但我无法实现。 这是我的代码:

import pandas as pd

for chunk in pd.read_csv("/folder/list1",chunksize=1000,header=None):
    for ind in chunk.index:
        flag =0
        for chunk1 in pd.read_csv("/folder/list2",chunksize=1000,header=None):
            for ind1 in chunk1.index:
                if chunk[0][ind] == chunk1[0][ind1]:
                    flag = 1
                    break
    if flag == 0:
            with open(f"result", 'a+') as file:
            file.write(chunk[0][ind] + '\n')

【问题讨论】:

  • 我们可以看看您对多进程解决方案的尝试吗?您是在寻找可以工作的代码还是只是寻找可以完成这项工作的通用算法(伪代码)?
  • 列表是否在文件中排序?
  • 寻找解决方案,我的代码根本不起作用。我会尽快发布。未排序的列表@DaSong
  • 我建议先sorting the files。对文件进行排序后,您基本上只需要两个指针,每个文件一个,并且只需要对两个文件进行一次迭代。
  • 仍然在这样的大名单上,不会有太大变化。多处理在这里有帮助吗?

标签: python ruby pandas multithreading multiprocessing


【解决方案1】:

这是 Ruby 中的一种方法。这个想法是创建一个散列,其键是文件#2 行的散列码,其值是文件中的偏移量数组,该文件开始具有由键给出的散列码的行。这些数组中的大多数当然会包含一个偏移量,但我们必须考虑这样一个事实,即不同的字符串可能具有相同的哈希码,这种可能性从唯一哈希码的数量是有限的这一事实中可以明显看出,而唯一字符串的数量是无限的。

可以想象,文件 #2 太大以至于无法将这个哈希值保存在内存中。如果是这种情况,则必须修改下面描述的方法以将哈希的内容保存在数据库中,并由键索引。

首先让我们创建一个文件 #2 的示例。

str =<<~_
Now is the time
for all good coders
to come to the aid
of their fellow coders
_
F2_NAME = 'test'
File.write(FNAME, str)
  #=> 78

假设我们要计算以下内容。

require 'set'
hash_codes_in_F2 = File.foreach(F2_NAME)
                       .with_object(Set.new) { |line, s| s << line.chomp.hash }
  #=> #<Set: {2098464159550983171, -1174471330590153942,
  #           -2185914657312873106, 4309024537421084150}>

我们计算过,例如:

"Now is the time".hash
  #=> 2098464159550983171

请参阅 Set::newString#hash

暂时假设每个字符串都有一个唯一的哈希码,我们知道这通常可能不是真的。我们可以简单地计算文件 1 中每一行的哈希码,看看它是否是集合 hash_codes_in_F2 的成员,每次查找都非常快,相当于确定哈希是否具有特定的键。文件 1 中的行是 F2 中的行当且仅当其哈希码是该集合的一个元素。

现在让我们修改这个方法以识别两个字符串可能具有相同的哈希码。我们将构造一个散列,而不是一个集合。

首先,我们需要一个辅助方法。

def a_repeat?(line, locs, f, loc)
  locs.any? do |l|
    pos = l
    line == f.gets.chomp
  end
  pos = loc
end

这里:

  • line 是一个字符串;
  • locs 是文件 2 中的偏移量数组,它以具有给定哈希码的(chomped)行开头;
  • f 是文件 2 的句柄,文件 2 已经打开读取;和
  • loc 是调用方法时文件 2 中的当前位置,需要在方法返回之前重新定位文件指针。

我们看到此方法确定(chomped)字符串 line 是否等于文件 2 中以 locs 给出的偏移量开始的任何行。

参见 [Enumerable#any?])(https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-any-3F)、IO#posIO#getsIO#pos=

我们现在可以构造哈希hash_codes

hash_codes = {}
f = File.new(F2_NAME)
until f.eof?
  loc = pos
  line = f.gets.chomp
  code = line.hash
  if hash_codes.key?(code)
    if a_repeat?(line, hash_codes[code], f, loc)
      hash_codes[code] << loc
    end
  else
    hash_codes[code] = [loc]
  end
end
hash_codes
  #=> {2098464159550983171=>[0], -1174471330590153942=>[16],
  #    -2185914657312873106=>[36], 4309024537421084150=>[55]}

注意以下几点。

[0, 16, 36, 55].each do |offset|
  f.pos = offset
  puts f.gets.chomp
end

展示

Now is the time
for all good coders
to come to the aid
of their fellow coders

如果文件 2 有一行从偏移量 67 开始,其哈希码为 -2185914657312873106,但不是字符串 "to come to the aid",则键 -2185914657312873106 的值为 [36, 67]

请注意,文件 2 仍处于打开状态。

我们现在只是循环遍历文件 1 的每一行。

假设文件1的一行如下:

line = "to go to the mall"

然后我们计算

code = line.hash
  #=> 1233397236348202523

作为hash_code.key?(code) #=&gt; false,我们得出结论line不是文件2的行。现在假设文件1的行是

line = "to come to the aid"

我们计算

code = line.hash
  #=> -2185914657312873106

因为hash_code.key?(code) #=&gt; true,我们计算

locs = hash_code[code]
  #=> [36]

这告诉我们文件 2 中有一行(或多行相同的行)具有哈希码 -2185914657312873106。但是,我们仍然必须验证这两行是否相同,因此对于locsl 的每个元素,我们需要计算

f.pos = l
line == f.gets.chomp

这里是

f.pos = 36
line == f.gets.chomp
  #=> true

告诉我们文件 1 中的那一行在文件 2 中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-19
    相关资源
    最近更新 更多