如何逐列读取CSV文件以进行转置?

时间:2012-08-13 14:48:27

标签: perl csv large-files transpose

我有以下格式的数据集:

snp,T2DG0200001,T2DG0200002,T2DG0200003,T2DG0200004
3_60162,AA,AA,AA,AA
3_61495,AA,AA,GA,GA
3_61466,GG,GG,CG,CG

真实数据比这大得多,扩展到数百万行和大约一千列。我的最终目标是转换这个怪物并将结果输出到文本文件(或CSV文件或其他任何内容,无关紧要)。

我需要将数据一块一块地提供给我的电脑,以免让我的记忆过载。我逐行读取CSV文件,然后转置它,并写入文件。然后我循环回来重复这些步骤,在我去的时候附加到文本文件中。

问题当然是,如果结果是原始数据文件的转置,我应该按列而不是按行追加文本文件列。但是一位朋友告诉我,在Perl代码中这是不可行的。我想知道我是否可以逐列读取数据。是否有类似的内容,例如我在原始代码中使用的getline method

while (my $row = $csv->getline ($fh)) {

可以返回列而不是行吗?如果不需要将整个数据加载到内存中,那么类似于Unix cut命令的东西将是首选。

2 个答案:

答案 0 :(得分:1)

CSV只是一个文本文件;它由一长串大的文本字符组成,因此没有随机访问列。理想情况下,您可以将CSV放入数据库,然后可以直接执行此操作。

但是,除此之外,我相信你可以在Perl中做一点聪明。我的方法是这样的:

my @filehandles;
my $line = 0;    

while (my $row = $csv->getline ($fh)<FILE>)
{
   #open an output file for each column!
   if (not defined $filehandles[0])
   {
       for (0..$#$row)
       {
           local $handle;
           open $handle, ">column_$_.txt" or die "Oops!";
           push @filehandles, $handle;
       }
   }

   #print each column to its respective output file.
   for (0..$#$row)
   {
       print $filehandles[$_] $row->[$_] . ",";
   }

   #This is going to take a LONG time, so show some sign of life.
   print '.' if (($line++ % 1000) == 0);
}

最后,每列将在其自己的文本文件中作为一行打印。不要忘记关闭所有文件,然后再次打开它们进行读取,然后一次将它们写入一个输出文件中。我的猜测是,这会很慢,但速度足以达到数百万行,只要你不经常这样做。并且它不会面临记忆限制。

答案 1 :(得分:0)

如果文件不适合您的计算机内存,您的程序必须多次读取它。没有其他办法了。

可能有些模块会隐藏或隐藏这个事实 - 比如DBD :: CSV - 但那些只是在幕后做同样的工作。