Python 用匹配的键组合线
我有一个具有以下结构的文本文件Python 用匹配的键组合线,python,linux,perl,awk,Python,Linux,Perl,Awk,我有一个具有以下结构的文本文件 ID,operator,a,b,c,d,true WCBP12236,J1,75.7,80.6,65.9,83.2,82.1 WCBP12236,J2,76.3,79.6,61.7,81.9,82.1 WCBP12236,S1,77.2,81.5,69.4,84.1,82.1 WCBP12236,S2,68.0,68.0,53.2,68.5,82.1 WCBP12234,J1,63.7,67.7,72.2,71.6,75.3 WCBP12234,J2,68.6,6
ID,operator,a,b,c,d,true
WCBP12236,J1,75.7,80.6,65.9,83.2,82.1
WCBP12236,J2,76.3,79.6,61.7,81.9,82.1
WCBP12236,S1,77.2,81.5,69.4,84.1,82.1
WCBP12236,S2,68.0,68.0,53.2,68.5,82.1
WCBP12234,J1,63.7,67.7,72.2,71.6,75.3
WCBP12234,J2,68.6,68.4,41.4,68.9,75.3
WCBP12234,S1,81.8,82.7,67.0,87.5,75.3
WCBP12234,S2,66.6,67.9,53.0,70.7,75.3
WCBP12238,J1,78.6,79.0,56.2,82.1,84.1
WCBP12239,J2,66.6,72.9,79.5,76.6,82.1
WCBP12239,S1,86.6,87.8,23.0,23.0,82.1
WCBP12239,S2,86.0,86.9,62.3,89.7,82.1
WCBP12239,J1,70.9,71.3,66.0,73.7,82.1
WCBP12238,J2,75.1,75.2,54.3,76.4,84.1
WCBP12238,S1,65.9,66.0,40.2,66.5,84.1
WCBP12238,S2,72.7,73.2,52.6,73.9,84.1
每个ID
对应于一个由操作员多次分析的数据集。i、 eJ1
和J2
是操作员J的第一次和第二次尝试。测量a
、b
、c
和d
使用4种稍有不同的算法来测量真实值位于true
列中的值
我想做的是创建3个新的文本文件,比较J1
vsJ2
、S1
vsS2
和J1
vsS1
的结果。J1
vsJ2
的输出示例:
ID,operator,a1,a2,b1,b2,c1,c2,d1,d2,true
WCBP12236,75.7,76.3,80.6,79.6,65.9,61.7,83.2,81.9,82.1
WCBP12234,63.7,68.6,67.7,68.4,72.2,41.4,71.6,68.9,75.3
foreach i (`more unique_ids`)
grep $i test.txt | egrep 'J[1-2]' | sort -t',' -k2
end
其中a1
是J1
等的测量a
另一个例子是针对S1
和S2
:
ID,operator,a1,a2,b1,b2,c1,c2,d1,d2,true
WCBP12236,77.2,68.0,81.5,68.0,69.4,53.2,84.1,68.5,82.1
WCBP12234,81.8,66.6,82.7,67.9,67.0,53,87.5,70.7,75.3
ID不会按字母数字顺序排列,也不会为同一ID对运算符进行集群。我不确定如何最好地完成此任务—使用linux工具或perl/python之类的脚本语言
我最初使用linux的尝试很快就失败了
首先查找所有唯一ID(已排序)
在这些ID中循环并排序J1
,J2
:
ID,operator,a1,a2,b1,b2,c1,c2,d1,d2,true
WCBP12236,75.7,76.3,80.6,79.6,65.9,61.7,83.2,81.9,82.1
WCBP12234,63.7,68.6,67.7,68.4,72.2,41.4,71.6,68.9,75.3
foreach i (`more unique_ids`)
grep $i test.txt | egrep 'J[1-2]' | sort -t',' -k2
end
这给了我排序的数据
WCBP12234,J1,63.7,67.7,72.2,71.6,75.3
WCBP12234,J2,68.6,68.4,41.4,68.9,80.4
WCBP12236,J1,75.7,80.6,65.9,83.2,82.1
WCBP12236,J2,76.3,79.6,61.7,81.9,82.1
WCBP12238,J1,78.6,79.0,56.2,82.1,82.1
WCBP12238,J2,75.1,75.2,54.3,76.4,82.1
WCBP12239,J1,70.9,71.3,66.0,73.7,75.3
WCBP12239,J2,66.6,72.9,79.5,76.6,75.3
我不知道如何重新排列这些数据以获得所需的结构。我尝试在foreach
循环awk'BEGIN{RS=“\n\n”}{print$1,$3,$10,$4,$11,$5,$12,$6,$13,$7}中的
有什么想法吗?我确信使用awk
可以以一种不那么麻烦的方式完成这项工作,尽管使用合适的脚本语言可能更好。您可以使用Perl csv模块提取字段,然后将其存储在散列中,其中ID是主键,第二个字段是辅助键,所有字段都作为值存储。然后,做任何你想做的比较都应该是微不足道的。如果要保留行的原始顺序,可以在第一个循环中使用数组
use strict;
use warnings;
use Text::CSV;
my %data;
my $csv = Text::CSV->new({
binary => 1, # safety precaution
eol => $/, # important when using $csv->print()
});
while ( my $row = $csv->getline(*ARGV) ) {
my ($id, $J) = @$row; # first two fields
$data{$id}{$J} = $row; # store line
}
Python方式:
import os,sys, re, itertools
info=["WCBP12236,J1,75.7,80.6,65.9,83.2,82.1",
"WCBP12236,J2,76.3,79.6,61.7,81.9,82.1",
"WCBP12236,S1,77.2,81.5,69.4,84.1,82.1",
"WCBP12236,S2,68.0,68.0,53.2,68.5,82.1",
"WCBP12234,J1,63.7,67.7,72.2,71.6,75.3",
"WCBP12234,J2,68.6,68.4,41.4,68.9,80.4",
"WCBP12234,S1,81.8,82.7,67.0,87.5,75.3",
"WCBP12234,S2,66.6,67.9,53.0,70.7,72.7",
"WCBP12238,J1,78.6,79.0,56.2,82.1,82.1",
"WCBP12239,J2,66.6,72.9,79.5,76.6,75.3",
"WCBP12239,S1,86.6,87.8,23.0,23.0,82.1",
"WCBP12239,S2,86.0,86.9,62.3,89.7,82.1",
"WCBP12239,J1,70.9,71.3,66.0,73.7,75.3",
"WCBP12238,J2,75.1,75.2,54.3,76.4,82.1",
"WCBP12238,S1,65.9,66.0,40.2,66.5,80.4",
"WCBP12238,S2,72.7,73.2,52.6,73.9,72.7" ]
def extract_data(operator_1, operator_2):
operator_index=1
id_index=0
data={}
result=[]
ret=[]
for line in info:
conv_list=line.split(",")
if len(conv_list) > operator_index and ((operator_1.strip().upper() == conv_list[operator_index].strip().upper()) or (operator_2.strip().upper() == conv_list[operator_index].strip().upper()) ):
if data.has_key(conv_list[id_index]):
iters = [iter(conv_list[int(operator_index)+1:]), iter(data[conv_list[id_index]])]
data[conv_list[id_index]]=list(it.next() for it in itertools.cycle(iters))
continue
data[conv_list[id_index]]=conv_list[int(operator_index)+1:]
return data
ret=extract_data("j1", "s2")
print ret
O/p:
{'WCBP12239':['70.9','86.0','71.3','86.9','66.0','62.3','73.7','89.7','75.3','82.1'],'WCBP12238':['72.7','78.6','73.2','79.0','52.6','56.2','73.9','82.9','82.1','WCBP12234':['66.6','63.7','67.9','67.7','67.7','53.0','72.2','70.7','71.6','WCBP12236'][68.0,75.7,68.0,80.6,53.2,65.9,68.5,83.2,82.1,82.1']
我没有像TLP那样使用Text::CSV。如果您需要,您可以,但对于本例,我认为由于字段中没有嵌入逗号,所以我对“,”进行了简单的拆分。此外,两个运算符的真实字段都会列出(而不是仅列出1),因为我认为最后一个值的特殊情况会使解决方案复杂化
#!/usr/bin/perl
use strict;
use warnings;
use List::MoreUtils qw/ mesh /;
my %data;
while (<DATA>) {
chomp;
my ($id, $op, @vals) = split /,/;
$data{$id}{$op} = \@vals;
}
my @ops = ([qw/J1 J2/], [qw/S1 S2/], [qw/J1 S1/]);
for my $id (sort keys %data) {
for my $comb (@ops) {
open my $fh, ">>", "@$comb.txt" or die $!;
my $a1 = $data{$id}{ $comb->[0] };
my $a2 = $data{$id}{ $comb->[1] };
print $fh join(",", $id, mesh(@$a1, @$a2)), "\n";
close $fh or die $!;
}
}
__DATA__
WCBP12236,J1,75.7,80.6,65.9,83.2,82.1
WCBP12236,J2,76.3,79.6,61.7,81.9,82.1
WCBP12236,S1,77.2,81.5,69.4,84.1,82.1
WCBP12236,S2,68.0,68.0,53.2,68.5,82.1
WCBP12234,J1,63.7,67.7,72.2,71.6,75.3
WCBP12234,J2,68.6,68.4,41.4,68.9,75.3
WCBP12234,S1,81.8,82.7,67.0,87.5,75.3
WCBP12234,S2,66.6,67.9,53.0,70.7,75.3
WCBP12239,J1,78.6,79.0,56.2,82.1,82.1
WCBP12239,J2,66.6,72.9,79.5,76.6,82.1
WCBP12239,S1,86.6,87.8,23.0,23.0,82.1
WCBP12239,S2,86.0,86.9,62.3,89.7,82.1
WCBP12238,J1,70.9,71.3,66.0,73.7,84.1
WCBP12238,J2,75.1,75.2,54.3,76.4,84.1
WCBP12238,S1,65.9,66.0,40.2,66.5,84.1
WCBP12238,S2,72.7,73.2,52.6,73.9,84.1
S1 S2.txt
WCBP12234,81.8,66.6,82.7,67.9,67.0,53.0,87.5,70.7,75.3,75.3
WCBP12236,77.2,68.0,81.5,68.0,69.4,53.2,84.1,68.5,82.1,82.1
WCBP12238,65.9,72.7,66.0,73.2,40.2,52.6,66.5,73.9,84.1,84.1
WCBP12239,86.6,86.0,87.8,86.9,23.0,62.3,23.0,89.7,82.1,82.1
J1 S1.txt
WCBP12234,63.7,81.8,67.7,82.7,72.2,67.0,71.6,87.5,75.3,75.3
WCBP12236,75.7,77.2,80.6,81.5,65.9,69.4,83.2,84.1,82.1,82.1
WCBP12238,70.9,65.9,71.3,66.0,66.0,40.2,73.7,66.5,84.1,84.1
WCBP12239,78.6,86.6,79.0,87.8,56.2,23.0,82.1,23.0,82.1,82.1
更新:要仅获取1个真值,for循环可以这样编写:
for my $id (sort keys %data) {
for my $comb (@ops) {
local $" = '';
open my $fh, ">>", "@$comb.txt" or die $!;
my $a1 = $data{$id}{ $comb->[0] };
my $a2 = $data{$id}{ $comb->[1] };
pop @$a2;
my @mesh = grep defined, mesh(@$a1, @$a2);
print $fh join(",", $id, @mesh), "\n";
close $fh or die $!;
}
}
更新:在grep expr中为测试添加了“defined”,因为这是正确的方法(而不是只测试“$\”,它可能是0,并且被grep错误地排除在列表之外).在您的第二个代码块中,您是否打算让82.1
只出现一次?抱歉,重新阅读问题,注意到它是“真”值。另外,为什么您需要J1 v J2两次?icedwater指的是表示您希望输入类型对应的J1 vs J2、S1 vs S2和J1 vs J2的结果的部分。我的意思是J1 vs J2
,S1 vs S2
和J1 vs S1
在您的文件中,同一数据集ID可以有不同的true
值?例如,WCBP12234