arrays - 用于管理 Perl 中不相邻行之间的计算的数组数组
问题描述
我正在处理一些数据以计算样本的平均值,并且当差异很大(平均值超过 +/- 2 个标准差)时,进行插值,但我需要强大的帮助!
困难的部分是选择让计算尊重它们所属的样本的行。样本标识符放在不容易管理的依赖逻辑中的第一列或第二列或第三列(下面的示例中没有第三列)。
我的数据看起来像这样(直接从我的文件中复制和粘贴)。输入文件也可在https://gofile.io/?c=3PLR8m获得。列是制表符分隔的,每个标识符在字符前都有一个空格。
ENTITY-CODE XX YY ZZ AA BB CC att 1
/P1
^/A1/S1 143.07 124.05 -159.24 -160.53 0.39 3.31 15
^<S2 143.45 123.69 -157.19 -160.74 0.43 1.5 14.8
+A1/S1 143.87 122.84 -157.08 -147.56 -30.37 3.07 4.9
^<S2 152.09 120.29 -155.42 -145.61 -67.13 0.37 3.3
^<S3 161.5 120.13 -153.34 -134.92 -73.39 -3.93 3.4
^<S4 27.76 122.15 -152.59 -103.01 -74.37 -20 2.9
^<S5 179.58 125.71 -153.46 -90.21 -73.6 -21.68 2.8
^<S6 189.23 128.85 -152.9 -86.28 -72.54 -19.89 2.4
^<S7 196.23 135.77 -152.82 -73.48 -75.22 -19.93 2.1
^<S8 195.49 147.85 -150.64 -63.59 -80.44 -32.27 1.5
^<S3 143.07 124.1 -157.05 -145.58 -1.81 6.34 16
+A1/S1 142.03 123.41 -156.23 -72.07 -19.45 -0.4 5.5
^<S2 134.29 121.27 -153.31 -76.28 -3.92 -2.37 3.8
^<S3 128.55 119.39 -152.31 -73.1 6.95 0.04 2.7
^<S4 120.87 115.88 -150.91 -69.62 8.05 0.63 2.7
^<S5 115.31 112.83 -151.31 -76.97 7.45 -2.31 2.4
^<S6 108.54 110.71 -149.38 -86.09 5.68 -6.48 1.5
^<S4 143.49 123.63 -155.79 -175.31 14.3 12.22 13.7
+A1/S1 143.5 124.75 -155.22 175.69 25.35 25.61 5.9
^<S2 145.63 130.57 -156.39 141.67 42.19 31.94 5.3
^<S3 153.77 131.23 -153.8 71.9 34.43 20.11 3.6
^<S4 160.99 132.18 -149.31 89.71 35.44 14.31 2.6
^<S5 166.86 133.6 -146.6 93.88 34.73 11.46 1.8
+A2/S1 143.63 122.79 -155.05 65.04 4.77 -16.93 3.5
^<S6 144.71 122.02 -151.41 56.49 -7.71 -16.1 2.8
^<S6 146.83 120.14 -148.52 61.14 24.37 48.58 2.9
^<S6 154.06 115.65 -149.29 60.87 20.18 13.8 2.5
^<S5 143.32 33.32 -153.16 -127.03 8.59 9.07 12.4
^<S6 143.49 121.69 -150.07 -127.26 9.04 10.85 12.5
基本上,具有标识符的行在同一列中包含“A”的行需要进行计算(连同“A”的行)以检查超出范围的值,因为它们属于同一样本. 如果在同一列中存在另一个包含“A”的标识符,则表示正在开始另一组属于另一个样本并需要进行另一个计算的行。
在我在这里发布的示例中,我想要一个脚本,它从第一个开始^/A1/S1
识别第一列中具有标识符的所有行,并检查它们的XX
,YY
和ZZ
值。
+A1/S1
如果标识符在第二列或其他列中,脚本也应该这样做。
在实践中,每次有一个包含“A”的标识符意味着正在开始一个样本,该样本的其他元素在同一列中具有 S 类型标识符(直到另一个 A 类型标识符)。
S 型标识符中包含的数字不相关。因此,例如,具有相同标识符的三行(紧挨输入示例的末尾)必须被视为三组不同的值。
输出的格式应该与输入的格式相同,只是插值的不同之处发生了变化。插值应包括对样本的平均值和标准偏差的计算(同一列中具有标识符的行,从标有“A”的行到同一列中具有“A”的另一个标识符之前的最后一个)并检查一个值是否超过平均值 +/- 2 个标准差 ( mean±(2*dev.st)
)。如果是,则用样本均值替换一个值。
在此处的示例中,我想获得与输入相同的内容,除了:XX
第八行中的值 (27.76),应替换为XX
根据同一样本行的值计算的平均值,这些值是前一个和下一行(在第二列中分别具有^<S3
和作为标识符)和(ii)第三十行(33.32)中的值应替换为在第一列中具有和的行上计算的平均值。^<S5
YY
^<S4
^<S6
因此,这是我想要的输出。
ENTITY-CODE XX YY ZZ AA BB CC att 1
/P1
^/A1/S1 143.07 124.05 -159.24 -160.53 0.39 3.31 15
^<S2 143.45 123.69 -157.19 -160.74 0.43 1.5 14.8
+A1/S1 143.87 122.84 -157.08 -147.56 -30.37 3.07 4.9
^<S2 152.09 120.29 -155.42 -145.61 -67.13 0.37 3.3
^<S3 161.5 120.13 -153.34 -134.92 -73.39 -3.93 3.4
^<S4 173.59 122.15 -152.59 -103.01 -74.37 -20 2.9
^<S5 179.58 125.71 -153.46 -90.21 -73.6 -21.68 2.8
^<S6 189.23 128.85 -152.9 -86.28 -72.54 -19.89 2.4
^<S7 196.23 135.77 -152.82 -73.48 -75.22 -19.93 2.1
^<S8 195.49 147.85 -150.64 -63.59 -80.44 -32.27 1.5
^<S3 143.07 124.1 -157.05 -145.58 -1.81 6.34 16
+A1/S1 142.03 123.41 -156.23 -72.07 -19.45 -0.4 5.5
^<S2 134.29 121.27 -153.31 -76.28 -3.92 -2.37 3.8
^<S3 128.55 119.39 -152.31 -73.1 6.95 0.04 2.7
^<S4 120.87 115.88 -150.91 -69.62 8.05 0.63 2.7
^<S5 115.31 112.83 -151.31 -76.97 7.45 -2.31 2.4
^<S6 108.54 110.71 -149.38 -86.09 5.68 -6.48 1.5
^<S4 143.49 123.63 -155.79 -175.31 14.3 12.22 13.7
+A1/S1 143.5 124.75 -155.22 175.69 25.35 25.61 5.9
^<S2 145.63 130.57 -156.39 141.67 42.19 31.94 5.3
^<S3 153.77 131.23 -153.8 71.9 34.43 20.11 3.6
^<S4 160.99 132.18 -149.31 89.71 35.44 14.31 2.6
^<S5 166.86 133.6 -146.6 93.88 34.73 11.46 1.8
+A2/S1 143.63 122.79 -155.05 65.04 4.77 -16.93 3.5
^<S6 144.71 122.02 -151.41 56.49 -7.71 -16.1 2.8
^<S6 146.83 120.14 -148.52 61.14 24.37 48.58 2.9
^<S6 154.06 115.65 -149.29 60.87 20.18 13.8 2.5
^<S5 143.32 123.41 -153.16 -127.03 8.59 9.07 12.4
^<S6 143.49 121.69 -150.07 -127.26 9.04 10.85 12.5
对于输入,它只有两个变化:
^<S4
在第 8 行(用第二列中的标识符标记)中,XX
值 27.76 已替换为对第XX
5 到 12 行的值计算的平均值(在第二列中具有+A1/S1
,^<S2
,^<S3
,^<S4
,^<S5
,^<S6
,^<S7
,^<S8
作为标识符) ;^<S6
在第 30 行(用第一列中的标识符标记)中,YY
值 33.32 已替换为对第 3、4、13、20、30YY
和 31 行的值计算的平均值(分别用标识符标记^/A1/S1
,^<S2
...^<S3
,^<S4
,^<S5
,^<S6
在第一列)。
到目前为止我写的代码如下。我想到了数组数组,但我不确定如何设置它。
任何建议都是非常受欢迎的,因为我被迷住了。谢谢!
open (HAN, "<", "$file") || die "problems with the input file";
my @lines = ();
while (<HAN>) {
chomp;
push(@lines, $_); }
#print STDERR "@lines\n";
close (HAN);
for ($lines[$i] =0; $i<=$#lines; $i++){
@columns = split (/\t/, $lines[$i]);
#print STDERR "@columns\n";
my @p;
my @s;
if (( $columns[0] ne "" ) && ( $columns[1] eq "" )){
push @p, $lines[$i] ;
#print STDERR "@p\n";
} elsif (( $columns[0] eq "" ) && ( $columns[1] ne "" )){
push @s, $lines[$i] ;
#print STDERR "@s\n";
print STDERR "@s\n";
解决方案
对不起,我没有更多的时间来专注于此。也许以下内容可以帮助您找到正确的方法。
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
use Syntax::Construct qw{ // };
use List::Util qw{ sum };
my @data;
while (<>) {
chomp;
push @data, [ split /\t/ ];
}
my (@dev_st, @mean);
for my $line_index (0 .. $#data) {
for my $column (2, 3) {
for my $level (0, 1) {
if (($data[$line_index][$level] // "") =~ /A/) {
my $to = $line_index;
my $inner_group;
do { ++$to } until $to > $#data
|| $level == 1 && $data[$to][0]
|| (($data[$to][$level] // "") =~ /A/
and $inner_group = 1);
--$to if $inner_group;
my @group_data = map $data[$_][2],
grep $data[$_][$level],
$line_index .. $to;
$mean[$level] = sum(@group_data) / @group_data;
$dev_st[$level] = sqrt(1/(@group_data - 1) * sum(
map { ($_ - $mean[$level]) ** 2 } @group_data));
# warn "$line_index: @group_data\n$mean[$level] $dev_st[$level]\n";
}
}
my $value = $data[$line_index][$column] // "";
next unless $value =~ /-?[0-9]+(?:\.[0-9]+)?/;
my ($level) = grep $data[$line_index][$_], 0, 1;
if ( $value > $mean[$level] + 2 * $dev_st[$level]
|| $value < $mean[$level] - 2 * $dev_st[$level]
) {
$data[$line_index][$column]
= sprintf '%.2f', $mean[$level];
}
}
say join "\t", map $_ // "", @{ $data[$line_index] };
}
print "\n";
推荐阅读
- swift - Swift 协议行为
- python - pyqt5 组合框选定项与另一个窗口共享(信号/插槽)
- python - 未找到电子表格错误 - 尝试访问 Google 表格
- angular - Angular 8 Accordion,地图未显示
- etl - 如何获得正确的气流时间表
- bash - 文件名中的 Bash 单引号和 ffmpeg 转义
- c - 如何在链表的结构中使用字符串?
- azure - 将 Liquibase 与 Azure SQL 和 Azure Active Directory 身份验证结合使用
- java - Hikari 无法创建池连接
- javascript - 从异步类构造函数创建 observable