免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2993 | 回复: 9
打印 上一主题 下一主题

[已解决,谢谢各位]请问如何用perl求行名相同列的平均值(含有很多列),谢谢 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-10-13 15:56 |只看该作者 |倒序浏览
本帖最后由 baiguihuajl 于 2015-10-14 13:59 编辑

请问如何求行名相同列的平均值(含有很多列),谢谢
比如文件1.txt
a        2        3        1        3        2        2
s        2        2        1        1        2        3
s        1        2        3        1        2        2
f        3        7        2        1        2        1
v        2        1        3        2        2        1
t        2        2        2        2        1        3
b        3        2        2        1        5        2
g        1        3        1        2        1        2
r        2        1        1        1        1        1
t        2        2        1        3        2        3
a        2        3        3        5        2        4
f        3        1        2        2        5        2
s        1        1        4        9        2        5
相同行名的列求平均的话就会得到2.txt:
a        2        3        2        4        2        3
s        1.33        1.67        2.67        3.67        2        3.33
f        3        4        2        1.5        3.5        1.5
v        2        1        3        2        2        1
t        2        2        1.5        2.5        1.5        3
b        3        2        2        1        5        2
g        1        3        1        2        1        2
r        2        1        1        1        1        1

论坛徽章:
7
巳蛇
日期:2013-11-28 09:22:59天秤座
日期:2014-10-25 15:40:452015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:53:172015亚冠之德黑兰石油
日期:2015-07-15 08:46:452015亚冠之平阳省
日期:2015-11-08 16:27:53白银圣斗士
日期:2015-11-14 09:58:12
2 [报告]
发表于 2015-10-13 18:00 |只看该作者
  1. #!/usr/bin/perl
  2. use strict;
  3. use Data::Dumper;

  4. my $data={};        #用来保存数据
  5. my $num={};                #用来保存出现次数
  6. my @keys=();        #用来记录出现顺序
  7. while(my $line=<DATA>){
  8.         my ($key,@values)=split /\s+/,$line;
  9.         if($data->{$key}){
  10.                 $num->{$key}++;
  11.                 my $val_num=scalar @{$data->{$key}};
  12.                 for (my $i=0;$i<$val_num;$i++){
  13.                         $data->{$key}->[$i]+=$values[$i];
  14.                 }
  15.         }else{
  16.                 $data->{$key}=\@values;
  17.                 $num->{$key}++;
  18.                 push @keys,$key;
  19.         }
  20. }

  21. foreach my $key(@keys){
  22.         my $val_num=scalar @{$data->{$key}};
  23.         print "$key\t";
  24.         for (my $i=0;$i<$val_num;$i++){
  25.                 my $val= ($data->{$key}->[$i]) / ($num->{$key});        #依据次数计算平均值
  26.                 my $mod=($data->{$key}->[$i]) % ($num->{$key});                #判断是否整除
  27.                 if($mod){
  28.                         printf "%-.2f\t",$val;
  29.                 }else{
  30.                         print "$val\t";
  31.                 }
  32.         }
  33.         print "\n";
  34. }

  35. __DATA__
  36. a        2        3        1        3        2        2
  37. s        2        2        1        1        2        3
  38. s        1        2        3        1        2        2
  39. f        3        7        2        1        2        1
  40. v        2        1        3        2        2        1
  41. t        2        2        2        2        1        3
  42. b        3        2        2        1        5        2
  43. g        1        3        1        2        1        2
  44. r        2        1        1        1        1        1
  45. t        2        2        1        3        2        3
  46. a        2        3        3        5        2        4
  47. f        3        1        2        2        5        2
  48. s        1        1        4        9        2        5
复制代码

论坛徽章:
307
程序设计版块每周发帖之星
日期:2016-04-08 00:41:33操作系统版块每日发帖之星
日期:2015-09-02 06:20:00每日论坛发贴之星
日期:2015-09-02 06:20:00程序设计版块每日发帖之星
日期:2015-09-04 06:20:00每日论坛发贴之星
日期:2015-09-04 06:20:00每周论坛发贴之星
日期:2015-09-06 22:22:00程序设计版块每日发帖之星
日期:2015-09-09 06:20:00程序设计版块每日发帖之星
日期:2015-09-19 06:20:00程序设计版块每日发帖之星
日期:2015-09-20 06:20:00每日论坛发贴之星
日期:2015-09-20 06:20:00程序设计版块每日发帖之星
日期:2015-09-22 06:20:00程序设计版块每日发帖之星
日期:2015-09-24 06:20:00
3 [报告]
发表于 2015-10-13 18:40 |只看该作者
本帖最后由 sunzhiguolu 于 2015-10-13 23:40 编辑

试下:

  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;

  4. my %h_keys;
  5. while (<>){
  6.    chomp;
  7.    my @a_line = split /\s+/;
  8.    my $id = shift @a_line;
  9.    if (exists $h_keys{$id}){
  10.       $h_keys{$id} .= ';' . "@a_line";
  11.    }else{
  12.       $h_keys{$id} = "@a_line";
  13.    }   
  14. }

  15. while (my ($id, $numbers) = each %h_keys){
  16.    my $cnt_rows = my @a_lines = split (/;/, $numbers);
  17.    if ($cnt_rows == 1){
  18.       print "$id $numbers\n";
  19.    }else{
  20.       print "$id";
  21.       my $cnt_cols = my @a_numbers = split /\s+/,(shift @a_lines);
  22.       foreach (@a_lines){
  23.          my @a_other_numbers = split /\s+/;
  24.          for (my $i = 0; $i < $cnt_cols; $i++){
  25.             $a_numbers[$i] += $a_other_numbers[$i];
  26.          }   
  27.       }   
  28.       for (my $i = 0; $i < $cnt_cols; $i++){
  29.          my $value = $a_numbers[$i];
  30.          $value % $cnt_rows == 0 ? printf " %d", $value / $cnt_rows : printf " %.2f", $value / $cnt_rows;
  31.       }   
  32.       print "\n";
  33.    }   
  34. }
复制代码

  1. perl abc.pl 1.txt > 2.txt
复制代码

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
4 [报告]
发表于 2015-10-13 21:14 |只看该作者
这种写法是不是太复杂?

#!/usr/bin/perl

use strict;
use warnings;

use v5.14;
use List::MoreUtils qw(pairwise);

my %rec;
while (<DATA>) {
  chomp;
  my ($key, @vals) = split;
  if ($rec{$key}) {
    $rec{$key} = [ pairwise { [ ++($a->[0]), $a->[1] += $b ] } @{ $rec{$key} }, @vals ];
  }
  else {
    $rec{$key} = [ map [1, $_], @vals ];
  }
}

while (my ($key, $vals) = each %rec) {
  say join "\t", ($key, map { $_->[1] / $_->[0] } @$vals);
}

__DATA__
a        2        3        1        3        2        2
s        2        2        1        1        2        3
s        1        2        3        1        2        2
f        3        7        2        1        2        1
v        2        1        3        2        2        1
t        2        2        2        2        1        3
b        3        2        2        1        5        2
g        1        3        1        2        1        2
r        2        1        1        1        1        1
t        2        2        1        3        2        3
a        2        3        3        5        2        4
f        3        1        2        2        5        2
s        1        1        4        9        2        5

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
5 [报告]
发表于 2015-10-13 21:50 |只看该作者
回复 4# MMMIX


   
利用 Perl 5.12 的新 each 和 autovivification,连 pairwise 都可以省了,代码可以更简洁,也更易懂:

#!/usr/bin/perl

use strict;
use warnings;

use v5.14;

my %rec;
while (<DATA>) {
  chomp;
  my ($key, @vals) = split;
  while (my ($i, $v) = each @vals) {
    $rec{$key}->[$i][0] += 1;
    $rec{$key}->[$i][1] += $v;
  }
}

while (my ($key, $vals) = each %rec) {
  say join "\t", ($key, map { $_->[1] / $_->[0] } @$vals);
}

__DATA__
a        2        3        1        3        2        2
s        2        2        1        1        2        3
s        1        2        3        1        2        2
f        3        7        2        1        2        1
v        2        1        3        2        2        1
t        2        2        2        2        1        3
b        3        2        2        1        5        2
g        1        3        1        2        1        2
r        2        1        1        1        1        1
t        2        2        1        3        2        3
a        2        3        3        5        2        4
f        3        1        2        2        5        2
s        1        1        4        9        2        5

论坛徽章:
0
6 [报告]
发表于 2015-10-14 17:05 |只看该作者
回复 5# MMMIX


    你好,关于这个题目 我在实现相加的时候为什么只有第一个元素相加了,而后面的没有,帮忙看下我的代码哪边出的问题,思考很久也没有解决,没有办法只能上来请教了。

#!/usr/bin/perl
use strict;
use Data:umper;

my %hash;
while(<DATA>{
        chomp;
        my($key,@vals)=split;
        if(!exists $hash{$key}){
                $hash{$key}[0]=\@vals;
                $hash{$key}[1]=1;
        }
        for(my $i=(0..$#vals)){
                        $hash{$key}[0][$i]+=$vals[$i];
                        $hash{$key}[1]++;
        }
}

print Dumper(%hash);

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
7 [报告]
发表于 2015-10-14 21:32 |只看该作者
回复 6# 815138698


    for 语句错了;还有这个 for 应该放在 else 里面:

my %hash;
while (<DATA>) {
  chomp;
  my ($key,@vals) = split;
  if (not exists $hash{$key}) {
    $hash{$key}[0] = \@vals;
    $hash{$key}[1] = 1;
  }
  else {
    for my $i (0 .. $#vals) {
      $hash{$key}[0][$i] += $vals[$i];
    }
    $hash{$key}[1] += 1;
  }
}

print Dumper(\%hash);


不过,上述代码可以简化为:

my %hash;
while (<DATA>) {
  chomp;
  my ($key,@vals) = split;
  while (my ($i, $v) = each @vals) {
    $hash{$key}[0][$i] += $v;
  }
  $hash{$key}[1] += 1;
}

print Dumper(\%hash);


论坛徽章:
0
8 [报告]
发表于 2015-10-15 10:38 |只看该作者
回复 7# MMMIX


    For的用法 没有掌握好  按照自己想的错误格式来写了,多谢指正~
    还有您提到的each array的用法 也是第一次见到  学习了  非常感谢~

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
9 [报告]
发表于 2015-10-15 12:21 |只看该作者
815138698 发表于 2015-10-15 10:38
回复 7# MMMIX

  还有您提到的each array的用法 也是第一次见到


Perl 5.12 的新特性。

论坛徽章:
0
10 [报告]
发表于 2015-10-15 12:29 |只看该作者
  1. use 5.010;

  2. my %data;

  3. while (<DATA>) {
  4.     my ( $name, @val ) = split;
  5.     $data{$name}[$_] += $val[$_] for 0 .. $#val;
  6.     $data{$name}[@val]++;
  7. }

  8. while ( my ( $name, $val ) = each %data ) {
  9.     my $count = pop @$val;
  10.     say join "\t", $name, map { sprintf "%.2f", $_ / $count } @$val;
  11. }

  12. __DATA__
  13. a        2        3        1        3        2        2
  14. s        2        2        1        1        2        3
  15. s        1        2        3        1        2        2
  16. f        3        7        2        1        2        1
  17. v        2        1        3        2        2        1
  18. t        2        2        2        2        1        3
  19. b        3        2        2        1        5        2
  20. g        1        3        1        2        1        2
  21. r        2        1        1        1        1        1
  22. t        2        2        1        3        2        3
  23. a        2        3        3        5        2        4
  24. f        3        1        2        2        5        2
  25. s        1        1        4        9        2        5
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP