前回は、定量データをスコア順に並び替えたのち、この順番でグループに割り振っていく方法を見た。今回は、定量データをスコア順に並び替えるところは同じだが、割り振り方を変更することにより、より平均的に分類できないかを見ていく。

前回と同じく、100人の学生を3つのクラスA、B、Cに分ける方法を考えてみる。

  1. まず、学生をスコア順にA、B、Cに一人ずつ割り振る。
  2. 次に、学生をA、B、Cのそれぞれに割り振った場合、どのクラスが最もスコアが良くなるかを判定して、最もスコアが良いクラスに割り振る。
  3. 仮に、Aに割り振ったとすると、次の学生はB、Cのどちらに割り振った方がクラスのスコアが良くなるのかを判定して、最もスコアが良いクラスに割り振る。
  4. 仮に、Bに割り振ったとすると、次の学生は自動的にCに割り振って、2へ繰り返す。

それでは、実際にC#で組んでみる。
以前作成した定量データを格納するItemクラスと分類された定量データを格納するGroupクラスは変更がないので、記載は省略した。
実際の分類は以下のクラスで行う。


public class SequentialSelectionClassification
{
    public IEnumerable Classify(IEnumerable source, IEnumerable valueIndices, int groupNumber)
    {
        //平均値
        var averageDictionary = new Dictionary();
        foreach (var valueIndex in valueIndices)
        {
            averageDictionary[valueIndex] = source.Average(x => x.Values[valueIndex]);
        } 

        //スコア計算
        var scoreDictionary = new Dictionary();
        foreach (var item in source)
        {
            var d = 0.0d;
            foreach (var valueIndex in valueIndices)
            {
                var v = (item.Values[valueIndex] - averageDictionary[valueIndex]);
                d += v * v;
            }
            scoreDictionary[item] = d;
        } 

        //スコアを昇順に並び替え
        var list = new List>(scoreDictionary);
        //昇順
        list.Sort((x, y) => x.Value.CompareTo(y.Value));
        // 降順
        //list.Sort((x, y) => -x.Value.CompareTo(y.Value));
        var items = list.Select(x => x.Key).ToArray(); 

        //グループ作成
        var groups = new List();
        for (var i = 0; i < groupNumber; i++)
        {
            groups.Add(new Group(valueIndices));
        } 

        //グループのインデックスと要素数のペア
        var groupCountDictionary = new Dictionary();
        for (var i = 0; i < groupNumber; i++)
        {
            groupCountDictionary[i] = 0;
        } 

        //グループ振り分け
        for (var i = 0; i < groupNumber; i++)
        {
            groups[i].Items.Add(items[i]);
            groupCountDictionary[i]++;
        }
        for (var i = groupNumber; i < items.Length; i++)
        {
            var item = items[i];
            var min = groupCountDictionary.Min(x => x.Value);
            var indices = groupCountDictionary.Where(x => x.Value == min).Select(x => x.Key); 

            var minIndex = -1;
            var minScore = double.MaxValue; 

            foreach (var index in indices)
            {
                var score = Score(averageDictionary, item, groups[index]);
                if (score < minScore)
                {
                    score = minScore;
                    minIndex = index;
                }
            } 

            groups[minIndex].Items.Add(item);
            groupCountDictionary[minIndex]++;
        } 

        return groups;
    } 

    private double Score(Dictionary averageDictionary, Item item, Group group)
    {
        var d = 0.0d;
        foreach (var kvp in averageDictionary)
        {
            var s = group.Items.Sum(x => x.Values[kvp.Key]) + item.Values[kvp.Key];
            s = (double)s / (group.Items.Count + 1) - kvp.Value;
            d += s * s;
        }
        return d;
    }
}

以上で、準備は完了だ。それでは、実際に分類してみる。定量データは乱数を用いてダミーデータを作成している。


public class Test
{
    public void Test2()
    {
        //ダミーデータ作成
        var items = new List();
        for (var i = 0; i < 100; i++)
        {
            var random = new Random(i);
            var values = new double[2];
            values[0] = random.Next(0, 100);
            values[1] = random.Next(0, 100);
            items.Add(new Item(values));
        }

        //分類
        var classification = new SequentialSelectionClassification();
        var groups = classification.Classify(items, new int[] { 0, 1 }, 3);

        //ダミーデータ表示
        System.Console.WriteLine("dummy-data");
        foreach (var item in items)
        {
            System.Console.WriteLine(item.Values[0] + "," + item.Values[1]);
        }

        //ダミーデータの平均値の表示
        System.Console.WriteLine("dummy-data-average");
        System.Console.WriteLine("0:" + items.Average(x => x.Values[0]));
        System.Console.WriteLine("1:" + items.Average(x => x.Values[1]));

        //結果表示
        foreach (var group in groups)
        {
            System.Console.WriteLine("group-item");
            foreach (var item in group.Items)
            {
                System.Console.WriteLine(item.Values[0] + "," + item.Values[1]);
            }
            System.Console.WriteLine("group-average");
            var dictionary = group.Average();
            foreach (var kvp in dictionary)
            {
                System.Console.WriteLine(kvp.Key + ":" + kvp.Value);
            }
        }
    }
}

この結果は以下のようになった。実際には、前回用いたダミーデータをファイル保存しておき、それを読み取っている。
【スコアを昇順で並び替えた場合】

全データ グループ1 グループ2 グループ3
インデックス0の平均値 51.12 52.81 44.78 55.61
インデックス1の平均値 50.66 45.96 50.06 55.79

【スコアを降順で並び替えた場合】

全データ グループ1 グループ2 グループ3
インデックス0の平均値 51.12 47.53 52.57 53.26
インデックス1の平均値 50.66 53.06 45.69 53.14

評価式を定義する。
(グループ1のインデックス0平均値-全データのインデックス0の平均値)^2
+(グループ2のインデックス0平均値-全データのインデックス0の平均値)^2
+(グループ3のインデックス0平均値-全データのインデックス0の平均値)^2
+(グループ1のインデックス1平均値-全データのインデックス1の平均値)^2
+(グループ2のインデックス1平均値-全データのインデックス1の平均値)^2
+(グループ3のインデックス1平均値-全データのインデックス1の平均値)^2

スコアを昇順で並び替えた場合:111.97
スコアを降順で並び替えた場合:56.18

以上から、スコアを降順に並べてから、グループスコアが最も小さくなるようにグループに振り分けていく方が、より平均的に分類できていることが分かる。

今までは、定量データをスコア順に取り出していた。
次回は、スコア順ではなく適切に取り出すことによって、より平均的に分類できないかを考えてみる。

関連する記事

  • R実装と解説 対応のない2標本の母平均の差の検定(母分散が異なる) [latexpage] 母分散が異なるの場合の対応のない2標本の母平均の差の検定とは、2つの母集団が正規分布に従い、ともに母分散が異なるとき、一方の母平均が他方の母平均と「異なる」または「大きい」、「小さい」かどうかを、検定統計量がt分布に従うことを利用して検定します。 統計的検定の流れ 検定の大まかな流れを確認しておきます。 […]
  • Ubuntu Server 20.04にOpalをインストールする方法Ubuntu Server 20.04にOpalをインストールする方法 Ubuntu Server […]
  • R言語 CRAN Task View:生態と環境データの分析R言語 CRAN Task View:生態と環境データの分析 CRAN Task View: Analysis of Ecological and Environmental Dataの英語での説明文をGoogle翻訳を使用させていただき機械的に翻訳したものを掲載しました。 Maintainer: Gavin Simpson Contact: ucfagls at […]
  • R ggplotでファセットラベルテキストの体裁を変更する方法 ggplotのfacet_gridやfacet_wrapを用いた場合、垂直方向のラベルテキストが縦書きとなり直感的でないときがあります。 この場合は、ラベルテキストのアングルを横書きに変更することで、より見やすいグラフとなります。 デフォルト 特に何も指定しない場合は、次のようなグラフとなります。 library(ggplot2) data("diamond […]
  • 相関係数相関係数 相関係数とは2変量のデータ間の関係性の強弱を計る統計学的指標である。相関係数rがとる値の範囲は-1≦r≦1である。相関係数rの値により以下のように呼ばれる。 -1≦r<0ならば負の相関 r=0ならば無相関 0<r≦1ならば正の相関 一般的に、強弱も合わせて以下のように呼ばれる。 […]
平均的に分類する方法の考察(3)