【问题标题】:average a column of a .csv file that includes floating point numbers with bash or perl使用 bash 或 perl 平均包含浮点数的 .csv 文件的列
【发布时间】:2013-04-09 12:16:04
【问题描述】:

我有几千个包含此类数据的文件:

bash$ cat somefile0001.csv
col1;col2;col3; ..... ;col10
2.34;0.19;6.40; ..... ;4.20
3.8;2.45;2.20; ..... ;5.09E+003   

基本上,它是一个 10x301 的 feild .csv 文件,在顶部包含一个由分号分隔的头文件(为简洁起见,不包括孔的东西)。

所以我的目标是将科学记数法更改为十进制数,将所有列平均在一起,然后将列标题与列平均值一起输出到一个新的 csv 文件中,然后再到数千个文件中。

我已经有工作代码来解析所有文件,但我似乎无法获得让平均值起作用的部分

 #!/bin/bash
 filename=csvfile.csv
 i=1
      runningsum=0
      echo ""> $filename.tmp.$i
      tmptrnfrm=$(cut -f$i -d ';' $filename)
      tmpfilehold=$filename.tmp.$i
      echo "$tmptrnfrm" >> $tmpfilehold
      trnsfrmcount=0

      for j in $(cat $tmpfilehold)
      do
           if [[ $trnsfrmcount = 0 ]]]
           then
                echo -n "Iteration $trnsfrmcount:"
                echo "$j" #>> $tmpfilehold
                trnsfrmcount=$[$trnsfrmcount+1]
           elif [[ $trnsfrmcount < 301 ]]
           then
                if [[ $(echo $j | sed 's/[0-9].[0-9][0-9]E+[0-9]/arbitrarystring/' ) == arbitrarystring ]]
                then
                     tempj=$(printf "%0f" $j)
                     runningsum=$(echo '$runningsum + $tempj' | bc)
                     echo "$j" #>> tmpfilehold
                     trnsfrmcount=$[$trnsfrmcount+1]
                else
                     echo "preruns: $runningsum"
                     runningsum=$(echo '$runningsum + $j' | bc)
                     echo "$j," #>> $tmpfilehold
                     echo "the running sum is: $runningsum"
                     trnsfrmcount=$[$trnsfrmcount+1]
                fi
           fi
      done
 totalz=$(echo '$runningsum / 300' | bc)
 echo "here is the total"
 echo "$totalz"

 exit 0

我知道这有点乱,我在标准输出中添加了很多额外的字符串,以查看运行时发生了什么。我想在 perl 中执行此操作,但我只是在学习并知道这可以使用 bash 来完成,而且我无法访问 CSV 模块,也无法安装它(否则它可能真的很容易)。

非常感谢任何帮助。

【问题讨论】:

    标签: perl bash parsing csv command-line-interface


    【解决方案1】:

    这是一个基本的 perl 脚本,它应该可以满足您的需求。我没有测试过。

    #!/usr/bin/perl 
    use strict;
    use warnings;
    
    my $infile = shift;
    my $outfile = shift || $infile . ".new";
    
    my $header = "";
    my $count  = 0;
    my @sums   = ();
    my @means  = ();
    
    open my $fin, '<', $infile or die $!;
    
    $header = <$fin>;
    @sums = map { 0 } split ";", $header;    # to initialize @sums;
    
    while ( my $line = <$fin> ) {
        chomp $line;
    
        my @fields = split ";", $line;
        for ( my $i = 0 ; $i < scalar @fields ; $i++ ) {
    
            # use sprintf to convert to decimal notation
            # if we think we are using scientific notation
            if ( $fields[$i] =~ m/E/i ) {
                $sums[$i] += sprintf( "%.2f", $fields[$i] );
            } else {
                $sums[$i] += $fields[$i];
            }
        }
    
        $count++;
    }
    
    close $fin;
    
    exit 1 if $count == 0;
    
    # calculate averages
    @means = map { sprintf( "%.2f", $_ / $count ) } @sums;
    
    # intentionally left out writing to a file
    print $header;
    print join( ";", @means ) . "\n";
    

    【讨论】:

    • 感谢您的帮助。过了一会儿,我能够跟随并修改它(只是输入输出处理)来做我需要的事情。我真的被卡住了,再次感谢。
    【解决方案2】:

    Tabulator 是一组 unix 命令行工具,用于处理带有标题行的分隔文件。下面是一个计算前三列平均值的示例:

    tblred -d';' -su -c'avg1_col=avg(col1),avg_col2=avg(col2)' somefile00001.csv

    生产

    avg1_col;avg_col2
    3.07;1.32
    

    【讨论】:

      猜你喜欢
      • 2015-03-31
      • 1970-01-01
      • 2014-09-19
      • 2020-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多