如何从包含行中最大值的 CSV 文件中提取列名(标题)?

如何从包含行中最大值的 CSV 文件中提取列名(标题)?

我正在尝试使用 bash 脚本提取每行中具有最大值的列名称,即列标题值或第一行中同一列的值。我使用以下命令从 CSV 文件中的每一行中提取最大值,但无法找到如何打印其列名称以及最大值:

awk -F ',' '{max=$'$col1';for (i=1;i<=NF;i++) {if ($i > max){max=$i}};print " max: " max}' "$INPUT_PATH/tmp.csv" >>$INPUT_PATH/max1.csv

例子:

示例 CSV 数据:

col1,col2,col3,col4
1,5,2,6
4,0,1,2
1,2,0,0
0,0,7,0

期望的输出:

col4 6 2
col1 4 1
col2 2 2
col3 7 3

有没有办法在上面的命令中执行此操作,或者是否有更好的方法从 CSV 文件中提取所需的信息?

答案1

使用米勒(https://github.com/johnkerl/miller)并运行

 mlr --c2n merge-fields -a max -r "^[a-z]" -o value -k  then put '
  for (key, value in $*) {
    if (value == $value_max && key != "value_max") {
        $fieldName=key;
    }
}' then cut -f fieldName,value_max then reorder -f fieldName,value_max input.csv

你将会拥有

col4 6
col1 4
col2 2
col3 7

答案2

使用trdatamash:

tr , '\t' < file.csv | datamash -H max 1-4 | datamash transpose

输出:

max(col1)   4
max(col2)   5
max(col3)   7
max(col4)   6

笔记:

  • 如果不需要sed前导,可以用一些清理输出。max()

  • 如果列数不是特别已知,但肯定小于某个大数,请替换1-41-1000,并根据需要添加零。

  • 要获得准确的计数,请将 替换为4,$(head -1 file.csv | tr , ' ' | wc -w)或 (通过用POSIX壳)$(read x < file.csv; echo ${x##*l};)

    通过清理和精确计数,生成的丑陋代码将如下所示:

    tr , '\t' < file.csv | 
    datamash -H max 1-$(read x < file.csv; echo ${x##*l};) | 
    datamash transpose | sed 's/.*(\|)//g'
    

    输出:

    col1    4
    col2    5
    col3    7
    col4    6
    

答案3

mx=0如果记录中的所有字段均为负数,则设置初始值的解决方案将失败。设置为$1是安全的,然后字段可以像@Peter.O 一样循环。

只是为了好玩,这里有一个轻微的awk变体,它迭代head数组索引,而不是创建计数器和循环

awk -F',' '
  NR==1{split($0,head,FS); next}
  {x=1; for  (h in head) if ($h>$x) x=h;print head[x], $x }
' file

输出

col4 6
col1 4
col2 2
col3 7

答案4

CSV 的问题是它不能用普通的 shell 工具很好地解析。他们就是做得不好。它在微不足道的情况下可以完成,但实际上 - 脚本语言是完成这项工作的工具。

我会更perl个人地思考:

#!/usr/bin/env perl
use strict;
use warnings;
use Text::CSV;

my $csv = Text::CSV->new();

open ( my $input, "<", "your_file.csv" ) or die $!;
$csv->column_names( $csv->getline( $input ) );

while ( my $row = $csv->getline_hr( $input ) ) {
    my ( $highest, @rest ) = sort { $row->{$b} <=> $row->{$a} } keys %$row;
    print join( "\t", $highest, $row->{$highest} ), "\n";
}

如果用作输入:

first,second,third,fourth
1,3,4,5,
5,4,3,2,
1,1,4,1,

将打印:

fourth  5
first   5
third   4

相关内容