获取bash中列中唯一值的计数
我有几列的制表符分隔的文件。 我想计算一个文件夹中所有文件的列中不同值的出现频率,并按照计数递减顺序(最高计数优先)进行sorting。 我将如何在Linux命令行环境中完成此操作?
它可以使用任何常见的命令行语言,如awk,perl,python等
要查看第二列的频率计数(例如):
awk -F '\t' '{print $2}' * | sort | uniq -c | sort -nr
fileA.txt
zza abc wde
fileB.txt
tre zda agc
fileC.txt
zra vdc amc
结果:
3 d 2 r 1 z 1 m 1 g 1 b
这是一个在shell中执行的方法:
FIELD=2 cut -f $FIELD * | sort| uniq -c |sort -nr
这就是bash所擅长的。
GNU网站提供了这个不错的awk脚本,它可以打印单词及其频率。
可能的变化:
- 您可以通过
sort -nr
(并反转word
和freq[word]
)来查看结果,以降序排列。 - 如果你想要一个特定的列,你可以省略for循环,并简单地写
freq[3]++
– 用列号replace3。
开始:
# 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] }
Perl的
此代码计算所有列的出现次数,并为其中的每一列打印sorting报告:
# 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循环中:
*循环组合input文件的每一行
*将行分割成@Fields数组
*对于每一列,递增结果数组散列数据结构
在顶级for循环中:
*循环结果数组
*打印列号
*获取该列中使用的值
*按出现次数sorting值
*根据数值进行二次sorting(例如b vs g vs m vs z)
*使用sorting列表遍历结果散列
*打印每个事件的值和数量
结果基于@Dennis提供的示例input文件
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
.csvinput
如果您的input文件是.csv,请将/\s+/
更改为/,/
困惑
在一个丑陋的比赛中,Perl的装备特别好。
这一行也是一样的:
perl -lane 'for $i (0..$#F){$g[$i]{$F[$i]}++};END{for $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*
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