質問するログイン新規登録

Q&A

解決済

5回答

1689閲覧

偏差値を正しく求めたい。

CarpeDiemnosiru

総合スコア4

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2020/07/09 01:12

編集2020/07/09 05:18

0

0

前提・実現したいこと

コマンドライン引数から成績を処理するコードをつくっているのですが、標準偏差がうまく求められません。本来ならsd = 18.85となるはずなのですが…
解決方法を教えてください。お願いします。
ちなみにコマンドライン引数は以下の通りです。
「Anne 100 Glbert 99 Diana 60 Emily 89 Bryce 79 Jane 74 Kilmeny 42 Marigold 64」

該当のソースコード

java

1package hello; 2 3public class Seiseki2 { 4 5 public static void main(String[] args) { 6 7 int i = 0; 8 double sum = 0; 9 double average = 0; 10 double sd = 0; 11 12 String names[] = new String[args.length/2]; 13 double score[][] = new double[2][args.length/2]; 14 15 for(i = 0; i < args.length; i += 2 ) { 16 names[i/2] = args[i]; 17 score[0][i/2] = Double.parseDouble(args[i + 1]); 18 sum += score[0][i/2]; 19 20 }for(i = 0; i < score[0].length; i ++ ) { 21 average = sum / 8.0; 22 double ssum = 0; 23 ssum += sqr(score[0][i/2] - average); 24 sd = Math.sqrt(ssum / (args.length/2)); 25 double hensachi = 50 + ((score[0][i/2] - average)/sd )* 10; 26 score[1][i] = hensachi; 27 28 } System.out.println("Average = " + average); 29 System.out.println("Standard Deviation = " + sd); 30 for(i = 0; i < 16; i += 2 ) { 31 32 double scoreX = score[0][i/2]; 33 String s = new java.text.DecimalFormat("0.#").format(scoreX ); 34 double scoreY = score[1][i/2]; 35 String ss = new java.text.DecimalFormat("0.#").format(scoreY); 36 37 System.out.print(" " + names[i/2] + " "); 38 System.out.print(s + " "); 39 System.out.println(ss); 40 41 } 42 43 } 44 45 private static double sqr(double d) { 46 return d * d; 47 } 48 49 50} 51 52 53

結果は以下の通りになります。
Average = 75.875
Standard Deviation = 4.640388251536718
Anne 100 78.3
Glbert 99 78.3
Diana 60 78.3
Emily 89 78.3
Bryce 79 21.7
Jane 74 21.7
Kilmeny 42 78.3
Marigold 64 78.3

試したこと

18行目から21行目の式を変えてみたりしましたが、うまくいきません。

補足情報

最終的な形は以下の通りにしたいと思っています。

Average = 75.9
Standard Deviation = 18.85
Anne 100 62.8
Glbert 99 62.3
Diana 60 41.6
Emily 89 57.0
Bryce 79 51.7
Jane 74 49.0
Kilmeny 42 32.0
Marigold 64 43.7

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

ozwk

2020/07/09 01:24

> うまく求められません 「うまくいかない」だけではなく、どうなるのかも書いてください
CarpeDiemnosiru

2020/07/09 01:38

申し訳ありません、いま情報を追加しました。
ozwk

2020/07/09 01:41

ありがとうございます
退会済みユーザー

退会済みユーザー

2020/07/09 01:42

STDEV = 20.15 では?
CarpeDiemnosiru

2020/07/09 01:54

今電卓で計算してみたのですが、18.85099…となりました。
退会済みユーザー

退会済みユーザー

2020/07/09 02:06

すまん、確かにまともに計算したら 18.85 (四捨五入)だった とりあえずインデントを合わせましょう
CarpeDiemnosiru

2020/07/09 02:25

インデント合わせました、ありがとうございます。
guest

回答5

0

ここで使っているiは?

java

1 2 for (i = 0; i < score[0].length; i++) { 3 double average = sum / 8.0; 4 double ssum = 0; 5 ssum += sqr(score[0][i] - average); 6 double sd = Math.sqrt(ssum / 8); 7 8 for (i = 0; i < score[0].length; i++) { // ←ここ 9 double hensachi = 50 + ((score[0][i] - average) / sd) * 10; 10 score[1][i] = hensachi; 11 } 12 System.out.println("Average = " + average); 13 System.out.println("Standard Deviation = " + sd); 14 15 for (i = 0; i < 16; i += 2) {// ←ここ 16 17 double scoreX = score[0][i]; 18 String s = new java.text.DecimalFormat("0.#").format(scoreX); 19 double scoreY = score[1][i]; 20 String ss = new java.text.DecimalFormat("0.#").format(scoreY); 21 22 System.out.print(" " + names[i] + " "); 23 System.out.print(s + " "); 24 System.out.println(ss); 25 } 26 27 }

インデントちゃんとしないと・・・

投稿2020/07/09 02:14

cateye

総合スコア6851

CarpeDiemnosiru

2020/07/09 02:23

インデント揃えました。ありがとうございます。「i」の使い方が間違っているということでしょうか?
cateye

2020/07/09 02:32

for(i = 0; i < score[0].length; i ++ )のループの中で for(i = 0; i < score[0].length; i++)とかfor(i = 0; i < 16; i += 2 )での最初期化?
CarpeDiemnosiru

2020/07/09 03:10

二重ループがあるということですね、直します。
cateye

2020/07/09 05:13

何かごっちゃにしてませんか? 合計を算出するのと、平均を算出するのは別のことです。 ・・・機能毎に、分けてみましょう・・・
guest

0

ベストアンサー

ozwkさんの回答にもありますが、配列を2倍、用意しているので、期待と異なる結果となります

java

1double score[][] = new double[2][args.length]; 2 3for(i = 0; i < args.length; i += 2 ) { 4 score[0][i] = Double.parseDouble(args[i + 1]); 5} 6 7// ↑ のように格納した場合 scoreは以下のようになる。 8// score[0] は、{100,0,99,0,60,0,89,0,79,0,74,0,42,0,64,0} 9 10// 以下のように全要素でssumを求めると余計な0が含まれるので、期待と異なる結果になる 11for(i = 0; i < score[0].length; i ++ ) { 12 double ssum = 0; 13 ssum += sqr(score[0][i] - average); 14} 15

投稿2020/07/09 03:31

momon-ga

総合スコア4828

0

とりあえず。サンプル
ただ、 引数からではなく標準入力からの登録に変えてあるので イメージとして理解してください。

import java.util.*; public class Main { public static void main(String[] args) throws Exception { try (Scanner s = new Scanner(System.in)) { int n = s.nextInt(); String[] a = new String[n]; double[] b = new double[n]; double c = 0D; double d = 0D; double[] e = new double[n]; double[] f = new double[n]; double g = 0D; double h = 0D; double i = 0D; for (int z = 0; z < n; z++) { a[z] = s.next(); b[z] = s.nextInt(); c += b[z]; } d = c / n; for (int z = 0; z < n; z++) { e[z] = b[z] - d; f[z] = Math.pow(e[z], 2); g += f[z]; } h = g / n ; i = Math.sqrt(h) ; System.out.printf("%-20s:%4.0f%n", "Total", c); System.out.printf("%-20s:%7.2f%n", "Average", d); System.out.printf("%-20s:%7.2f%n", "Standard Div", i); for (int z = 0; z < n; z++) { System.out.printf("%-20s:%4.0f ( %4.1f )%n", a[z], b[z], 50 + ((b[z] - d) / i ) * 10); } } } }

結果

Total : 607 Average : 75.88 Standard Div : 18.85 Anne : 100 ( 62.8 ) Glbert : 99 ( 62.3 ) Diana : 60 ( 41.6 ) Emily : 89 ( 57.0 ) Bryce : 79 ( 51.7 ) Jane : 74 ( 49.0 ) Kilmeny : 42 ( 32.0 ) Marigold : 64 ( 43.7 )

投稿2020/07/09 05:19

編集2020/07/09 05:20
退会済みユーザー

退会済みユーザー

総合スコア0

0

コード中に 8 で割るところがありますが、そういう固定値ではないはずです。
args.length / 2 の値にしないといけないでしょう。

点数と偏差値を 2次元配列の [0] と [1] で区別しているから面倒になっています。
次のようにしましょう。

Java

1 public static void main(String[] args) { 2 3 int n = args.length / 2; 4 String names[] = new String[n]; 5 double score[] = new double[n]; 6 double deval[] = new double[n]; 7 8 double sum = 0; 9 for (int i = 0, j = 0; i < n; i++) { 10 names[i] = args[j++]; 11 score[i] = Double.parseDouble(args[j++]); 12 sum += score[i]; 13 } 14 15 // ここで、平均、標準偏差、偏差値を計算 16 17 System.out.printf("Average = %.1f\n", average); 18 System.out.printf("Standard Deviation = %.2f\n", sd); 19 20 for (int i = 0; i < n; i++) 21 System.out.printf("%-9s %3.0f %6.1f\n", 22 names[i], score[i], deval[i]); 23 }

追記
もう解決済みですか?
質問のコードをどんどん修正すると、回答の指摘が何のことかわからなくなるので
修正コードは追記されるほうが良いと思います。

現在のコードにも average = sum / 8.0; のように 8 が残っています。
また、コードの中に /2 がたくさんあります。
最初に int n = args.length / 2; として、その n を使うとコードが見やすくなります。
また、小数点以下の文字数を指定するのには printf を使うと簡単です。

Java

1package hello; 2 3public class Seiseki2 { 4 5 public static void main(String[] args) { 6 7 int n = args.length / 2; 8 String names[] = new String[n]; 9 double score[][] = new double[2][n]; 10 11 double sum = 0, j = 0; 12 for (int i = 0; i < n; i++) { 13 names[i] = args[j++]; 14 score[0][i] = Double.parseDouble(args[j++]); 15 sum += score[0][i]; 16 } 17 double average = sum / n; 18 19 double ssum = 0; 20 for (int i = 0; i < n; i++) 21 ssum += sqr(score[0][i] - average); 22 23 double sd = Math.sqrt(ssum / n); 24 25 for (int i = 0; i < n; i++) 26 score[1][i] = 50 + 10 * (score[0][i] - average) / sd; 27 28 System.out.printf("Average = %.1f\n", average); 29 System.out.printf("Standard Deviation = %.2f\n", sd); 30 31 for (int i = 0; i < n; i++) 32 System.out.printf("%-9s %3.0f %6.1f\n", 33 names[i], score[0][i], score[1][i]); 34 } 35 36 private static double sqr(double d) { return d * d; } 37}

投稿2020/07/09 04:12

編集2020/07/09 13:23
kazuma-s

総合スコア8222

CarpeDiemnosiru

2020/07/09 05:09

args.length/2、訂正しました。 テキストの方で点数と偏差値は二次元配列に格納しろとの指示がありまして。
guest

0

インデントが汚いです。直しましょう。
インデントをきちんと整理してみると2重ループ構造になってしまっているのがわかると思います。


多少無駄にループが回ろうがわかりやすさ優先で書きましょう:

java

1int main(String[] args){ 2 // コマンドライン引数を読み込むためのループ 3 4 // 平均値を計算するためのループ 5 6 // 標準偏差を計算するためのループ 7 8 // 偏差値を計算するためのループ 9 10 // 表示するためのループ 11}

scorenameを人数の倍用意して1つ置きにデータを入れてますね?
コマンドライン引数が(名前,点数)の組であるためにi+=2とした都合できっと工夫したのでしょうが、
その後の展開が非常にわかりづらくなる=ミスりやすいので1つ置きに入れるのはやめましょう。
(実際、標準偏差を求めるときにミスってます)
namescorei/2で代入すれいいです:

java

1String names[] = new String[args.length/2]; 2double score[][] = new double[2][args.length/2]; 3 4for(i = 0; i < args.length; i += 2 ) { 5 names[i/2] = args[i]; 6 score[0][i/2] = Double.parseDouble(args[i + 1]); 7 sum += score[0][i/2]; 8}

ループの外で使わないのにループの変数iをループ外で宣言するのはヤメましょう。
なんか使うのかな?と読むとき不安になります。

diff

1- int i = 0; 2- for(i = 0; ...) 3+ for(int i = 0; ...)

投稿2020/07/09 02:29

編集2020/07/09 02:39
ozwk

総合スコア13553

CarpeDiemnosiru

2020/07/09 03:14

この場合って System.out.println("Average = " + average); System.out.println("Standard Deviation = " + sd); はどこに入れるとループに巻き込まれないのでしょうか。
ozwk

2020/07/09 03:17

ループの外に書けばいいんじゃないですかね
CarpeDiemnosiru

2020/07/09 03:20

ループ内に入れないとaverageを変数に解決できません、と表示されます。
ozwk

2020/07/09 03:23

じゃあそれもループの外に出せばいいんじゃないですかね
CarpeDiemnosiru

2020/07/09 03:34

修正してみたのですが、∞がでてしまい、どうしたらいいのかわかりません。
ozwk

2020/07/09 03:57

ループとループの間でやって下さい
CarpeDiemnosiru

2020/07/09 05:16

何度もすみません、ループの間でできました! すべてi/2に変えてみたのですが、また違う値が出てしまいます。
ozwk

2020/07/09 06:42

その話はコマンドライン引数からnameとscore作るとき だけ の話です
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.29%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問