จะเรียงลำดับคอลัมน์ตามบรรทัดแรกได้อย่างไร


12

ฉันต้องการเรียงลำดับคอลัมน์ของชุดข้อมูลที่มีขนาดใหญ่มาก (1,000 บรรทัดและ 700,000 คอลัมน์) ตัวอย่างเช่นคอลัมน์ของฉันถูกจัดเรียงแบบสุ่มเช่น: col1 col4 col3 col2 และฉันต้องเรียงลำดับนั้น

ฉันลองใช้คำสั่งแล้ว แต่ไม่ประสบความสำเร็จ

ตัวอย่าง:

ID M2 M5 M8 M1 M3 M9 .....M7000000
Animal1 1 0 2 1 0 2 .....1
Animal2 0 1 2 0 1 1 .....0
Animal3 2 1 0 1 2 1 .....0
.
.
.
.
Animaln

ในตัวอย่างนี้จุดหมายความว่าฉันมีคอลัมน์และเส้นจำนวนมาก อีกครั้งฉันต้องเรียงลำดับคอลัมน์ให้เป็นเช่น:

ID M1 M2 M3 M4 M5 M6 .....M7000000
Animal1 1 0 2 1 0 2 .....1
Animal2 0 1 2 0 1 1 .....0
Animal3 2 1 0 1 2 1 .....0
.
.
.
.
Animaln

ขอบคุณ


คุณสามารถเพิ่มตัวอย่างด้วยชุดข้อมูลสองสามบรรทัดได้หรือไม่?
jcbermu

ผลลัพธ์ที่คาดหวังของคุณมีการเรียงบรรทัดแรกเท่านั้นค่าอื่น ๆ ยังคงเหมือนเดิมเพราะอะไร
RomanPerekhrest

ที่จริงแล้วมันจำเป็นต้องปฏิบัติตามคอลัมน์เป็นความผิดพลาดของตัวอย่าง ขออภัย
LLVerardo

ต้องการเรียงลำดับคอลัมน์ทั้งหมดตามบรรทัดแรก
LLVerardo

2
ไขว้เรียงตามคอลัมน์แรกเปลี่ยนกลับ
Satō Katsura

คำตอบ:


10

ด้วย GNU datamashและ GNU sort:

datamash transpose -t ' ' -H <file_in.csv | sort -V | datamash transpose -t ' ' -H >file_out.csv

ใช้งานได้ดีกับข้อมูล "มีขนาดเล็กพอสมควร" อาจหรืออาจจะไม่ทำงานกับไฟล์ของคุณ

แก้ไข:โซลูชันด้านล่างที่ไม่มีการแปลงสัญญาณควรใช้ทรัพยากรน้อย


1
คำสั่งอาร์เอสอาจจะเป็นทางเลือกที่เบาdatamashเช่นrs -T < file_in.csv | sort | rs -T -C' '( rsควรจะมีเป็นแพคเกจในระบบ Debian-based)
steeldriver

2
FWIW, rs("reshape a data array") มีอยู่ในระบบพื้นฐานของ BSD บางตัว
Kusalananda

6
perl -pale '
   $. == 1 and
   @I = map  { $_->[1] }
        sort { $a->[0] <=> $b->[0] }
        map  { [ $F[$_] =~ /^M(\d+)$/, $_ ] } 1..$#F;
   $_ = "@F[0, @I]";
' yourlargefile

  1. สำหรับบรรทัดแรกเราตัวเลขเรียงเป็น 2 ... สุดท้ายคอลัมน์โดยใช้ส่วนที่เป็นตัวเลขของพวกเขาหลังจากหลักที่เกิดขึ้นในการเริ่มต้นใช้ที่รู้จักกันดีM Schwartzian maneuverสิ่งนี้ทำให้เรามีดัชนีที่เรียงลำดับใหม่เพื่อให้คอลัมน์ออกมาเรียงตามตัวเลข (M1, M2, M3, ... )
  2. สิ่งที่เหลืออยู่ก็คือการใช้ดัชนีเหล่านี้ที่มาจาก@Iเพื่อจัดเรียง@Fองค์ประกอบใหม่
  3. การกำหนดอาร์เรย์ในรูปแบบเครื่องหมายอัญประกาศคู่จะแปลงให้เป็นสตริงโดยแยกพื้นที่องค์ประกอบออก
  4. -pตัวเลือกที่จะช่วยให้ Perl AutoPrint ของ$_เนื้อหาจะเพิ่ม-lnewline

6

การใช้โมดูล Perl เรียง :: โดยธรรมชาติ

ข้อมูลอินพุต

ID M2 M5 M8 M1 M3 M9 M700000
A1 m1,2 m1,5 m1,8 m1,1 m1,3 m1,9 m1,7000000
A2 m2,2 m2,5 m2,8 m2,1 m2,3 m2,9 m2,7000000
A3 m3,2 m3,5 m3,8 m3,1 m3,3 m3,9 m3,7000000
A1000 m1000,2 m1000,5 m1000,8 m1000,1 m1000,3 m1000,9 m1000,7000000
perl -MSort::Naturally -lane '
  if ($. == 1) {
    @indices = (0, map  { $_->[0] }
                   sort { ncmp($a->[1], $b->[1]) }
                   map  { [$_, $F[$_]] }
                   1..$#F
               );
    $, = " ";
  }
  print @F[@indices]
' test.data

เอาท์พุต

ID M1 M2 M3 M5 M8 M9 M700000
A1 m1,1 m1,2 m1,3 m1,5 m1,8 m1,9 m1,7000000
A2 m2,1 m2,2 m2,3 m2,5 m2,8 m2,9 m2,7000000
A3 m3,1 m3,2 m3,3 m3,5 m3,8 m3,9 m3,7000000
A1000 m1000,1 m1000,2 m1000,3 m1000,5 m1000,8 m1000,9 m1000,7000000

+1 สำหรับสง่างามที่สุดไม่ถือว่าคำนำหน้าเฉพาะเจาะจงมากเกินไปสำหรับชื่อคอลัมน์โซลูชันหนึ่งผ่าน
arielf

4

หากคุณติดตั้งrsยูทิลิตี้คุณสามารถทำสิ่งนี้:

rs -c' ' -T | {
    stdbuf -i0 sed "1q"
    sort -V
} | rs -C' ' -T

หรือทั้งหมดในบรรทัดเดียว:

rs -c' ' -T | { stdbuf -i0 sed "1q"; sort -V ; } | rs -C' ' -T
  • การrsแปลงข้อมูลอินพุตครั้งแรก(ด้วยช่องว่างที่มีช่องว่าง)
  • กลุ่มคำสั่ง:
    • sedอ่านบรรทัดแรกออกผลลัพธ์จากนั้นออกจากส่วนที่เหลือของไปป์จากการrsแตะต้อง stdbufจำเป็นเพื่อให้แน่ใจว่าsedอ่านได้ถึงบรรทัดใหม่แรกเท่านั้นและไม่เพิ่มอีกโดยปิดการบัฟเฟอร์ข้อมูล
    • sorts บรรทัดที่เหลือ
  • ครั้งที่สองrsเปลี่ยนกระแสข้อมูลผลลัพธ์กลับเป็นรูปแบบดั้งเดิม

rsติดตั้งโดยค่าเริ่มต้นใน MacOS ในระบบ Linux คุณอาจต้องติดตั้ง -

sudo apt install rs

ข้อแม้: stdbufและตัวเลือกsorts -Vเป็นเฉพาะ GNU ดังนั้นจะไม่ทำงานบน MacOS ที่ไม่ได้แก้ไข


0

หากคุณมี GNU awkคุณสามารถลอง:

NR == 1 {
    for (i = 2; i <= NF; i++) {
        columns[substr($i, 2)] = i;
    }
    count = asorti(columns, sorted, "@ind_num_asc");
    printf("%s", $1);
    for (i = 1; i <= count; i++) {
        printf(" M%s", sorted[i]);
        indx[i] = columns[sorted[i]];
    }
    print "";
    next;
}
{
    printf("%s", $1);
    for (i = 1; i <= count; i++) {
        printf(" %s", $(indx[i]));
    }
    print "";
}

0

ใน Python:

from csv import DictReader, DictWriter
with open('in_file.csv') as infile, open('out_file.csv') as outfile:
  reader = DictReader(infile)
  writer = DictReader(outfile, fieldnames=sorted(reader.fieldnames))
  writer.writerows(reader)

0

ฉันไม่รู้ว่าคุณคิดว่านี่เป็นคำตอบที่ดีหรือไม่ แต่ ...

ทำไมคุณไม่ใช้ฐานข้อมูลเพื่อแก้ไขปัญหานี้ คุณสามารถนำเข้าชุดข้อมูลของคุณเป็นตารางชั่วคราวจากนั้นทำ

เลือกคอลัมน์ 1, คอลัมน์ 2, ... คอลัมน์ -n จาก my_temp_table

คุณสามารถใช้ตัวกรองอื่นหรือการแปลงตามที่คุณต้องการ จากนั้นคุณสามารถจัดรูปแบบผลลัพธ์ของคุณได้ตามต้องการ

งานทั้งหมดนี้สามารถตั้งโปรแกรมเป็นสคริปต์ทุบตีและเอาท์พุทผูกมัดโดยใช้ท่อ

บางครั้งฉันใช้คำสั่ง "pv" เพื่อดูความคืบหน้าของเอาต์พุตระหว่างคำสั่ง

ในการนำเข้าชุดข้อมูลคุณสามารถตั้งโปรแกรม ETL โดยใช้ Pentaho Data Integration


0

บางทีนี่อาจช่วยคุณได้

  1. ขั้นแรกคุณสามารถใช้แปลงไฟล์ของคุณ (หนึ่งใน/programming/1729824/an-efficient-way-to-transpose-a-file-in-bash )
  2. เรียงลำดับคอลัมน์แรกด้วยคำสั่ง sort
  3. ไขว้อีกครั้ง

Ex:

$ echo "ID M2 M5 M8 M1 M3 M9 .....M7000000
Animal1 1 0 2 1 0 2 .....1
Animal2 0 1 2 0 1 1 .....0
Animal3 2 1 0 1 2 1 .....0
.
.
.
.
Animaln" | awk '
{ 
    for (i=1; i<=NF; i++)  {
        a[NR,i] = $i
    }
}
NF>p { p = NF }
END {    
    for(j=1; j<=p; j++) {
        str=a[1,j]
        for(i=2; i<=NR; i++){
            str=str" "a[i,j];
        }
        print str
    }
}' | sort -n | awk '
{ 
    for (i=1; i<=NF; i++)  {
        a[NR,i] = $i
    }
}
NF>p { p = NF }
END {    
    for(j=1; j<=p; j++) {
        str=a[1,j]
        for(i=2; i<=NR; i++){
            str=str" "a[i,j];
        }
        print str
    }
}'
ID M1 M2 M3 M5 .....M7000000 M8 M9
Animal1 1 1 0 0 .....1 2 2
Animal2 0 0 1 1 .....0 2 1
Animal3 1 2 2 1 .....0 0 1
.       
.       
.       
.       
Animaln    
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.