รับจำนวนค่าที่ไม่ซ้ำกันในคอลัมน์ใน bash


98

ฉันมีไฟล์ที่คั่นด้วยแท็บที่มีหลายคอลัมน์ ฉันต้องการนับความถี่ของการเกิดค่าต่างๆในคอลัมน์สำหรับไฟล์ทั้งหมดในโฟลเดอร์และจัดเรียงตามลำดับการนับที่ลดลง (จำนวนสูงสุดก่อน) ฉันจะทำสิ่งนี้ให้สำเร็จในสภาพแวดล้อมบรรทัดคำสั่งของ Linux ได้อย่างไร

สามารถใช้ภาษาบรรทัดคำสั่งทั่วไปเช่น awk, perl, python เป็นต้น

คำตอบ:


156

หากต้องการดูจำนวนความถี่สำหรับคอลัมน์สอง (ตัวอย่าง):

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

ผลลัพธ์:

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

69

นี่คือวิธีการทำในเชลล์:

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

นี่คือสิ่งที่ bash นั้นยอดเยี่ยมมาก


24
"เรียง" ของ ... ar ar ar! :)
John Rix

3
Kinda sorta สิ่งที่ไม่เหมือนใคร : P (btw. ใช้-d,เพื่อคั่นฟิลด์ด้วยลูกน้ำหรือตัวคั่นอื่น ๆ )
cprn

4
ฉันใช้cut -f 1 -d ' '. ขอบคุณมาก. :)
Alfonso Nishikawa

8

เว็บไซต์ GNUบ่งชี้ว่านี่สคริปต์ awk ที่ดีซึ่งพิมพ์ทั้งสองคำและความถี่ของพวกเขา

การเปลี่ยนแปลงที่เป็นไปได้:

  • คุณสามารถไพพ์ผ่านsort -nr(และย้อนกลับwordและfreq[word]) เพื่อดูผลลัพธ์จากมากไปหาน้อย
  • หากคุณต้องการคอลัมน์เฉพาะคุณสามารถละเว้น for loop และเขียน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]
 }

2
สคริปต์ตัวอย่างที่ยอดเยี่ยม มันแสดงให้เห็นถึงความสามารถของ awk มากมาย
David Mann

สคริปต์นี้มีประโยชน์สำหรับฉันในการพิจารณาว่าแถวใดในสมุดงาน Excel ที่ฉันต้องใส่ใจจริงๆ :) (คัดลอกเนื้อหา Excel ไปยังไฟล์ข้อความใช้ awk และ voila! ฉันสามารถสร้างไฟล์รูปแบบสำหรับ grep -n ได้) .
Jubbles

6

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*

คำอธิบาย

ในระดับบนสุดในขณะที่วนซ้ำ:
* วนซ้ำแต่ละบรรทัดของไฟล์อินพุตที่รวมกัน
* แยกบรรทัดลงในอาร์เรย์ @Fields
* สำหรับทุกคอลัมน์ให้เพิ่มโครงสร้างข้อมูลอาร์เรย์ของแฮชผลลัพธ์

ในระดับบนสุดสำหรับลูป:
* วนซ้ำเหนืออาร์เรย์ผลลัพธ์
* พิมพ์หมายเลขคอลัมน์
* รับค่าที่ใช้ในคอลัมน์นั้น
* เรียงลำดับค่าตามจำนวนครั้งที่เกิดขึ้น
* การเรียงลำดับรองตามค่า (ตัวอย่างเช่น 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]}++};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

ทับทิม (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
สิ่งนี้น่าสนใจมากทั้งเพราะฉันใช้มันและมันได้ผลและเพราะฉันประหลาดใจที่ทับทิมน่าเกลียดขนาดไหน .. ฉันคิดว่าเพอร์ลแย่!
ryansstack

ในการป้องกันของทับทิมสิ่งนี้อาจทำให้เรียบร้อยขึ้น ตัวอย่างเช่นการใช้each_with_objectเหนือสิ่งอื่นใด ในระยะสั้นนี่เป็นการเขียนแบบลวก ๆ
Rambatino
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.