Nhận số lượng các giá trị duy nhất trong một cột trong bash


95

Tôi có các tệp được phân cách bằng tab với một số cột. Tôi muốn đếm tần suất xuất hiện của các giá trị khác nhau trong một cột cho tất cả các tệp trong một thư mục và sắp xếp chúng theo thứ tự số lượng giảm dần (số lượng cao nhất trước). Làm cách nào để thực hiện điều này trong môi trường dòng lệnh Linux?

Nó có thể sử dụng bất kỳ ngôn ngữ dòng lệnh phổ biến nào như awk, perl, python, v.v.

Câu trả lời:


152

Để xem số lượng tần suất cho cột hai (ví dụ):

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

fileA.txt

z    z    a
a    b    c
w    d    e

fileB.txt

t    r    e
z    d    a
a    g    c

fileC.txt

z    r    a
v    d    c
a    m    c

Kết quả:

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

68

Đây là một cách để làm điều đó trong shell:

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

Đây là loại điều mà bash rất tuyệt.


22
"Loại" điều ... ar ar ar! :)
John Rix

3
Kinda sắp xếp một điều độc đáo. : P (btw. Dùng -d,để phân cách các trường bằng dấu phẩy hoặc bất kỳ dấu phân cách nào khác).
cprn

4
Tôi đã sử dụng cut -f 1 -d ' '. Cảm ơn bạn rất nhiều. :)
Alfonso Nishikawa

8

Trang GNU gợi ý tập lệnh awk hay này, nó in cả các từ và tần số của chúng.

Những thay đổi có thể xảy ra:

  • Bạn có thể chuyển qua sort -nr(và đảo ngược wordfreq[word]) để xem kết quả theo thứ tự giảm dần.
  • Nếu bạn muốn một cột cụ thể, bạn có thể bỏ qua vòng lặp for và chỉ cần viết freq[3]++- thay thế 3 bằng số cột.

Đây là:

 # 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]
 }

2
Kịch bản ví dụ tuyệt vời. Nó thể hiện rất nhiều khả năng của awk.
David Mann

Tập lệnh này rất hữu ích để tôi xác định hàng nào trong sổ làm việc Excel mà tôi thực sự cần chú ý :) (đã sao chép nội dung Excel vào tệp văn bản, sử dụng awk và, thì đấy !, tôi có thể tạo tệp mẫu cho grep -n) .
Jubbles

6

Perl

Mã này tính toán các lần xuất hiện của tất cả các cột và in một báo cáo được sắp xếp cho từng cột trong số chúng:

# 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"
    }
}

Lưu văn bản dưới dạng giá trị column.pl
Chạy nó dưới dạng: perl columnvalues.pl files*

Giải trình

Trong vòng lặp while cấp cao nhất:
* Lặp lại từng dòng của tệp đầu vào được kết hợp
* Tách dòng thành mảng @Fields
* Đối với mỗi cột, hãy tăng cấu trúc dữ liệu mảng-của-băm kết quả

Trong vòng lặp for cấp cao nhất:
* Lặp lại mảng kết quả
* In số cột
* Lấy các giá trị được sử dụng trong cột đó
* Sắp xếp các giá trị theo số lần xuất hiện
* Sắp xếp thứ cấp dựa trên giá trị (ví dụ: b vs g vs m vs z)
* Lặp lại thông qua băm kết quả, sử dụng danh sách đã sắp xếp
* In giá trị và số của mỗi lần xuất hiện

Kết quả dựa trên các tệp đầu vào mẫu do @Dennis cung cấp

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

đầu vào .csv

Nếu tệp đầu vào của bạn là .csv, hãy thay đổi /\s+/thành/,/

Sự xáo trộn

Trong một cuộc thi xấu xí, Perl đặc biệt được trang bị tốt.
Một lớp lót này thực hiện tương tự:

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*

2

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

5
Điều này rất thú vị, cả vì tôi đã sử dụng nó và nó hoạt động, và cũng bởi vì tôi chỉ ngạc nhiên về việc ruby ​​xấu xí như thế nào .. Tôi đã nghĩ perl xấu!
ryansstack

Về khả năng bảo vệ của ruby, điều này có thể thực sự được cải thiện. Ví dụ, sử dụng each_with_object, trong số những thứ khác. Tóm lại, điều này được viết hơi thô thiển.
Rambatino
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.