我正在尝试编写一个脚本来处理行为测试设备的输出。我需要在生成的CSV文件中按时间戳对齐所有数据。这是一个问题:测试运行的开始时间不同(它接近但不准确 - 可以关闭几秒到几分钟)。我可以得到我想要的输出,我想我对如何对齐所有变量有一个好主意,但不知道如何实现它。
所有数据都包含两个级别的哈希值(%hash {id} {vars}),所有变量都存储为数字以保持简单(变量名称从打印输出的数组中读取)。从输入文件中删除所有数据后,脚本将遍历散列并打印出数据,如下所示:
Variable 1
ID #1 data1 data2 data3...
ID #2 data1 data2 data3...
...
Variable 2
...
等等。
这些是24小时录音。所有主题的最后一个数据点(var = 20)都很轻:数据在白天和夜晚都会显示为“ON”或“OFF”。我能看到的最佳对齐方法是使用灯光OFF标记来对齐数据。
我的想法如下:
1.找到每个ID的第一个位置,其中var'20'='OFF'并记录位置
2.找出哪个ID具有OFF的最大位置(即最早开始记录的ID)
3.将空值对添加到每个其他主题,直到所有的OFF位置相同。
例如,如果数据每分钟记录一次,并且一个主体的OFF时间比所有其他主体晚5分钟,则将5个空数据点添加到所有其他主题以对齐数据。
必须为每个主题的所有数据点进行此操作,而不仅仅是灯开/关测量。
这种方法有用吗?如果是这样,我怎么能实现这个呢?
**请注意,我需要能够将其打包为在多台计算机上运行的独立脚本,因此我不能指望默认情况下未安装的perl模块。
- 按请求编辑:示例。输入数据看起来像这样(它是一个CSV文件)
ID, TIME, DATA1, DATA2, DATA3, [...] , LIGHT
Subj1, 10:00:00, data1, data2, data3, [...] , ON
Subj1, 10:00:30, data1, data2, data3, [...] , ON
Subj1, 10:01:00, data1, data2, data3, [...] , OFF
Subj1, 10:01:00, data1, data2, data3, [...] , OFF
对于另一个主题,数据可能如下所示:
ID, TIME, DATA1, DATA2, DATA3, [...] , LIGHT
Subj2, 09:59:27, data1, data2, data3, [...] , ON
Subj2, 09:59:57, data1, data2, data3, [...] , ON
Subj2, 10:00:27, data1, data2, data3, [...] , ON
Subj2, 10:00:57, data1, data2, data3, [...] , OFF
Subj2, 10:01:27, data1, data2, data3, [...] , OFF
脚本从所有文件中获取每一行,并将它们添加到由ID键控的哈希值,每个数据列的一个级别由列号键入。对于这两个文件,hash看起来像这样:
$VAR1 = {
'Subj1' => {
'1' => [
data1
data1
...
]
'2' => [
data2
data2
...
]
...
'20' => [
ON
ON
...
}
'Subj1' => {
'1' => [
data1
data1
...
]
'2' => [
data2
data2
...
]
...
'20' => [
ON
ON
...
}
};
使用foreach循环输出数据:
foreach my $k (sort {$a cmp $b} keys %data) {
print OUT $k, "\,";
foreach my $d ( @{ $data{$k}{$i} } ) { print OUT $d, "\,"; }
print OUT "\n";
}
输出如下:
TIME
Subj1, 10:00:00, 10:00:30, 10:01:00, 10:01:30,
Subj2, 09:59:27, 09:59:57, 10:00:27, 10:00:57, 10:01:27,
DATA1
Subj1, data1, data1, data1, data1, data1,
Subj2, data2, data2, data2, data2, data2, data2,
[ ... all other data ... ]
LIGHT
Subj1, ON, ON, OFF, OFF,
Subj2, ON, ON, ON, OFF, OFF,
我需要做的是通过LIGHT中的ON / OFF列对齐所有数据,方法是添加如下的空值:
TIME
Subj1, , 10:00:00, 10:00:30, 10:01:00, 10:01:30,
Subj2, 09:59:27, 09:59:57, 10:00:27, 10:00:57, 10:01:27,
DATA1
Subj1, , data1, data1, data1, data1, data1,
Subj2, data2, data2, data2, data2, data2, data2,
[ ... all other data ... ]
LIGHT
Subj1, , ON, ON, OFF, OFF,
Subj2, ON, ON, ON, OFF, OFF,
试图找出最好的方法。对不起,这很长......
答案 0 :(得分:1)
这对你有什么用?
它确实使用了List::Util::max
,但这已经标准化了一段时间,如果你没有它,很容易自己编写。
use List::Util qw(max);
use strict;
use warnings;
my $ALLDATA = {
'Subj1' => {
'1' => [
'data1',
'data1',
],
'2' => [
'data2',
'data2',
],
'20' => [
'ON',
'ON',
'OFF',
]
},
'Subj2' => {
'1' => [
'data1',
'data1',
],
'2' => [
'data2',
'data2',
],
'20' => [
'ON',
'ON',
'ON',
'OFF',
'OFF',
]
},
};
sub num_ons_before_first_off
{
my $n = 0;
foreach(@_)
{
last if $_ eq 'OFF';
$n++;
}
return $n;
}
# store a 'numons' piece of data for each subject, for use later
foreach my $subject(values(%$ALLDATA))
{
$subject->{'numons'} = num_ons_before_first_off(@{$subject->{'20'}});
}
# calculate the max 'numons' across all subjects
my $max_ons = max(map { $_->{'numons'} } values(%$ALLDATA));
foreach my $k(keys(%$ALLDATA))
{
my $subject = $ALLDATA->{$k};
#output leading blank entries
print ',' x ($max_ons - $subject->{'numons'});
#output the real data
foreach my $data(@{$subject->{'20'}})
{
print "$data,";
}
print "\n";
}
希望显而易见的是如何将其扩展到数据输出的其余部分。
你的问题中是否需要间距? 你说它是CSV,所以我猜不是。如果这很重要,我可以更新。
答案 1 :(得分:0)
这不是答案,但不适合评论:
当你说你想'通过LIGHT中的ON / OFF列对齐所有数据'时,你的意思是对齐所有内容吗?
例如,如果您有这些数据:
Subj1,ON,ON,OFF,
Subj2,ON,ON,ON,OFF,OFF,
输出会是这个吗?
Subj1, , , ON, ON, OFF,
Subj2, ON, ON, ON, OFF, OFF,
或者你想要它是这样的:
Subj1, , ON, ON, OFF, , <-- Note trailing blank entry
Subj2, ON, ON, ON, OFF, OFF,
也就是说,将第一个“关闭”对齐,就像在文字描述中一样?
答案 2 :(得分:0)
知道了! “max”是那里的关键。 jwd,不知道为什么,但我无法调整你的脚本来处理数据(不断得到“不能使用字符串作为哈希引用,而严格”错误)。但它给了我所需的灵感。
在处理文件时,我实现了一个递增计数器,直到达到第一个OFF。这将作为键值对传递给哈希以及主题ID($ offset {$ id} = $ count)。
完成处理文件后,我将最大值拉出哈希值,然后使用从最大值中减去的原始键值重新定义值。
输出时,我使用您的代码作为基础添加额外的逗号来填充数据。最终相关部分如下所示:
my $max_off = max values %offset;
foreach my $k ( keys %offset ) {
$offset{$k} = $max_off - $offset{$k};
}
foreach my $k (sort {$a cmp $b} keys %data) {
print OUT $k, "\,";
print OUT ',' x ($offset{$k});
foreach my $d ( @{ $data{$k}{$i} } ) { print OUT $d, "\,"; }
print OUT "\n";
}
}
完全符合我的需要。谢谢你的建议!