0

我已经构建了几个脚本来组织测试设备的数据输出,但我遇到了这个心理障碍。

测试设备监控来自多个受试者(具有标识符 ID1、ID2 等)的四种类型的输入(Data1、Data2、Data3、Data4),并以日期和时间戳为间隔记录每一种输入。设备转储的 CSV 文件组织如下:

Start,Date,Time0
Subject,ID1,ID2,[...],ID#

Date,Time1
Data1,aa1,aa2,[...],aa#
Data2,ba1,ba2,[...],ba#
Data3,ca1,ca2,[...],ca#
Data4,da1,da2,[...],da#

Date,Time2
Data1,ab1,ab2,[...],ab#
Data2,bb1,bb2,[...],bb#
Data3,cb1,cb2,[...],cb#
Data4,db1,db2,[...],db#

...等等。

“开始”将此行标识为数据的开头;“主题”将该行标识为包含主题 ID 的行;“Data1”-“Data4”将该行标识为包含该数据类型的数据的行,该数据类型在前面的日期和时间指示的特定时间间隔内。

因此,输出数据被分成多个块,这对于设备制造商来说确实是一个不幸的选择,尤其是在几天或几周内每隔几分钟收集一次数据时。要分析数据而不必手动选择每 6 行,我们需要将所有数据类型分组到块中,如下所示:

Data1,Subject,ID1,ID2,[...],ID#
Date,Time1,aa1,aa2,[...],aa#
Date,Time2,ab1,ab2,[...],ab#
...

Data2,Subject,ID1,ID2,[...],ID#
Date,Time1,ba1,ba2,[...],ba#
Date,Time2,bb1,bb2,[...],bb#
...

目标是将四种数据类型中的每一种都放在单独的块中,以便任何给定主题(ID1 到 ID#)的时间课程数据将位于单个列中,日期和时间作为初始列。(上面的“DataX”和“Subject”只是简单地用作列标题。)

目前我通过将每一行放入一个单独的数组来做到这一点。这是一种快速而肮脏的完成工作的方式。该脚本获取时间和日期,并将 ID 行推入四个数组中的每一个(每种数据类型一个),然后根据数据类型依次添加每个数据行。输出只是逐行打印每个数组,添加一个空白行,然后打印下一个数组。这可行,但理想情况下,我想按主题 ID 对数据列进行排序,然后打印出数据,而不会丢失按日期和时间戳进行的垂直排序。(因为数据已经垂直排序,所以我目前在打印之前对数组没有排序功能。)

最简单的方法是什么?在精神上,我在尝试解析如何将 Y 行、X 列中的数据与 CSV 文件中 X 列中的主题 ID 相关联时遇到了麻烦。我使用的所有其他数据输出文件要么将主题 ID 作为每行中的第一项,要么每个主题有一个文件,这样更容易。

注意:因为时间/日期在他们自己的行上,我为每个使用一个变量;如果脚本检测到包含新时间和/或日期的行,它会更新变量值。

编辑——我采纳了 Borodin 的一些建议(让 FH 按行而不是按段落处理)。我将主题行中的数据拉入一个数组(@ids),并使用日期/时间和 ID 作为键将数据行推入散列:

my ($datatype, @fields) = @line;
push @keys, $datatype unless exists $data{$datatype};
my $datetime = "$date\,$time";
push @timestamps, $datetime unless exists $data{$datetime};
for my $i ( 0 .. $#fields) {
    push @{$data{$datetime}{$ids[$i]}}=>$fields[$i]
    };

我还将日期时间对放入第二个数组以维护顺序(@timestamps)。此时的问题是我在将值打印出来时遇到问题。目前正在尝试:

    foreach my $date (keys %data) {
    print OUT $date;
    foreach my $id (@ids) {
        foreach my $s (keys %{$data{$date}}) {
            if ( exists($data{$date}{$id}) ) {
                print OUT ",", $data{$date}{$id}
                }
            else {
                print OUT ",";
                }
            }
        }
    print OUT "\n"; # close printing on a given date
    }

继续获取垃圾输出(打印哈希引用,而不是实际值!)。Dumper 输出如下所示:

$VAR1 = {
    'date,time' => [
                    'ID1' => [
                            '0.00'
                            ]
                    'ID2' => [
                            '0.12',
                            ]
                    'ID3' => [
                            '0.17',
                            ]
                    'ID4' => [
                            '0.22',
                            ]
                    ]
            }
    };

打印输出是这样的:

date,time,ARRAY(0x7f91c1030f60),ARRAY(0x7f91c1030f60),ARRAY(0x7f91c1030f60),ARRAY(0x7f91c1030f60)

抱歉,到目前为止的示例一直在解释上造成问题。输入文件中有很多多余的数据和文本,我只包含了我试图提取和排序的部分的高度简化版本。

4

2 回答 2

1

该程序将所有数据读入散列并以您需要的转换状态再现它。这很好,除非数据非常庞大并且不容易放入您可用的内存中,在这种情况下您将需要不同的解决方案。

该程序需要输入文件的名称作为命令行参数,data.csv如果没有提供,则默认为。它设置$/为空字符串以启用 Perl 的“段落模式”输入,其中数据被读取到下一个空白行或文件末尾。这意味着一次读取给定时间间隔的所有数据,并且在处理之前必须进一步拆分为单独的行。

use strict;
use warnings;

my ($subject, @ids);
my @sort_order;
my (%data, @keys);

my ($file) = @ARGV;
$file //= 'data.csv';

open my $fh, '<', $file or die qq{Unable to open file "$file" for reading: $!};
local $/ = '';
while (<$fh>) {

  my @rows = split /\n/;

  unless ($subject) {
    ($subject, @ids) = split /,/, $rows[1];
    @sort_order = sort { $ids[$a] cmp $ids[$b] } 0 .. $#ids;
    next;
  }

  my ($date, $time) = split /,/, shift @rows;
  for (@rows) {
    my ($id, @fields) = split /,/;
    push @keys, $id unless exists $data{$id};
    push @{ $data{$id} }, [$date, $time, @fields[@sort_order]];
  }
}

for my $key (@keys) {
  print join(',', $key, $subject, @ids[@sort_order]), "\n";
  print join(',', @$_), "\n" for @{ $data{$key} };
  print "\n";
}

输出

Data1,Subject,ID#,ID1,ID2,[...]
Date,Time1,aa#,aa1,aa2,[...]
Date,Time2,ab#,ab1,ab2,[...]

Data2,Subject,ID#,ID1,ID2,[...]
Date,Time1,ba#,ba1,ba2,[...]
Date,Time2,bb#,bb1,bb2,[...]

Data3,Subject,ID#,ID1,ID2,[...]
Date,Time1,ca#,ca1,ca2,[...]
Date,Time2,cb#,cb1,cb2,[...]

Data4,Subject,ID#,ID1,ID2,[...]
Date,Time1,da#,da1,da2,[...]
Date,Time2,db#,db1,db2,[...]
于 2013-04-24T17:46:44.217 回答
0

您是否考虑过将数据放入 SQL 数据库中?[例如“少服务器”SQLite]

这可能有点矫枉过正,但它应该为您提供更好的大数据集灵活性。

于 2013-04-25T11:26:41.577 回答