解析エンジニアの自動化 blog

コツコツと自動化した方法を残す blog

python で 感情分析〜単語感情極性対応表を使う練習〜



こんにちは。
仕事の自動化にやりがいと達成感を感じるガッくんです。


この記事の目次



背景・目的


『感情 python 』で検索すると『単語感情極性対応表』という辞書にたどり着きました。

ひとまず感触を確かめてみます。



動作環境


Windows 7
・winpython 64bit 3.4.4



プログラム

単語感情極性対応表のダウンロード

・『単語感情極性対応表 ダウンロード』でネット検索


・単語感情極性対応表のダウンロードサイトへのリンクをクリック


ダウンロードサイトから日本語の辞書を選択


・全てを選択、テキストエディタにコピペしてテキストを保存


ソースコード


# -*- coding: utf-8 -*-
import pandas as pd
 
# 単語感情極性対応表 のパスを設定する
filepath='C:\\Users\\UserName\\Desktop\\dictionary\\pn_table.txt'
print('dictionary path = ' + filepath)
print()
 
# pandas で読み込む
pn_table = pd.read_csv(filepath, engine='python', encoding='shift_jis', sep=':', names=('Word','Reading','POS','PN'))
 
# 語のリスト と PN 値のリスト の作成
word_list = list(pn_table['Word'])
pn_list = list(pn_table['PN'])
 
# 語をキーとした PN 値辞書の作成
pn_dict = dict(zip(word_list, pn_list))
 
# 辞書テスト
text = '良い'
if text in pn_dict.keys():
    print(text, pn_dict[text])
else:
    print(text, '無し')
 
text = '悪い'
if text in pn_dict.keys():
    print(text, pn_dict[text])
else:
    print(text, '無し')



結果


In [1]: runfile('C:/WPy64-3720/settings/.spyder-py3/pn_table-test0.py', wdir='C:/WPy64-3720/settings/.spyder-py3')
dictionary path = C:\Users\UserName\Desktop\dictionary\pn_table.txt
 
良い 0.9999950000000001
悪い -1.0
 
In [2]:



コメント

参照を多く行う場合は dictionary と相場が決まっています。

これが出来れば、あとは形態素解析した文節を辞書で参照していけば良いだけですね。



以上

C# の HashSet と SortedSet



こんにちは。
仕事の自動化にやりがいと達成感を感じるガッくんです。


この記事の目次



背景・目的


履歴を管理したり、重複を避ける場合には HashSet か SortedSet を使うのが王道だと思います。

HashSet と SortedSet がいったいどれほどの威力なのかを確かめました。



動作環境


Windows 7
Visual Studio 2017



プログラム

ソースコード

重複のあるランダムな List から重複のない List を作成します。

なお、 1 行目の #define のコメントを外すと、 List の値を出力する事ができるようになります。

//#define OUTPUT_VALUES
 
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
 
namespace speed_​​comparison_duplicate
{
    class Program
    {
        static void Main(string[] args)
        {
            ///////////////////////////////////////////////////////////////////////////////
            // 重複のあるランダムな values List を作成し、
            // values List から重複のない List を作成する。
            ///////////////////////////////////////////////////////////////////////////////
            // 重複のあるランダムな values List の作成
            //    ある数の配列を用意する。
            //    重複がない様に連番で初期化する。
            //    乱数を使って配列の値を入れ替えて並び順をランダムにする。
            //    ランダムに並べ替えた配列を List に 2 回代入する。
            ///////////////////////////////////////////////////////////////////////////////
            // values List から重複のない List の作成
            //    values List を調べて追加されたことのない要素で有れば、
            //    List に要素を追加する。
            //    パターンA
            //        Contains メソッドで values List の有無を調べる
            //    パターンB
            //        BinarySearch メソッドで values List の有無を調べる
            //    パターンC
            //        HashSet で重複のない List を作成する
            //    パターンD
            //        SortedSet で重複のない List を作成する
            ///////////////////////////////////////////////////////////////////////////////
 
 
 
            ///////////////////////////////////////////////////////////////////////////////
            // 重複のあるランダムな values List の作成
            //    ある数の配列を用意する。
            //    重複がない様に連番で初期化する。
            //    乱数を使って配列の値を入れ替えて並び順をランダムにする。
            ///////////////////////////////////////////////////////////////////////////////
            Stopwatch sw = new Stopwatch();
            sw.Reset();
            sw.Start();
 
            // cntArray 個の配列作成
            int cntArray = 30000;
            int[] values = new int[cntArray];
 
            // 配列の初期化
            int startValue = 523;
            for (int i = 0; i < values.Length; i++)
            {
                values[i] = startValue + i;
            }
           
            // 乱数発生器作成する
            Random r = new Random();
           
            // 配列を cntSwap 回シャッフルする
            int cntSwap = cntArray;
            for (int i = 0; i < cntSwap; i++)
            {
                // 入れ替える配列インデックスをランダムに選定する
                int j = r.Next(0, values.Length);
 
                // 配列の値の入れ替え
                int tmpJ = values[j];
                values[j] = values[i];
                values[i] = tmpJ;
            }
 
            // cntDuplicate 個の重複のあるランダムな values List の作成
            int cntDuplicate = 2;
            List values_List = new List();
            for (int i = 0; i < cntDuplicate; i++)
            {
                for (int j = 0; j < values.Length; j++)
                {
                    values_List.Add(values[j]);
                }
            }
 
            sw.Stop();
            Console.WriteLine("配列作成終了");
 
            string filepath = "C:\\Users\\UserName\\Desktop\\log.txt";
            StreamWriter w = new StreamWriter(filepath, false, Encoding.GetEncoding("shift_jis"));
 
            TimeSpan ts = sw.Elapsed;
            w.Write("*   値のランダムな values List の個数:");
            w.WriteLine(values_List.Count);
            w.Write("                               重複数:");
            w.WriteLine(cntDuplicate);
            w.Write("値のランダムな values List の作成時間:");
            w.WriteLine($" {ts.Hours}時間 {ts.Minutes}分 {ts.Seconds}秒 {ts.Milliseconds}ミリ秒");
 
#if (OUTPUT_VALUES)
            w.WriteLine(string.Format("{0,10}", "Index") + ":" + string.Format("{0,20}", "Values"));
            for (int i = 0; i < values_List.Count; i++)
            {
                w.WriteLine(string.Format("{0,10}", i) + ":" + string.Format("{0,20}", values_List[i]));
            }
#endif
 
            ///////////////////////////////////////////////////////////////////////////////
            // values List の空ループの時間調査
            ///////////////////////////////////////////////////////////////////////////////
            sw.Reset();
            sw.Start();
 
            for (int i = 0; i < values_List.Count; i++)
            {
            }

            sw.Stop();
            Console.WriteLine("空ループ終了");
 
            ts = sw.Elapsed;
            w.WriteLine("");
            w.Write("*          values List の空ループ時間:");
            w.WriteLine($" {ts.Hours}時間 {ts.Minutes}分 {ts.Seconds}秒 {ts.Milliseconds}ミリ秒");
 
            ///////////////////////////////////////////////////////////////////////////////
            // values List から重複のない List の作成
            //    values List を調べて追加されたことのない要素で有れば、
            //    List に要素を追加する。
            //    パターンA
            //        Contains メソッドで values List の有無を調べる
            ///////////////////////////////////////////////////////////////////////////////
            sw.Reset();
            sw.Start();
 
            List list1 = new List();
 
            for(int i = 0; i < values_List.Count; i++)
            {
                if (!list1.Contains(values_List[i]))
                {
                    list1.Add(values_List[i]);
                }
            }
 
            sw.Stop();
            Console.WriteLine(" Contains 終了");
 
            ts = sw.Elapsed;
            w.WriteLine("");
            w.Write("*             重複のない list1 の個数:");
            w.WriteLine(list1.Count);
            w.Write("          重複のない list1 の作成時間:");
            w.WriteLine($" {ts.Hours}時間 {ts.Minutes}分 {ts.Seconds}秒 {ts.Milliseconds}ミリ秒");
 
#if (OUTPUT_VALUES)
            w.WriteLine(string.Format("{0,10}", "Index") + ":" + string.Format("{0,20}", "Values"));
            for (int i = 0; i < list1.Count; i++)
            {
                w.WriteLine(string.Format("{0,10}", i) + ":" + string.Format("{0,20}", list1[i]));
            }
#endif
 
            ///////////////////////////////////////////////////////////////////////////////
            // values List から重複のない List の作成
            //    values List を調べて追加されたことのない要素で有れば、
            //    List に要素を追加する。
            //    パターンB
            //        BinarySearch メソッドで values List の有無を調べる
            ///////////////////////////////////////////////////////////////////////////////
            sw.Reset();
            sw.Start();
 
            List list2 = new List();
 
            for (int i = 0; i < values_List.Count; i++)
            {
                int idx = list2.BinarySearch(values_List[i]);
                if (idx < 0)
                {
                    list2.Add(values_List[i]);
                    list2.Sort();
                }
            }
 
            sw.Stop();
            Console.WriteLine(" BinarySearch 終了");
 
            ts = sw.Elapsed;
            w.WriteLine("");
            w.Write("*             重複のない list2 の個数:");
            w.WriteLine(list1.Count);
            w.Write("          重複のない list2 の作成時間:");
            w.WriteLine($" {ts.Hours}時間 {ts.Minutes}分 {ts.Seconds}秒 {ts.Milliseconds}ミリ秒");
 
#if (OUTPUT_VALUES)
            w.WriteLine(string.Format("{0,10}", "Index") + ":" + string.Format("{0,20}", "Values"));
            for (int i = 0; i < list2.Count; i++)
            {
                w.WriteLine(string.Format("{0,10}", i) + ":" + string.Format("{0,20}", list2[i]));
            }
#endif
 
            ///////////////////////////////////////////////////////////////////////////////
            // values List から重複のない List の作成
            //    values List を調べて追加されたことのない要素で有れば、
            //    List に要素を追加する。
            //    パターンC
            //        HashSet で重複のない List を作成する
            ///////////////////////////////////////////////////////////////////////////////
            sw.Reset();
            sw.Start();
 
            HashSet hash = new HashSet();
 
            for (int i = 0; i < values_List.Count; i++)
            {
                hash.Add(values_List[i]);
            }
 
            List hashList = hash.ToList();
 
            sw.Stop();
            Console.WriteLine(" HashSet 終了");
 
            ts = sw.Elapsed;
            w.WriteLine("");
            w.Write("*              重複のない hash の個数:");
            w.WriteLine(hash.Count);
            w.Write("           重複のない hash の作成時間:");
            w.WriteLine($" {ts.Hours}時間 {ts.Minutes}分 {ts.Seconds}秒 {ts.Milliseconds}ミリ秒");
 
#if (OUTPUT_VALUES)
            w.WriteLine(string.Format("{0,10}", "Index") + ":" + string.Format("{0,20}", "Values"));
            for (int i = 0; i < hashList.Count; i++)
            {
                w.WriteLine(string.Format("{0,10}", i) + ":" + string.Format("{0,20}", hashList[i]));
            }
#endif
 
            ///////////////////////////////////////////////////////////////////////////////
            // values List から重複のない List の作成
            //    values List を調べて追加されたことのない要素で有れば、
            //    List に要素を追加する。
            //    パターンD
            //        SortedSet で重複のない List を作成する
            ///////////////////////////////////////////////////////////////////////////////
            sw.Reset();
            sw.Start();
 
            SortedSet sset = new SortedSet();
 
            for (int i = 0; i < values_List.Count; i++)
            {
                sset.Add(values_List[i]);
            }
 
            List ssetList = sset.ToList();
 
            sw.Stop();
            Console.WriteLine(" SortedSet 終了");
 
            ts = sw.Elapsed;
            w.WriteLine("");
            w.Write("*              重複のない sset の個数:");
            w.WriteLine(hash.Count);
            w.Write("           重複のない sset の作成時間:");
            w.WriteLine($" {ts.Hours}時間 {ts.Minutes}分 {ts.Seconds}秒 {ts.Milliseconds}ミリ秒");
 
#if (OUTPUT_VALUES)
            w.WriteLine(string.Format("{0,10}", "Index") + ":" + string.Format("{0,20}", "Values"));
            for (int i = 0; i < ssetList.Count; i++)
            {
                w.WriteLine(string.Format("{0,10}", i) + ":" + string.Format("{0,20}", ssetList[i]));
            }
#endif
 
            ///////////////////////////////////////////////////////////////////////////////
            // 終了処理
            ///////////////////////////////////////////////////////////////////////////////
            w.Close();
            Console.WriteLine("");
            Console.Write("何かキーを押して下さい。");
            Console.ReadKey();
        }
    }
}



結果

ちょっと見づらいですが、結果です。
テキストエディタにコピペしてもらうと、もっと見やすくなると思います。


*   値のランダムな values List の個数:60000
                               重複数:2
値のランダムな values List の作成時間: 0時間 0分 0秒 1ミリ秒
 
*          values List の空ループ時間: 0時間 0分 0秒 0ミリ秒
 
*             重複のない list1 の個数:30000
          重複のない list1 の作成時間: 0時間 0分 2秒 619ミリ秒
 
*             重複のない list2 の個数:30000
          重複のない list2 の作成時間: 0時間 0分 8秒 441ミリ秒
 
*              重複のない hash の個数:30000
           重複のない hash の作成時間: 0時間 0分 0秒 1ミリ秒
 
*              重複のない sset の個数:30000
           重複のない sset の作成時間: 0時間 0分 0秒 17ミリ秒



コメント

HashSet と SortedSet の威力が絶大でした。

HashSet と SortedSet では HashSet が圧倒的に早かったです。
SortedSet はソートしてる分遅かったのでしょうか。



以上

Windows で JUMAN と KNP と pyknp を使う



こんにちは。
仕事の自動化にやりがいと達成感を感じるガッくんです。


この記事の目次



背景・目的


自然言語処理で感情分析やりたいと思っています。

感情分析の前処理として、ちょっと調べてみると、
JUMAN という形態素解析
KNP という構文解析
pyknp という Python バインディング
を使うのが良さそうでした。

しかし、 Windows 、 python3 という組み合わせでは JUMAN/KNP が shift-jis で python3 が utf-8 なので、 コーデックエラーが出ます。

このエラー回避にかなりハマったので、とりあえず、インストールして、形態素解析までたどり着いた方法をまとめます。



動作環境


Windows 7
・winpython 64bit 3.7.2.0
・JUMAN 7.0
・KNP 4.11
・pyknp 0.22

事前に winpython はインストールされていることを前提とします。

winpython のインストールディレクトリは下記とします。
インストールディレクトリ:C:\WPy64-3720



プログラム

インストール

インストールについては以下のサイトを参考にしました。

Windows 7 64bit に JUMAN/KNP(構文解析器)を導入しました - Qiita

リンクのサイト通りにやると特になんの問題も無く下記がインストール出来ました。
• KNP Ver.4.11 (Windows 64bit版)
• Juman Ver 7.0 (Windows 64bit版)
• pyknp(pyknp-0.22.tar.gz)

なお、 KNP と Juman のインストールフォルダは全てデフォルトにしています。
この後、エラー回避で対象となるフォルダ、ファイルを示していますが、デフォルトインストールした場合のフォルダ、ファイルになりますので、ご了承下さい。

【参考サイトの補足】
python コマンドは WinPython Command Prompt から実行します。

図1 python コマンド実行方法

テストソースコード


#-*- encoding: utf-8 -*-
from pyknp import Juman
 
juman = Juman(jumanpp=False)
 
result = juman.analysis("最近、痛ましい事件や事故のニュースが多い。")
 
for mrph in result.mrph_list():
    print (mrph.midasi)

テストソースコード


# -*- coding: utf-8 -*-
import pyknp
 
knp = pyknp.KNP()
line = '最近、痛ましい事件や事故のニュースが多い。'
result = knp.parse(line)
result.draw_tag_tree()

エラーコード

テストソースコードを実行すると、コーデックエラーとなり、以下の様なエラーメッセージが表示されました。

〜 'utf-8' codec can't decode 〜



エラー回避

参考サイトによる pyknp のエラー回避

インターネットに参考になるサイトがありました。
サイトの内容とエラーが合っているので、やってみました。

PyKNPをWindows10にインストールする(お土産付き) - Qiita

ディレクトリ:C:\Program Files\pyknp\pyknp-0.22.tar\dist\pyknp-0.22\pyknp-0.22\pyknp\juman
ファイル:juman.py
 
52行目
変更前
            self.process = subprocess.Popen('bash -c "%s"' % command, env=env,
変更後
            self.process = subprocess.Popen('"%s"' % command, env=env,



ディレクトリ:C:\Program Files\pyknp\pyknp-0.22.tar\dist\pyknp-0.22\pyknp-0.22\pyknp\juman
ファイル:juman.py

66行目
変更前
    def query(self, sentence, pattern):
        assert(isinstance(sentence, six.text_type))
        self.process.stdin.write(sentence.encode('utf-8')+six.b('\n'))
        self.process.stdin.flush()
        result = ""
        while True:
            line = self.stdouterr.readline()[:-1].decode('utf-8')
            if re.search(pattern, line):
                break
            result = "%s%s\n" % (result, line)
        return result
 
変更後
    def query(self, sentence, pattern, encoding="ms932"):
        assert(isinstance(sentence, six.text_type))
       self.process.stdin.write(sentence.encode(encoding)+six.b('\n'))
        self.process.stdin.flush()
        result = ""
        while True:
            line = self.stdouterr.readline()[:-1].decode(encoding)
            if re.search(pattern, line):
                break
            result = "%s%s\n" % (result, line)
        return result

このエラー回避でエラーメッセージに変化が現れた。
juman が見つからないといったエラーになった。
そして、独自にエラー回避を行った。

独自のエラー回避①

エラーメッセージで knp.py の処理が表示されていた。
KNP のコンストラクタで jumanpp を強制的に使用する初期化だった。
jumanpp はそもそもインストールしていないので、コンストラクタを juman を使用する初期化に書き換えた。

ディレクトリ:C:\WPy64-3720\python-3.7.2.amd64\Lib\site-packages\pyknp\knp
ファイル:knp.py
 
30行目
変更前
    def __init__(self, command='knp', server=None, port=31000, timeout=60,
                 option='-tab', rcfile='', pattern=r'EOS',
                 jumancommand='jumanpp', jumanrcfile='', jumanpp=True):
        self.command = command
        self.server = server
        self.port = port
        self.timeout = timeout
        self.option = option.split()
        self.rcfile = rcfile
        self.pattern = pattern
        self.socket = None
        self.subprocess = None
        self.jumanpp = jumanpp
 
変更後
    def __init__(self, command='knp', server=None, port=31000, timeout=60,
                 option='-tab', rcfile='', pattern=r'EOS',
                 jumancommand='jumanpp', jumanrcfile='', jumanpp=False):
        self.command = command
        self.server = server
        self.port = port
        self.timeout = timeout
        self.option = option.split()
        self.rcfile = rcfile
        self.pattern = pattern
        self.socket = None
        self.subprocess = None
        self.jumanpp = jumanpp

ここで、またエラーとなった。
コーデックを utf-8 で行う処理が残っていた。
そこで、独自のエラー回避②を行った。

独自のエラー回避②

参考サイトによる pyknp のエラー回避とやっている事は同じです。

ディレクトリ:C:\WPy64-3720\python-3.7.2.amd64\Lib\site-packages\pyknp\juman
ファイル:process.py
 
64行目
変更前
    def query(self, sentence, pattern):
        assert(isinstance(sentence, six.text_type))
        self.process.stdin.write(sentence.encode('uft-8')+six.b('\n'))
        self.process.stdin.flush()
        result = ""
        while True:
            line = self.stdouterr.readline().rstrip().decode('uft-8')
            if re.search(pattern, line):
                break
            result = "%s%s\n" % (result, line)
        return result
 
変更後
    def query(self, sentence, pattern, encoding="ms932"):
        assert(isinstance(sentence, six.text_type))
        self.process.stdin.write(sentence.encode(encoding)+six.b('\n'))
        self.process.stdin.flush()
        result = ""
        while True:
            line = self.stdouterr.readline().rstrip().decode(encoding)
            if re.search(pattern, line):
                break
            result = "%s%s\n" % (result, line)
        return result 



結果

テストソースコード

図2 テストソースコード①結果


テストソースコード

図3 テストソースコード②結果


図3 は等幅フォントではないため、罫線がズレて表示されていて、よく分からないので、テキストエディタにコピペして、ツリー構造がハッキリ分かる画像を4 に示します。


テストソースコード

図4 テストソースコード②結果



コメント

Windows でも python を使い倒すことに貢献できたら幸いです。

長くなったので、感情分析はまた、別の記事にします。



以上

10 秒で出来る形態素解析【python】【janome】【Windows】



こんにちは。
仕事の自動化にやりがいと達成感を感じるガッくんです。


この記事の目次



背景・目的


自然言語処理をやってみたくなったので、とりあえず形態素分析をやりました。



動作環境


Windows 7
・winpython 64bit 3.4.4
janome

事前に winpython はインストールされていることを前提とします。



プログラム

janome インストール

WinPython Command Prompt から pip でインストールします。

図1 janome インストール

コマンドはこちら

図2 janome インストール

ソースコード


from janome.tokenizer import Tokenizer

t = Tokenizer()

for token in t.tokenize(u'私はこの味が好ましくない。'):
    print(token)



結果


In [1]: runfile('C:/WinPython-64bit-3.4.4.6Qt5/settings/.spyder-py3/temp.py', wdir='C:/WinPython-64bit-3.4.4.6Qt5/settings/.spyder-py3')
私       名詞,代名詞,一般,*,*,*,私,ワタシ,ワタシ
は       助詞,係助詞,*,*,*,*,は,ハ,ワ
この      連体詞,*,*,*,*,*,この,コノ,コノ
味       名詞,一般,*,*,*,*,味,アジ,アジ
が       助詞,格助詞,一般,*,*,*,が,ガ,ガ
好ましく    形容詞,自立,*,*,形容詞・イ段,連用テ接続,好ましい,コノマシク,コノマシク
ない      助動詞,*,*,*,特殊・ナイ,基本形,ない,ナイ,ナイ
。       記号,句点,*,*,*,*,。,。,。
 
In [2]:

図3 結果



コメント

たったこれだけで形態素分析が出来ちゃいます。



以上

C# で 逆行列を求める



こんにちは。
仕事の自動化にやりがいと達成感を感じるガッくんです。


この記事の目次



背景・目的


C# ってベクトル計算、行列計算のライブラリが豊富ではありません。
私が知らないだけかもしれませんが。

実に簡単なアルゴリズムですが逆行列を解くプログラムを書いたので、まとめておきます。



動作環境


Windows 7
Visual Studio 2017



プログラム

ソースコード


using System;
using System.Collections.Generic;
 
namespace inverse_matrix
{
    class Program
    {
        static void Main(string[] args)
        {
            List> matrix = new List>();
 
            matrix.Add(new List());
            matrix[matrix.Count - 1].Add(1);
            matrix[matrix.Count - 1].Add(1);
            matrix[matrix.Count - 1].Add(-1);
 
            matrix.Add(new List());
            matrix[matrix.Count - 1].Add(-2);
            matrix[matrix.Count - 1].Add(-1);
            matrix[matrix.Count - 1].Add(1);
 
            matrix.Add(new List());
            matrix[matrix.Count - 1].Add(-1);
            matrix[matrix.Count - 1].Add(-2);
            matrix[matrix.Count - 1].Add(1);
 
            List> inv = matrixinv(matrix);
 
            for (int i = 0; i < inv.Count; i++)
            {
                for (int j = 0; j < inv[i].Count; j++)
                {
                    if (j == 0) Console.Write(string.Format("{0,10}", inv[i][j]));
                    else Console.Write(" , " + string.Format("{0,10}", inv[i][j]));
                }
                Console.WriteLine("");
            }
 
            Console.ReadKey();
        }
 
        private static List> matrixinv(List> matrix)
        {
            // 戻り値 List
            List> matrixinv = new List>();
 
            // matrix の行数取得
            int n = matrix.Count;
 
            // matrix の列数が行数と同じであることの確認
            int m = -1;
            for (int i = 0; i < n; i++)
            {
                m = matrix[i].Count;
                if(m != n)
                {
                    return matrixinv;
                }
            }
 
            int max;
 
            // matrixinv に単位行列を格納する
            for (int i = 0; i < n; i++)
            {
                // matrixinv に行を追加する
                matrixinv.Add(new List());
 
                // 1 行ずつ値の代入
                for (int j = 0; j < n; j++)
                {
                    if (i == j) matrixinv[matrixinv.Count - 1].Add(1.0); // 1 を代入
                    else matrixinv[matrixinv.Count - 1].Add(0);          // 0 を代入
                }
            }
 
            // 逆行列の計算
            for(int k = 0; k < n; k++)
            {
                max = k;
                double tmp;
 
                for(int j = k + 1; j < n; j++)
                {
                    if (Math.Abs(matrix[j][k]) > Math.Abs(matrix[max][k]))
                    {
                        max = j;
                    }
                }
 
                if (max != k)
                {
                    for (int i = 0; i < n; i++)
                    {
                        // 入力行列側
                        tmp = matrix[max][i];
                        matrix[max][i] = matrix[k][i];
                        matrix[k][i] = tmp;
                       
                        // 単位行列側
                        tmp = matrixinv[max][i];
                        matrixinv[max][i] = matrixinv[k][i];
                        matrixinv[k][i] = tmp;
                    }
                }
 
                tmp = matrix[k][k];
 
                for (int i = 0; i < n; i++)
                {
                    matrix[k][i] /= tmp;
                    matrixinv[k][i] /= tmp;
                }
 
                for (int j = 0; j < n; j++)
                {
                    if (j != k)
                    {
                        tmp = matrix[j][k] / matrix[k][k];
                        for (int i = 0; i < n; i++)
                        {
                            matrix[j][i] = matrix[j][i] - matrix[k][i] * tmp;
                            matrixinv[j][i] = matrixinv[j][i] - matrixinv[k][i] * tmp;
                        }
                    }
                }
            }
 
            //逆行列が計算できなかった時
            for (int j = 0; j < n; j++)
            {
                for (int i = 0; i < n; i++)
                {
                    if (double.IsNaN(matrixinv[j][i]))
                    {
                        matrixinv[j][i] = 0; // NaN を ゼロ に置き換える
                    }
                }
            }
 
            // 戻り値
            return matrixinv;
        }
    }
} 



結果


図1 結果



コメント

他にも固有値解析や特異値分解などもまとめておきたいですね。



以上

C# で k-d tree を作る



こんにちは。
仕事の自動化にやりがいと達成感を感じるガッくんです。


この記事の目次



背景・目的


せっかく Class のことをおさらいしてきたので、最後(?)に Class を使ってオブジェクト指向な感じで k-d tree を構築するプログラムを書きました。



動作環境


Windows 7
Visual Studio 2017



プログラム

ソースコード


using System;
using System.Collections.Generic;
 
namespace k_d_tree
{
    class Program
    {
        static void Main(string[] args)
        {
            // ノードリストの作成
            List point = new List();
 
            // ノードリストにノード座標を入力していく
            point.Add(new Node(1, 2, 3));
            point.Add(new Node(2, 5, 4));
            point.Add(new Node(3, 9, 6));
            point.Add(new Node(4, 4, 7));
            point.Add(new Node(5, 8, 1));
            point.Add(new Node(6, 7, 2));
 
            // tree クラスのインスタンス作成
            tree t = new tree();
 
            // k-d tree の構築
            Node ret = t.Build(point, 0);
 
            // k-d tree のコンソール表示
            t.Disp(ret, 0, "");
            Console.WriteLine("何かキーを押して下さい.");
            Console.ReadKey();
        }
    }
 
    class Node
    {
        // メンバ
        public int ID;
        public List Vector = new List();
        public Node left_child;
        public Node right_child;
 
        // コンストラクタ
        public Node(int id, double x, double y)
        {
            ID = id;
            Vector.Add(x);
            Vector.Add(y);
        }
    }
 
    class tree
    {
        // k-d tree 構築用メソッド
        public Node Build(List nodeList, int depth)
        {
            if (nodeList.Count == 0)
            {
                return null;
            }
 
            int k = nodeList[0].Vector.Count;
 
            int axis = depth % k;
 
            nodeList.Sort(delegate (Node n1, Node n2)
            {
                if (n1.Vector[axis] > n2.Vector[axis])
                {
                    return 1;
                }
                else if (n1.Vector[axis] < n2.Vector[axis])
                {
                    return -1;
                }
 
                return 0;
            });
 
            int median = nodeList.Count / 2;
 
            List leftNodeList = new List();
            List rightNodeList = new List();
 
            for (int i = 0; i < median; i++)
            {
                leftNodeList.Add(nodeList[i]);
            }
 
            for (int i = median + 1; i < nodeList.Count; i++)
            {
                rightNodeList.Add(nodeList[i]);
            }
 
            Node node = nodeList[median];
            node.left_child = Build(leftNodeList, depth + 1);
            node.right_child = Build(rightNodeList, depth + 1);
 
            return node;
        }
 
        // コンソール表示用メソッド
        public void Disp(Node node, int depth, string LR)
        {
            if (node == null) return;
 
            Console.WriteLine(new string('-', depth * 2) + "> " + LR + "{0}:({1},{2})", node.ID, node.Vector[0], node.Vector[1]);
 
            Disp(node.left_child, depth + 1, "Left");
            Disp(node.right_child, depth + 1, "Right");
        }
    }
}



結果


図1 結果



コメント

ソートを使った k-d tree の構築はバランスの良い tree が出来ますが、ソートをするため計算コストが高いです。



以上

C# の Class の複雑なメンバの操作性



こんにちは。
仕事の自動化にやりがいと達成感を感じるガッくんです。


この記事の目次



背景・目的


下記の記事でメンバの操作性を確認したんですが、確認を忘れていたことがあったので、再度まとめました。

C# の Class の操作性 - 解析エンジニアの自動化 blog



動作環境


Windows 7
Visual Studio 2017



プログラム

ソースコード


using System;
using System.Collections.Generic;
 
namespace How_to_use_ClassList
{
    class Program
    {
        static void Main(string[] args)
        {
            // 変数への値の代入
            sample s = new sample();
            s.list.Add(new List());
            s.list[s.list.Count - 1].Add(10);
            s.list[s.list.Count - 1].Add(20);
            s.list[s.list.Count - 1].Add(30);
            s.list.Add(new List());
            s.list[s.list.Count - 1].Add(40);
            s.list[s.list.Count - 1].Add(50);
            s.list[s.list.Count - 1].Add(60);
 
            List s_list = new List();
            s_list.Add(s);
 
            // コンソール表示
            for (int i = 0; i < s_list.Count; i++)
            {
                for (int j = 0; j < s_list[i].list.Count; j++)
                {
                    for (int k = 0; k < s_list[i].list[j].Count; k++)
                    {
                        if (k == 0) Console.Write(s_list[i].list[j][k]);
                        else Console.Write(" , " + s_list[i].list[j][k]);
                    }
                    Console.WriteLine("");
                }
            }
 
            // 値を書き換えてみる
            s_list[0].list[0][0] = 200;
 
            // コンソール表示
            Console.WriteLine("");
            Console.WriteLine("");
            for (int i = 0; i < s_list.Count; i++)
            {
                for (int j = 0; j < s_list[i].list.Count; j++)
                {
                    for (int k = 0; k < s_list[i].list[j].Count; k++)
                    {
                        if (k == 0) Console.Write(s_list[i].list[j][k]);
                        else Console.Write(" , " + s_list[i].list[j][k]);
                    }
                    Console.WriteLine("");
                }
            }
 
            // 終了待機
            Console.ReadKey();
        }
    }
 
    class sample
    {
        public List> list = new List>();
    }
}



結果


図1 結果



コメント

どんなに複雑なデータ構造でも、値のやり取りが簡単です。

構造体だとこうはいかないです。



以上