Python 使用另一个大文件过滤较小的文件

Python 使用另一个大文件过滤较小的文件,python,perl,awk,Python,Perl,Awk,我有一个巨大的csv文件,大约有10^9行,每行有一对ID,例如: IDa,IDb IDb,IDa IDc,IDd 将此文件称为1。我还有一个更小的csv文件,大约有10^6行,格式相同。将此文件命名为2 我只想在file2中查找至少包含一个ID的行,该ID存在于file1中的某个位置 有没有快速的方法可以做到这一点?我不介意它是用awk、python还是perl编写的。我实际上会用sqlite来编写类似的东西。您可以使用sqlite3 test.sqlite从与两个文件相同的目录创建一个新数

我有一个巨大的csv文件,大约有10^9行,每行有一对ID,例如:

IDa,IDb
IDb,IDa
IDc,IDd
将此文件称为1。我还有一个更小的csv文件,大约有10^6行,格式相同。将此文件命名为2

我只想在file2中查找至少包含一个ID的行,该ID存在于file1中的某个位置


有没有快速的方法可以做到这一点?我不介意它是用awk、python还是perl编写的。

我实际上会用
sqlite
来编写类似的东西。您可以使用
sqlite3 test.sqlite
从与两个文件相同的目录创建一个新数据库,然后执行以下操作:

create table file1(id1, id2);
create table file2(id1, id2);
.separator ","
.import file1.csv file1
.import file2.csv file2
WITH all_ids AS (
    SELECT id1 FROM file1 UNION SELECT id2 FROM file1
)
SELECT * FROM file2 WHERE id1 IN all_ids OR id2 IN all_ids;

使用
sqlite
的优点是,与使用某种脚本语言编写的简单脚本相比,您可以更智能地管理内存。

我实际上会使用
sqlite
实现类似的功能。您可以使用
sqlite3 test.sqlite
从与两个文件相同的目录创建一个新数据库,然后执行以下操作:

create table file1(id1, id2);
create table file2(id1, id2);
.separator ","
.import file1.csv file1
.import file2.csv file2
WITH all_ids AS (
    SELECT id1 FROM file1 UNION SELECT id2 FROM file1
)
SELECT * FROM file2 WHERE id1 IN all_ids OR id2 IN all_ids;
使用sqlite的优点是,与使用某种脚本语言编写的简单脚本相比,您可以更智能地管理内存。

在perl中

use strict;
use warnings;
use autodie;

# read file2
open my $file2, '<', 'file2';
chomp( my @file2 = <$file2> );
close $file2;

# record file2 line numbers each id is found on
my %id;
for my $line_number (0..$#file2) {
    for my $id ( split /,/, $file2[$line_number] ) {
        push @{ $id{$id} }, $line_number;
    }
}

# look for those ids in file1
my @use_line;
open my $file1, '<', 'file1';
while ( my $line = <$file1> ) {
    chomp $line;
    for my $id ( split /,/, $line ) {
        if ( exists $id{$id} ) {
            @use_line[ @{ $id{$id} } ] = @{ $id{$id} };
        }
    }
}
close $file1;

# print lines whose ids were found
print "$_\n" for @file2[ grep defined, @use_line ];
使用严格;
使用警告;
使用自动模具;
#读取文件2
在perl中打开我的$file2,“

use strict;
use warnings;
use autodie;

# read file2
open my $file2, '<', 'file2';
chomp( my @file2 = <$file2> );
close $file2;

# record file2 line numbers each id is found on
my %id;
for my $line_number (0..$#file2) {
    for my $id ( split /,/, $file2[$line_number] ) {
        push @{ $id{$id} }, $line_number;
    }
}

# look for those ids in file1
my @use_line;
open my $file1, '<', 'file1';
while ( my $line = <$file1> ) {
    chomp $line;
    for my $id ( split /,/, $line ) {
        if ( exists $id{$id} ) {
            @use_line[ @{ $id{$id} } ] = @{ $id{$id} };
        }
    }
}
close $file1;

# print lines whose ids were found
print "$_\n" for @file2[ grep defined, @use_line ];
使用严格;
使用警告;
使用自动模具;
#读取文件2
打开我的$file2,“示例文件:

cat f1
IDa,IDb
IDb,IDa
IDc,IDd


cat f2
IDt,IDy
IDb,IDj
Awk解决方案:

awk -F, 'NR==FNR {a[$1]=$1;b[$2]=$2;next} ($1 in a)||($2 in b)' f1 f2
IDb,IDj
这将在数组a和b中存储文件1的第一列和第二列。如果看到第二个文件的第一列或第二列,则打印这些行。

示例文件:

cat f1
IDa,IDb
IDb,IDa
IDc,IDd


cat f2
IDt,IDy
IDb,IDj
Awk解决方案:

awk -F, 'NR==FNR {a[$1]=$1;b[$2]=$2;next} ($1 in a)||($2 in b)' f1 f2
IDb,IDj

这将在数组a和b中存储文件1的第一列和第二列。如果看到第二个文件的第一列或第二列,则打印这些行。

使用这些输入文件进行测试:

$ cat file1
IDa,IDb
IDb,IDa
IDc,IDd

$ cat file2
IDd,IDw
IDx,IDc
IDy,IDz
如果文件1可以放入内存中:

$ awk -F, 'NR==FNR{a[$1];a[$2];next} ($1 in a) || ($2 in a)' file1 file2
IDd,IDw
IDx,IDc
$ awk -F, '
    ARGIND==2 {
        if ($1 in inBothFiles) {
            inBothFiles[$1] = 1
        }
        if ($2 in inBothFiles) {
            inBothFiles[$2] = 1
        }
        next
    }
    ARGIND==1 {
        inBothFiles[$1] = 0
        inBothFiles[$2] = 0
        next
    }
    ARGIND==3 {
        if (inBothFiles[$1] || inBothFiles[$2]) {
            print
        }
    }
' file2 file1 file2
IDd,IDw
IDx,IDc
如果不是,但文件2可以放在内存中:

$ awk -F, 'NR==FNR{a[$1];a[$2];next} ($1 in a) || ($2 in a)' file1 file2
IDd,IDw
IDx,IDc
$ awk -F, '
    ARGIND==2 {
        if ($1 in inBothFiles) {
            inBothFiles[$1] = 1
        }
        if ($2 in inBothFiles) {
            inBothFiles[$2] = 1
        }
        next
    }
    ARGIND==1 {
        inBothFiles[$1] = 0
        inBothFiles[$2] = 0
        next
    }
    ARGIND==3 {
        if (inBothFiles[$1] || inBothFiles[$2]) {
            print
        }
    }
' file2 file1 file2
IDd,IDw
IDx,IDc
上面使用GNUawk表示argid-对于其他awk,只需在开始处添加一个
FNR==1{argid++}


为了提高效率,我首先列出了
argid==2
块(即处理第二个参数的部分,在本例中是10^9
file1
),因此我们不会对大得多的文件中的每一行不必要地测试
argid==1

使用这些输入文件进行测试:

$ cat file1
IDa,IDb
IDb,IDa
IDc,IDd

$ cat file2
IDd,IDw
IDx,IDc
IDy,IDz
如果文件1可以放入内存中:

$ awk -F, 'NR==FNR{a[$1];a[$2];next} ($1 in a) || ($2 in a)' file1 file2
IDd,IDw
IDx,IDc
$ awk -F, '
    ARGIND==2 {
        if ($1 in inBothFiles) {
            inBothFiles[$1] = 1
        }
        if ($2 in inBothFiles) {
            inBothFiles[$2] = 1
        }
        next
    }
    ARGIND==1 {
        inBothFiles[$1] = 0
        inBothFiles[$2] = 0
        next
    }
    ARGIND==3 {
        if (inBothFiles[$1] || inBothFiles[$2]) {
            print
        }
    }
' file2 file1 file2
IDd,IDw
IDx,IDc
如果不是,但文件2可以放在内存中:

$ awk -F, 'NR==FNR{a[$1];a[$2];next} ($1 in a) || ($2 in a)' file1 file2
IDd,IDw
IDx,IDc
$ awk -F, '
    ARGIND==2 {
        if ($1 in inBothFiles) {
            inBothFiles[$1] = 1
        }
        if ($2 in inBothFiles) {
            inBothFiles[$2] = 1
        }
        next
    }
    ARGIND==1 {
        inBothFiles[$1] = 0
        inBothFiles[$2] = 0
        next
    }
    ARGIND==3 {
        if (inBothFiles[$1] || inBothFiles[$2]) {
            print
        }
    }
' file2 file1 file2
IDd,IDw
IDx,IDc
上面使用GNUawk表示argid-对于其他awk,只需在开始处添加一个
FNR==1{argid++}



为了提高效率,我首先列出了
argid==2
块(即处理第二个参数的部分,在本例中是10^9
file1
),这样我们就不会对大得多的文件中的每一行不必要地测试
argid==1

file1中有多少种不同的ID?10^9? 您的示例有3行代码和3个不同的ID。我认为您应该尝试使用其中一种技术编写一段代码,现在您只需要询问您的整个就绪程序。@JamesBrown大约10^9,很遗憾。然后可能分为两个阶段。例如,使用AWK将文件2中的所有ID读取到内存中,将这些ID与文件1匹配,您就有了一个从文件2获取的ID列表。这样就不需要在内存中存储10^9个键,只需要存储10^6个。是否需要保留文件2中的行顺序?文件1中有多少种不同类型的ID?10^9? 您的示例有3行代码和3个不同的ID。我认为您应该尝试使用其中一种技术编写一段代码,现在您只需要询问您的整个就绪程序。@JamesBrown大约10^9,很遗憾。然后可能分为两个阶段。例如,使用AWK将文件2中的所有ID读取到内存中,将这些ID与文件1匹配,您就有了一个从文件2获取的ID列表。这样就不需要在内存中存储10^9个键,而只需要存储10^6个。是否需要保留文件2中的行顺序?谢谢。我从未使用过sqlite。我是否只从sqlite3导入添加*?
sqlite3
是一个独立的可执行文件。您只需使用
sqlite3test.sqlite
执行它,它将创建一个名为
test.sqlite
的新数据库。然后,它会给您一个提示,您可以在其中键入sql命令。在这个提示中,只需键入我上面给出的命令。啊,是的。我认为还有一个python sqlite模块也可以工作。是的,有python sqlite模块,但是没有必要将python用于如此简单的事情。
UNION ALL
将包含来自
id2
的副本,在最坏的情况下,将
所有ID
中的ID数量增加一倍。谢谢。我从未使用过sqlite。我是否只从sqlite3导入添加*?
sqlite3
是一个独立的可执行文件。您只需使用
sqlite3test.sqlite
执行它,它将创建一个名为
test.sqlite
的新数据库。然后,它会给您一个提示,您可以在其中键入sql命令。在这个提示中,只需键入我上面给出的命令。啊,是的。我认为还有一个python sqlite模块也可以工作。是的,有一个python sqlite模块,但是没有必要将python用于如此简单的事情。
UNION ALL
将包含来自
id2
的副本,在最坏的情况下,将
ALL\u ID
中的ID数量增加一倍。其中至少包含一个存在于某处的ID-
a[]
不够吗?@JamesBrown,OP提到了这对ID。所以我假设这两列都是ID。我只想在文件2中找到包含…-这个解决方案从
file1
返回行。在我看来,这需要在内存中存储较大文件中的所有数据(多GB)。每行有两个ID。其中至少包含一个存在于某处的ID-
a[]
不够吗?@JamesBrown,OP提到了一对ID。所以我假设这两列都是ID。我只想在文件2中找到包含…-此解决方案从
file1
返回行