Kịch bản Awk hiển thị đầu ra không chính xác


8

Tôi đang đối mặt với một vấn đề trong awktập lệnh - Tôi cần tạo một báo cáo chứa điểm thấp nhất, cao nhất và trung bình cho mỗi bài tập trong tệp dữ liệu. Tên của bài tập được đặt trong column 3.

Dữ liệu đầu vào là:

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

kịch bản awk :

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])

}

Sản lượng mẫu dự kiến:

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

Khi tôi chạy tập lệnh, tôi nhận được "Thấp" là 0 cho tất cả các bài tập không đúng. Tôi làm sai ở đâu? Xin hướng dẫn.


hiển thị dữ liệu mẫu và tập lệnh của bạn ở đây.
karakfa

Vui lòng kiềm chế đăng hình ảnh hoặc liên kết cho các mẫu đầu vào và đầu ra dự kiến, yêu cầu bạn vui lòng đăng chúng dưới dạng văn bản với các thẻ mã trong câu hỏi của bạn và sau đó cho chúng tôi biết.
RavinderSingh13

Đã được chỉnh sửa bởi người dùng khác.
pikaraider

Sử dụng GNU awk, tôi nhận được kết quả tương tự từ mã được đăng của bạn giống như tôi làm từ câu trả lời datamash của mình, btw (sau khi thực hiện in các bài tập theo thứ tự được sắp xếp thay vì ngẫu nhiên). Bạn đang làm việc tốt.
Shawn

@Shawn, ý bạn là kịch bản awk tôi đã đăng ở trên có hoạt động như mong đợi cho bạn không? Khi tôi chạy nó, tôi thấy "Thấp" là 0 cho tất cả các bài tập. Bạn có thể vui lòng chia sẻ mã awk tạo ra đầu ra chính xác để tôi có thể khắc phục lỗi của mình không?
pikaraider

Câu trả lời:


1

Bạn chắc chắn có thể làm điều này với awk, nhưng vì bạn cũng đã gắn thẻ kịch bản này, tôi cho rằng các công cụ khác là một tùy chọn. Đối với kiểu thu thập số liệu thống kê về các nhóm có trong dữ liệu, dữ liệu GNU thường giảm công việc xuống một lớp đơn giản. Ví dụ:

$ (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

Điều này nói rằng với mỗi nhóm có cùng giá trị cho cột thứ 3 ( -g3cộng -svới sắp xếp đầu vào (Yêu cầu của công cụ)) của đầu vào CSV đơn giản ( -t,) với tiêu đề ( --header-in), hiển thị mức tối thiểu, tối đa và trung bình của cột thứ 4. Tất cả đều được đưa ra một tiêu đề mới và được trchuyển sang dấu phẩy thành các tab.


1

Mã của bạn hoạt động tương tự như với GNU awk. Tuy nhiên, chạy nó với -ttùy chọn để cảnh báo về các cấu trúc không di động sẽ mang lại:

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'

Và việc chạy tập lệnh với cách triển khai awk khác ( mawktrong trường hợp của tôi) sẽ cho 0 'cho cột Thấp. Vì vậy, một số điều chỉnh cho kịch bản:

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])

}

và nó hoạt động như mong đợi trên awk khác.

Những thay đổi:

  • Sử dụng dấu phẩy đơn giản làm dấu tách trường thay vì biểu thức chính quy.
  • Thay đổi điều kiện tối thiểu thành cài đặt thành giá trị hiện tại vào lần đầu tiên chuyển nhượng này bằng cách kiểm tra xem cnt[$3]có bằng 0 không (đây sẽ là lần đầu tiên vì giá trị đó được tăng lên ở dòng sau) hoặc nếu min hiện tại lớn hơn giá trị này.

Cảm ơn @Shawn. Hoạt động hoàn hảo!
pikaraider

Hoặc, giả sử nó được cài đặt trên máy tính của bạn, chỉ cần chạy gawkthay vì lấy phiên bản GNU.
Shawn

1

một cách tiếp cận tương tự khác

$ 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
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.