J'ai des fichiers délimités par des tabulations avec plusieurs colonnes. Je souhaite compter la fréquence d'apparition des différentes valeurs d'une colonne pour tous les fichiers d'un dossier et les trier par ordre décroissant de nombre (le nombre le plus élevé en premier). Comment pourrais-je accomplir cela dans un environnement de ligne de commande Linux?
Il peut utiliser n’importe quel langage de ligne de commande courant comme awk, Perl, python etc.).
Pour voir un nombre de fréquences pour la colonne deux (par exemple):
awk -F '\t' '{print $2}' * | sort | uniq -c | sort -nr
fileA.txt
z z a
a b c
w d e
fichierB.txt
t r e
z d a
a g c
fichierC.txt
z r a
v d c
a m c
Résultat:
3 d
2 r
1 z
1 m
1 g
1 b
Voici un moyen de le faire dans la coquille:
FIELD=2
cut -f $FIELD * | sort| uniq -c |sort -nr
C'est le genre de chose que bash est génial.
Le site GN suggère ce script de Nice awk, qui affiche à la fois les mots et leur fréquence.
Changements possibles:
sort -nr
(et inverser Word
et freq[Word]
) pour voir le résultat en ordre décroissant.freq[3]++
_ - remplacez 3 par le numéro de colonne.Voici:
# 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]
}
Ce code calcule les occurrences de toutes colonnes et affiche un rapport trié pour chacune d'entre elles:
# 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"
}
}
Enregistrez le texte sous columnvalues.pl
Exécutez-le comme: Perl columnvalues.pl files*
Au niveau supérieur de la boucle while:
* Boucle sur chaque ligne des fichiers d'entrée combinés
* Fractionner la ligne dans le tableau @Fields
* Pour chaque colonne, incrémentez la structure de données du tableau de hachages résultant
Au niveau supérieur de la boucle:
* Boucle sur le tableau de résultats
* Imprimer le numéro de colonne
* Obtenir les valeurs utilisées dans cette colonne
* Trier les valeurs en fonction du nombre d'occurrences
* Tri secondaire basé sur la valeur (par exemple b vs g vs m vs z)
* Parcourez le résultat en utilisant la liste triée
* Imprimer la valeur et le nombre de chaque occurrence
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
Si vos fichiers d’entrée sont au format .csv, changez /\s+/
à /,/
Dans un vilain concours, Perl est particulièrement bien équipé.
Ce one-liner fait la même chose:
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*
Rubis (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