成績処理

試験の成績処理です。成績処理としてよく行われるのは

(1) クラスごとの平均点の一覧表

(2) 順位付け

(3) 成績個票の作成

でしょう。Cindyscriptのリスト処理を使って,これらの処理を行います。

例として次のようなデータを考えます。

各クラスの人数は40人前後で,5クラスとします。学籍番号は,入学年度,クラス,生徒番号が各2桁ずつで6桁の数からなり,得点は全員分を一括して入力されているものとします。

学籍番号 氏名 第1回 第2回 第3回 第4回 第5回

160101 氏名1 33 40 49 65 75

160102 氏名2 93 47 91 40 80

160103 氏名3 52 81 29 20 37

160104 氏名4 84 27 85 94 26

・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・

データは testdata.csv とします。このページの下からダウンロードできます。

読み込んだデータ dlist は,Dispmat() を用いて

dlist=Readcsv("testdata.csv");

Dispmat(dlist);

とすれば,コンソールで確認できます。

クラスごとの平均点の一覧表

まず1組を抽出してみましょう。1組の学籍番号は 160101から始まります。中央の2桁が 01 となっているのが1組です。

dlist=Readcsv("testdata.csv");

rown=length(dlist);

coln=length(transpose(dlist));

data=dlist_(2..rown);

class=select(data,floor(mod(#_1,10000)/100)==1);

つぎに,この class1 について,第1回の試験の受験者数を調べ(値が0以上のものの数)平均点などを求めてみましょう。第1回のデータは,3番目にあるので

test=select(column(class,3),#!="");

で受験者を抽出し,合計を人数で割って平均点が出ます。

ninzu=length(test);

average=sum(test)/ninzu;

以上を各クラスのそれぞれの回の試験について行い,リストに格納します。

1つのクラスの,各試験の受験者と平均点のリストを sc,その5クラス分を score とします。

---- データの読み込みからクラス別平均点の算出まで ----------------------------------------

dlist=Readcsv("testdata.csv");

rown=length(dlist);

coln=length(transpose(dlist));

data=dlist_(2..rown);

kaisu=coln-2;

score=[];

repeat(5,s,

class=select(data,floor(mod(#_1,10000)/100)==s);

sc=[];

repeat(kaisu,t,

test=select(column(class,2+t),#!="");

ninzu=length(test);

sc=append(sc,[ninzu,sum(test)/ninzu]);

);

score=append(score,sc);

);

---------------------------------------------------------------------------------------------------

できあがった score を,一覧表にして画面に表示します。

一覧表では,小数点以下2位を四捨五入して表示するために,Sprintf() を用います。右寄せで表示しますが,Sprintf()+" " とすると,右側にスペースが空いて見やすくなります。" " をつけない場合と比べてみてください。

Yoko=apply(1..(coln-1),20);

Tate=apply(1..6,10);

Tabledatalight("",Yoko,Tate,[],[0]);

Putrow(1,"c",["クラス"] ++ dlist_1_(3..coln));

PutcoL(1,"c",[""] ++ 1..5);

repeat(5,s,

repeat(kaisu,t,

Putcell((t+1),(s+1),"r",Sprintf(score_s_t_2,1)+" ");

);

);

受験者数も入れるのであれば,次のように括弧をつけて付加することが考えられます。

Yoko=apply(1..(coln-1),30);

Tate=apply(1..6,10);

Tabledatalight("",Yoko,Tate,[],[0]);

Putrow(1,"c",["クラス"] ++ dlist_1_(3..coln));

PutcoL(1,"c",[""] ++ 1..5);

repeat(5,s,

repeat(kaisu,t,

Putcell((t+1),(s+1),"r",Sprintf(score_s_t_2,1)+" ("+score_s_t_1+") ");

);

);

順位をつける

CindyScriptの関数 sort(data) でデータが昇順に並べ替えられます。逆順にするには reverse() を使えばよいのですが,

dat=reverse(sort(data,#_3));

Dispmat(dat);

の結果を確かめると,次のようになっています。(第1回の試験での並べ替えです)

160512 氏名173 70 34 82 99

160431 氏名150 91 93 58 47

160413 氏名132 62 40 98 54

160536 氏名197 100 51 71 56 85

160533 氏名194 100 21 76 49 78

160336 氏名115 100 90 88 32 40

160415 氏名134 99 87 27 91 21

欠席者が先頭にきています。また,100点が3人いますが,出席番号が逆順です。

そこで,発想を変えて,「100-得点」で昇順にします。

dat=sort(data,100-#_3);

Dispmat(dat);

160336 氏名115 100 90 88 32 40

160533 氏名194 100 21 76 49 78

160536 氏名197 100 51 71 56 85

160124 氏名24 99 54 61 56 70

ただし,このとき,コンソールに WARNING: Potential type mismatch in "-" --> 100-#_3 というエラーメッセージが出ます。欠席のためデータが空の場合に警告されるのです。しかし,欠席者を除外したリストを作ってしまうと,あとが面倒なので,この警告は無視しましょう。ただし,警告が出た理由:欠席者がいる は,次に順位付けをするときに留意します。

次に順位をつけます。前の人と同じならば順位を変えず,そうでなければ順位を更新します。順位を表す変数を order として,始めに1を代入しておきます。順位はそれぞれの人のデータの後方に追加するものとして,1番の人には1を追加しておきます。繰り返し処理は start->2 で,2番から始めます。

data=sort(data,100-#_3);

order=1;

data_1=append(data_1,1); //始めの人に順位1を付加

repeat(rown-2,s,start->2,

if(data_s_3!="",

if(data_s_3!=data_(s-1)_3,order=s);

data_s=append(data_s,order);

);

);

160336 氏名115 100 90 88 32 40 1

160533 氏名194 100 21 76 49 78 1

160536 氏名197 100 51 71 56 85 1

160124 氏名24 99 54 61 56 70 4

160415 氏名134 99 87 27 91 21 4

160224 氏名65 98 45 82 23 87 6

これで順位のつけ方はわかったので,すべての試験について順位付けをします。最後に番号順に戻しておきます。

----順位付け-------------------------------------------------------------------------

dlist=Readcsv("testdata.csv");

rown=length(dlist);

coln=length(transpose(dlist));

data=dlist_(2..rown);

kaisu=coln-2;

repeat(kaisu,t,

data=sort(data,100-#_(t+2));

order=1;

data_1=append(data_1,1); //始めの人に順位1を付加

repeat(rown-2,s,start->2,

if(data_s_(t+2)!="",

if(data_s_(t+2)!=data_(s-1)_(t+2),order=s);

data_s=append(data_s,order);

,

data_s=append(data_s,"");

);

);

);

----------------------------------------------------------------------------------------

Dispmat(data); でコンソールに表示してみましょう。

160231 氏名72 78 64 39 97 100 46 96 154 9 1

160434 氏名153 53 53 49 48 100 107 114 134 133 1

160523 氏名184 69 47 96 44 100 75 134 14 144 1

160305 氏名84 64 41 55 44 100 85 154 117 144 1

160512 氏名173 70 34 82 99 78 167 45 5

160420 氏名139 74 76 28 55 99 61 59 183 120 5

160535 氏名196 75 63 56 54 99 55 99 116 123 5

最後の回の順位付けで終わっています。このあと,学籍番号順に戻しておきましょう。

data=sort(data);

160101 氏名1 33 40 49 65 75 155 157 134 93 66

160102 氏名2 93 47 91 40 80 12 134 25 154 54

160103 氏名3 52 81 29 20 37 108 50 179 201 160

160104 氏名4 84 27 85 94 26 38 190 36 14 191

160105 氏名5 91 92 65 62 52 16 21 93 101 127

成績個票を作る

各回ごとの得点,平均点,順位を示した成績個票を作ります。1枚のページに一人分のデータを表示するわけです。

そのためには,KeTCindyのアニメーション機能を使います。KeTCindyのアニメーションには,自動でフレームを表示していく動画と,手動でフレームを順に表示するパラパラとがあります。これらは,いずれも1つの画面を1ページとして,複数枚のページからなるPDFを作っているわけです。ですから,人数分のページを作ってパラパラの形式で保存すればよいわけです。

そのために,どれでもよいので,アニメーション用のボタン,「ParaF」「Anime」「Flip」のついたものをひな形として使います。

パラパラ(アニメーション)の作り方は次のようになっています。

まず,フレーム1枚分を時間tの関数として,mf(t) で定義します。ここでは t番目の学生のデータを定義すればよいのです。平均点は average() に入っているとします。また,表の枠はできているとします。

mf(t):=(

Letter([[0,4.5],"e",data_t_1+" "+data_t_2]); // 学籍番号と氏名

repeat(kaisu,s,

Putcell(s+1,2,"r",data_t_(s+2)+" ");

Putcell(s+1,3,"r",Sprintf(average_s,1)+" ");

Putcell(s+1,4,"r",data_t_(kaisu+s+2)+" ");

);

);

Setpara("seiseki","mf(t)","t=[1,"+(rown-1)+"]",["Div="+(rown-2)], ["Title=月例テスト結果"]);

t番目の学生のデータは,順位をつけて

160101 氏名1 33 40 49 65 75 155 157 134 93 66

のようになっています。したがって,s回目のデータは,得点が,data_t_(s+2),順位がdata_t_(kaisu+s+2) であることに注意します。

また,Setpara() の指定は次のようになっています。

・範囲 :1から,行数-1まで

・フレーム分割数:行数-2 ここで -2とするのがちょっとしたポイントです。たとえば,100人分であれば99分割するのです。100cmのテープを100分割することをイメージしてください。

スライダを作って番号を取得し,

Slider("A-C-B",[-2,10],[-2,0]);

mf(floor(|A,C|/|A,B|*(rown-1))+1);

とすると,一人分の学生の個票が表示されます。出力範囲の SW,NEは,Tabledatalight() に "Rng=n" オプションをつけ,学籍番号と氏名が入るようにしています。

,

data_s=append(data_s,""); // 欠席者は空を追加

ParaFボタンでデータを作り,FlipボタンでPDFを作ると次のような個票ができます。

160215 の学生は,第2回のテストを受けていません。

データの読み込みから,平均の計算,順位付け,個票の作成までの全体のスクリプトを再掲します。

dlist=Readcsv("testdata.csv");

rown=length(dlist);

coln=length(transpose(dlist));

data=dlist_(2..rown);

kaisu=coln-2;

// 順位付け

repeat(kaisu,t,

data=sort(data,100-#_(t+2));

order=1;

data_1=append(data_1,1);

repeat(rown-2,s,start->2,

if(data_s_(t+2)!="",

if(data_s_(t+2)!=data_(s-1)_(t+2),order=s);

data_s=append(data_s,order);

,

data_s=append(data_s,"");

);

);

);

data=sort(data); // 学籍番号順に戻す

Dispmat(data); // コンソールに表示して確認

// 平均点の計算

average=[];

repeat(kaisu,t,

test=select(column(data,2+t),#!="");

ninzu=length(test);

average=append(average,sum(test)/ninzu);

);

// 作表

Yoko=apply(1..(coln-1),20);

Tate=apply(1..4,10);

Tabledatalight("",Yoko,Tate,[],[0,"Rng=n"]);

Putrow(1,"c",["回"] ++ dlist_1_(3..coln));

PutcoL(1,"c",["","得点","平均","順位"]);

// アニメーションの定義

mf(t):=(

Letter([[0,4.5],"e",data_t_1+" "+data_t_2]);

repeat(kaisu,s,

Putcell(s+1,2,"r",data_t_(s+2)+" ");

Putcell(s+1,3,"r",Sprintf(average_s,1)+" ");

Putcell(s+1,4,"r",data_t_(kaisu+s+2)+" ");

);

);

Setpara("seiseki","mf(t)","t=[1,"+(rown-1)+"]",["Div="+(rown-2)], ["Title=月例テスト結果"]);

Slider("A-C-B",[-2,10],[-2,0]);

mf(floor(|A,C|/|A,B|*(rown-1))+1);

「KeTCindyCalc」に戻る