如何在Perl中为两行数据查找不同的列
我有6列这样的数据如何在Perl中为两行数据查找不同的列,perl,Perl,我有6列这样的数据 LINES XY1 XY2 XY3 XY4 XY5 P1 Z/Z T/T -/- T/T T/T P2 A/A A/A G/G Z/Z T/T 1 G/G T/T G/G T/T G/G 2 T/T A/A C/C C/C T/T 3 T/T G/G T/T G/G T/T 4 A/A C/C A/A A/A A/A 5 A/A A/A T/T T/T A/A
LINES XY1 XY2 XY3 XY4 XY5
P1 Z/Z T/T -/- T/T T/T
P2 A/A A/A G/G Z/Z T/T
1 G/G T/T G/G T/T G/G
2 T/T A/A C/C C/C T/T
3 T/T G/G T/T G/G T/T
4 A/A C/C A/A A/A A/A
5 A/A A/A T/T T/T A/A
XY1
到XY5
)对于行P1
和P2
是不同的。相等意味着P1
和P2
包含相同的字母(等位基因),或者它们中的任何一个是Z/Z
或-/-
1
到5
行中的列与P2
跨列XY1
到XY5
。如果它们与输出匹配,则应包含1
,否则0
。我继续这个过程,我的程序遇到了第二组P1
和P2
行1
到5
的行总数,仅包括P1
和P2
之间不同的列P1
和P2
之间不同的列数来计算1
到5
行的行百分比LINES XY1 XY2 XY3 XY4 XY5
P1 eq nq eq eq eq SUM %
P2 1
1 0 0 1 0 0 0 0
2 0 1 0 0 1 1 100
3 0 0 0 0 1 0 0
4 1 0 0 0 0 0 0
5 1 1 0 0 0 1 100
我有超过5000行的数据,目前我正在用不同的公式在Excel 2010中工作,但这占用了我很多精力
我想用Perl来做这个,但我是Perl的新手。我已成功地将文件读取到屏幕上
下面是我为文件读取部分编写的代码
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV;
my $file = 'csv.csv';
my $csv = Text::CSV->new();
open(CSV, "<", $file) or die $!;
while (<CSV>) {
if ($csv->parse($_)) {
my @columns = $csv->fields();
print "@columns\n";
}
else {
my $err = $csv->error_input;
print "Failed to parse line: $err";
}
}
close CSV;
#/usr/bin/perl
严格使用;
使用警告;
使用Text::CSV;
my$file='csv.csv';
my$csv=Text::csv->new();
打开(CSV),此程序似乎可以执行您需要的操作。它需要输入文件的路径作为命令行上的参数。生成的输出将发送到STDOUT
很多人不相信我的话,但使用Text::CSV
解析制表符分隔的数据是错误的。它需要设置分隔符,并禁用引号和转义选项,如果操作正确,它最终的行为与split/\t/
相同。您不能说数据是制表符分隔的还是空白分隔的ed,但由于您似乎没有包含空格的数据,因此我假设为后者。这种数据的解析非常简单,只需使用split
它的工作原理是检查输入的每一行,查看它是P1
行、P2
行、编号行还是其他任何行(假定为标题行)
- 当遇到标题行时,后续行的
printf
格式将从标题字段的间距导出,并将该行复制到输出
- 当遇到
P1
行时,数据只需保存在@P1
- 当遇到
P2
行时,数据保存在@P2
中,以便与后续数据进行比较。适当的P1
和P2
行将打印到输出中,并计算一个数组@enquality
,该数组包含P1
数据不匹配的列的索引<代码>P2
数据
@p2
中的数据进行比较,并相应地将1
或0
插入相应的输出列中。$sum
的值是通过将@不等数组中列出的输出列的值相加而计算出来的。百分比Age的计算方法是除以@enquality
中的条目数,然后将数据打印到输出中
33.3333
的内容
另外,您没有说输出P2
行末尾的1
指示了什么,所以我只是照本宣科地复制了它
use strict;
use warnings;
sub compare_alleles {
return 1 if grep {$_ eq '-/-' or $_ eq 'Z/Z' } @_;
return $_[0] eq $_[1] ? 1 : 0;
}
my $format;
my (@p1, @p2);
my @unequal;
while (<>) {
unless (/^(P?\d)/) {
my @widths;
push @widths, $+[1] - $-[1] while /(\S+\s*)/g;
pop @widths;
push @widths, $widths[-1], $widths[-1];
$format = join '', map("%-${_}s", @widths, ''), "\n";
print;
next;
}
my @fields = split;
if ($fields[0] eq 'P1') {
@p1 = @fields;
}
elsif ($fields[0] eq 'P2') {
@p2 = @fields;
printf $format, 'P1', map (compare_alleles($p1[$_], $p2[$_]) ? 'eq' : 'nq', 1..5), 'SUM', '%';
printf $format, 'P2', map('', 1..5), '', '1';
@unequal = grep { not compare_alleles($p1[$_], $p2[$_]) } 1..5;
}
else {
my @columns = ($fields[0], map { $fields[$_] eq $p2[$_] ? 1 : 0 } 1..5);
my $sum = 0;
$sum += $_ for @columns[@unequal];
my $percent = $sum == 0 ? 0 : $sum * 100 / @unequal;
printf $format, @columns, $sum, $percent;
}
}
哇,这是一个很高的要求。你甚至没有说你的数据是否用制表符分隔。你使用了默认的逗号分隔符
Text::CSV
。亲爱的borodin非常感谢你的帮助。请忽略我在%计算中使用的P1和P2之间的NQ之和1。我在excel中的数据看起来像我的标题行(行,XY1到XY5)(这对于所有集合都是相同的)后面是带有P1(parent1)和P2(parent2)的行,后面是带有线条(脱离弹簧)的行,如此序列。第二个集合将继续这样,其结果为XY1到XY5(这些XY编号可能会在某一时间发生变化)。我想将%表示为4位数字,如89.94。在使用代码后,我在第19行的串联中遇到了类似使用未初始化的vlaue$uuu的错误。感谢您可以设置粘贴箱吗?如果您自己无法解决此问题,我需要查看确切的文件内容。还请显示您希望多个数据集的输出。@user2134713:请不要Don’不要试图通过编辑我的答案来扩展您的问题。您可以在问题中添加少量数据,也可以在上面创建一个页面并链接到该页面。亲爱的Borodin,感谢您的回复,这是pastebin的链接。我给出了三个父集合的示例数据,并且第一个集合的结果符合预期。希望我解释得很好。谢谢
LINES XY1 XY2 XY3 XY4 XY5
P1 eq nq eq eq eq SUM %
P2 1
1 0 0 1 0 0 0 0
2 0 1 0 0 1 1 100
3 0 0 0 0 1 0 0
4 1 0 0 0 0 0 0
5 1 1 0 0 0 1 100