Awk-Skript mit falscher Ausgabe

8

Ich habe ein Problem mit dem awkSkript. Ich muss einen Bericht erstellen, der die niedrigste, höchste und durchschnittliche Punktzahl für jede Zuweisung in der Datendatei enthält. Der Name der Zuordnung befindet sich in column 3.

Eingabedaten sind:

Student,Catehory,Assignment,Score,Possible
Chelsey,Homework,H01,90,100
Chelsey,Homework,H02,89,100
Chelsey,Homework,H03,77,100
Chelsey,Homework,H04,80,100
Chelsey,Homework,H05,82,100
Chelsey,Homework,H06,84,100
Chelsey,Homework,H07,86,100
Chelsey,Lab,L01,91,100
Chelsey,Lab,L02,100,100
Chelsey,Lab,L03,100,100
Chelsey,Lab,L04,100,100
Chelsey,Lab,L05,96,100
Chelsey,Lab,L06,80,100
Chelsey,Lab,L07,81,100
Chelsey,Quiz,Q01,100,100
Chelsey,Quiz,Q02,100,100
Chelsey,Quiz,Q03,98,100
Chelsey,Quiz,Q04,93,100
Chelsey,Quiz,Q05,99,100
Chelsey,Quiz,Q06,88,100
Chelsey,Quiz,Q07,100,100
Chelsey,Final,FINAL,82,100
Chelsey,Survey,WS,5,5
Sam,Homework,H01,19,100
Sam,Homework,H02,82,100
Sam,Homework,H03,95,100
Sam,Homework,H04,46,100
Sam,Homework,H05,82,100
Sam,Homework,H06,97,100
Sam,Homework,H07,52,100
Sam,Lab,L01,41,100
Sam,Lab,L02,85,100
Sam,Lab,L03,99,100
Sam,Lab,L04,99,100
Sam,Lab,L05,0,100
Sam,Lab,L06,0,100
Sam,Lab,L07,0,100
Sam,Quiz,Q01,91,100
Sam,Quiz,Q02,85,100
Sam,Quiz,Q03,33,100
Sam,Quiz,Q04,64,100
Sam,Quiz,Q05,54,100
Sam,Quiz,Q06,95,100
Sam,Quiz,Q07,68,100
Sam,Final,FINAL,58,100
Sam,Survey,WS,5,5
Andrew,Homework,H01,25,100
Andrew,Homework,H02,47,100
Andrew,Homework,H03,85,100
Andrew,Homework,H04,65,100
Andrew,Homework,H05,54,100
Andrew,Homework,H06,58,100
Andrew,Homework,H07,52,100
Andrew,Lab,L01,87,100
Andrew,Lab,L02,45,100
Andrew,Lab,L03,92,100
Andrew,Lab,L04,48,100
Andrew,Lab,L05,42,100
Andrew,Lab,L06,99,100
Andrew,Lab,L07,86,100
Andrew,Quiz,Q01,25,100
Andrew,Quiz,Q02,84,100
Andrew,Quiz,Q03,59,100
Andrew,Quiz,Q04,93,100
Andrew,Quiz,Q05,85,100
Andrew,Quiz,Q06,94,100
Andrew,Quiz,Q07,58,100
Andrew,Final,FINAL,99,100
Andrew,Survey,WS,5,5
Ava,Homework,H01,55,100
Ava,Homework,H02,95,100
Ava,Homework,H03,84,100
Ava,Homework,H04,74,100
Ava,Homework,H05,95,100
Ava,Homework,H06,84,100
Ava,Homework,H07,55,100
Ava,Lab,L01,66,100
Ava,Lab,L02,77,100
Ava,Lab,L03,88,100
Ava,Lab,L04,99,100
Ava,Lab,L05,55,100
Ava,Lab,L06,66,100
Ava,Lab,L07,77,100
Ava,Quiz,Q01,88,100
Ava,Quiz,Q02,99,100
Ava,Quiz,Q03,44,100
Ava,Quiz,Q04,55,100
Ava,Quiz,Q05,66,100
Ava,Quiz,Q06,77,100
Ava,Quiz,Q07,88,100
Ava,Final,FINAL,99,100
Ava,Survey,WS,5,5
Shane,Homework,H01,50,100
Shane,Homework,H02,60,100
Shane,Homework,H03,70,100
Shane,Homework,H04,60,100
Shane,Homework,H05,70,100
Shane,Homework,H06,80,100
Shane,Homework,H07,90,100
Shane,Lab,L01,90,100
Shane,Lab,L02,0,100
Shane,Lab,L03,100,100
Shane,Lab,L04,50,100
Shane,Lab,L05,40,100
Shane,Lab,L06,60,100
Shane,Lab,L07,80,100
Shane,Quiz,Q01,70,100
Shane,Quiz,Q02,90,100
Shane,Quiz,Q03,100,100
Shane,Quiz,Q04,100,100
Shane,Quiz,Q05,80,100
Shane,Quiz,Q06,80,100
Shane,Quiz,Q07,80,100
Shane,Final,FINAL,90,100
Shane,Survey,WS,5,5

awk script :

BEGIN {
  FS=" *\\, *"
}

FNR>1 {
  min[$3]=(!($3 in min) || min[$3]> $4 )? $4 : min[$3]
  max[$3]=(max[$3]> $4)? max[$3] : $4
  cnt[$3]++
  sum[$3]+=$4
}
END {
  print "Name\tLow\tHigh\tAverage"
  for (i in cnt)
    printf("%s\t%d\t%d\t%.1f\n", i, min[i], max[i], sum[i]/cnt[i])

}

Erwartete Probenausgabe:

Name    Low     High    Average
Q06     77      95      86.80
L05     40      96      46.60
WS      5       5       5
Q07     58      100     78.80
L06     60      99      61
L07     77      86      64.80

Wenn ich das Skript ausführe, erhalte ich für alle Zuweisungen ein "Niedrig" von 0, was nicht korrekt ist. Wo gehe ich falsch? Bitte führen.

Pikaraider
quelle
Zeigen Sie hier Ihre Beispieldaten und Ihr Skript.
Karakfa
Bitte veröffentlichen Sie keine Bilder oder Links für Beispiele für Eingaben und erwartete Ausgaben. Bitten Sie Sie, diese als Text mit Code-Tags in Ihrer Frage zu veröffentlichen, und teilen Sie uns dies dann mit.
RavinderSingh13
Bereits von einem anderen Benutzer bearbeitet.
Pikaraider
Mit GNU awk erhalte ich die gleichen Ergebnisse aus Ihrem veröffentlichten Code wie aus meiner Datamash-Antwort, übrigens (nachdem die Zuordnungen in sortierter Reihenfolge anstatt zufällig gedruckt wurden). Ihre funktioniert gut.
Shawn
@Shawn, meinst du, das awk-Skript, das ich oben gepostet habe, funktioniert wie erwartet für dich? Wenn ich es ausführe, sehe ich für alle Zuweisungen ein "Niedrig" von 0. Können Sie bitte einen awk-Code freigeben, der die richtige Ausgabe erzeugt, damit ich meinen Fehler korrigieren kann?
Pikaraider

Antworten:

1

Sie können dies sicherlich mit awk tun, aber da Sie dieses Skript auch markiert haben, gehe ich davon aus, dass andere Tools eine Option sind. Für diese Art der Erfassung von Statistiken über in den Daten vorhandene Gruppen reduziert GNU Datamash den Job häufig auf einen einfachen Einzeiler . Zum Beispiel:

$ (echo Name,Low,High,Average; datamash --header-in -s -t, -g3 min 4 max 4 mean 4  < input.csv) | tr , '\t'
Name    Low     High    Average
FINAL   58      99      85.6
H01     19      90      47.8
H02     47      95      74.6
H03     70      95      82.2
H04     46      80      65
H05     54      95      76.6
H06     58      97      80.6
H07     52      90      67
L01     41      91      75
L02     0       100     61.4
L03     88      100     95.8
L04     48      100     79.2
L05     0       96      46.6
L06     0       99      61
L07     0       86      64.8
Q01     25      100     74.8
Q02     84      100     91.6
Q03     33      100     66.8
Q04     55      100     81
Q05     54      99      76.8
Q06     77      95      86.8
Q07     58      100     78.8
WS      5       5       5

Dies besagt, dass für jede Gruppe mit demselben Wert für die 3. Spalte ( -g3plus -szum Sortieren der Eingabe (eine Anforderung des Werkzeugs)) der einfachen CSV-Eingabe ( -t,) mit einem Header ( --header-in) das Minimum, Maximum und der Mittelwert von angezeigt werden die 4. Spalte. Es wird alles mit einem neuen Header versehen und weitergeleitet tr, um die Kommas in Tabulatoren umzuwandeln.

Shawn
quelle
1

Ihr Code funktioniert wie er ist mit GNU awk. Wenn Sie es jedoch mit der -tOption ausführen, vor nicht portierbaren Konstrukten zu warnen, erhalten Sie:

awk: foo.awk:6: warning: old awk does not support the keyword `in' except after `for'
awk: foo.awk:2: warning: old awk does not support regexps as value of `FS'

Wenn Sie das Skript mit einer anderen Implementierung von awk ausführen ( mawkin meinem Fall), erhalten Sie Nullen für die Spalte "Niedrig". Also, einige Verbesserungen am Skript:

BEGIN {
  FS=","
}

FNR>1 {
  min[$3]=(cnt[$3] == 0 || min[$3]> $4 )? $4 : min[$3]
  max[$3]=(max[$3]> $4)? max[$3] : $4
  cnt[$3]++
  sum[$3]+=$4
}
END {
  print "Name\tLow\tHigh\tAverage"
  PROCINFO["sorted_in"] = "@ind_str_asc" # gawk-ism for pretty output; ignored on other awks
  for (i in cnt)
    printf("%s\t%d\t%d\t%.1f\n", i, min[i], max[i], sum[i]/cnt[i])

}

und es funktioniert wie erwartet auch bei diesem anderen awk.

Die Änderungen:

  • Verwenden eines einfachen Kommas als Feldtrennzeichen anstelle eines regulären Ausdrucks.
  • Wenn Sie die min-Bedingung ändern, um sie beim ersten Mal auf den aktuellen Wert einzustellen, überprüfen Sie, ob sie cnt[$3]gleich 0 ist (was das erste Mal ist, weil dieser Wert in einer späteren Zeile erhöht wird), oder ob die Strom min ist größer als dieser Wert.
Shawn
quelle
Danke @Shawn. Funktioniert perfekt!
Pikaraider
Wenn Sie davon ausgehen, dass es auf Ihrem Computer installiert ist, führen Sie es gawkstattdessen aus, um die GNU-Version zu erhalten.
Shawn
1

ein anderer ähnlicher Ansatz

$ awk -F, 'NR==1 {print "name","low","high","average"; next} 
                 {k=$3; sum[k]+=$4; count[k]++}
     !(k in min) {min[k]=max[k]=$4} 
       min[k]>$4 {min[k]=$4} 
       max[k]<$4 {max[k]=$4}                    
       END       {for(k in min) print k,min[k],max[k],sum[k]/count[k]}' file | 
 column -t

name   low  high  average
Q06    77   95    86.8
L05    0    96    46.6
WS     5    5     5
Q07    58   100   78.8
L06    0    99    61
L07    0    86    64.8
H01    19   90    47.8
H02    47   95    74.6
H03    70   95    82.2
Karakfa
quelle