获取bash中列中唯一值的计数

Posted

技术标签:

【中文标题】获取bash中列中唯一值的计数【英文标题】:Getting the count of unique values in a column in bash 【发布时间】:2011-06-22 18:06:31 【问题描述】:

我有包含几列的制表符分隔文件。我想计算文件夹中所有文件的列中不同值的出现频率,并按计数的递减顺序对它们进行排序(最高计数优先)。我将如何在 Linux 命令行环境中完成此操作?

它可以使用任何常用的命令行语言,如 awk、perl、python 等。

【问题讨论】:

【参考方案1】:

Perl

此代码计算所有列的出现次数,并为每个列打印一个排序报告:

# columnvalues.pl
while (<>) 
    @Fields = split /\s+/;
    for $i ( 0 .. $#Fields ) 
        $result[$i]$Fields[$i]++
    ;

for $j ( 0 .. $#result ) 
    print "column $j:\n";
    @values = keys %$result[$j];
    @sorted = sort  $result[$j]$b <=> $result[$j]$a  ||  $a cmp $b  @values;
    for $k ( @sorted ) 
        print " $k $result[$j]$k\n"
    

将文本另存为 columnvalues.pl 运行为:perl columnvalues.pl files*

说明

在顶层while循环中: * 循环遍历组合输入文件的每一行 * 将行拆分为@Fields 数组 * 对于每一列,递增结果数组哈希数据结构

在顶层 for 循环中: * 循环遍历结果数组 * 打印列号 * 获取该列中使用的值 * 按出现次数对值进行排序 * 基于值的二级排序(例如 b vs g vs m vs z) * 使用排序列表遍历结果哈希 * 打印每次出现的值和次数

基于@Dennis 提供的示例输入文件的结果

column 0:
 a 3
 z 3
 t 1
 v 1
 w 1
column 1:
 d 3
 r 2
 b 1
 g 1
 m 1
 z 1
column 2:
 c 4
 a 3
 e 2

.csv 输入

如果您的输入文件是 .csv,请将 /\s+/ 更改为 /,/

混淆

在一场丑陋的比赛中,Perl 装备精良。 这个单线做同样的事情:

perl -lane 'for $i (0..$#F)$g[$i]$F[$i]++;ENDfor $j (0..$#g)print "$j:";for $k (sort$g[$j]$b<=>$g[$j]$a||$a cmp $b keys %$g[$j])print " $k $g[$j]$k"' files*

【讨论】:

【参考方案2】:

这是在 shell 中执行此操作的一种方法:

FIELD=2
cut -f $FIELD * | sort| uniq -c |sort -nr

这是 bash 擅长的事情。

【讨论】:

事物的“排序”... ar ar ar! :) 有点独特的东西。 :P(顺便说一句。使用-d, 以逗号或任何其他分隔符分隔字段)。 我使用了cut -f 1 -d ' '。万分感谢。 :)【参考方案3】:

查看第二列的频率计数(例如):

awk -F '\t' 'print $2' * | sort | uniq -c | sort -nr

文件A.txt

z    z    a
a    b    c
w    d    e

文件B.txt

t    r    e
z    d    a
a    g    c

文件C.txt

z    r    a
v    d    c
a    m    c

结果:

  3 d
  2 r
  1 z
  1 m
  1 g
  1 b

【讨论】:

【参考方案4】:

Ruby(1.9+)

#!/usr/bin/env ruby
Dir["*"].each do |file|
    h=Hash.new(0)
    open(file).each do |row|
        row.chomp.split("\t").each do |w|
            h[ w ] += 1
        end
    end
    h.sort|a,b| b[1]<=>a[1] .each|x,y| print "#x:#y\n" 
end

【讨论】:

这很有趣,因为我使用了它并且它有效,还因为我对 ruby​​ 的丑陋感到惊讶.. 我认为 perl 很糟糕! 在 ruby​​ 的辩护中,这可以真正得到改善。例如,使用each_with_object 等。简而言之,这写得有些粗俗。【参考方案5】:

GNU site 建议使用这个不错的 awk 脚本,它可以打印单词及其频率。

可能的变化:

您可以通过管道通过sort -nr(以及反向wordfreq[word])以降序查看结果。 如果你想要一个特定的列,你可以省略 for 循环,只写 freq[3]++ - 用列号替换 3。

这里是:

 # wordfreq.awk --- print list of word frequencies

 
     $0 = tolower($0)    # remove case distinctions
     # remove punctuation
     gsub(/[^[:alnum:]_[:blank:]]/, "", $0)
     for (i = 1; i <= NF; i++)
         freq[$i]++
 

 END 
     for (word in freq)
         printf "%s\t%d\n", word, freq[word]
 

【讨论】:

很棒的示例脚本。它展示了 awk 的很多功能。 这个脚本有助于我确定我真正需要注意的 Excel 工作簿中的哪些行:) (将 Excel 内容复制到文本文件,使用 awk,瞧!,我可以grep -n) 的模式文件。

以上是关于获取bash中列中唯一值的计数的主要内容,如果未能解决你的问题,请参考以下文章

如何获取列中每个值的计数?

如何获取列中每个不同值的计数? [复制]

如何使用 Linq 获取列中每个不同值的计数

是否有任何其他选项可以从表中获取总计数和同一查询中列的不同计数?

Python开发---37pandas

在唯一列值的熊猫上应用计数器[重复]