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

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

コピペで音声データの作成アプリが出来るようになる【Windows】【HTML】【JavaScript】【VBS】



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


この記事の目次



背景・目的


なんのキッカケかは忘れましたが、音声データの作成をやってみたくなり、調べたところ簡単だったので、雑ですが、音声データ作成アプリっぽいものを作りました。



動作環境


Windows 7
・HTML
JavaScript
VBScript

また、音声読み上げに関するランタイム、ライブラリは画像の通りです。




構成


3 つのファイルから構成されるアプリにしました。

デスクトップに speak というフォルダを作成して、 3 つのファイルを保存しました。




プログラム

speak.html ソースコード


<html>
        <head>
                <title>テキスト読み上げ音声ファイルメーカー</title>
                <script language="javascript" type="text/javascript">
                        function OnLinkClickAudition() {
                                var txt = document.form1.msg.value;
                                var sh = new ActiveXObject("WScript.Shell");
                                sh.Exec("cmd /C wscript C:\\Users\\UserName\\Desktop\\speak\\Speak_Audition.vbs " + txt);
                                sh.null;
                        }
                        function OnLinkClickOutput() {
                                var txt = document.form1.msg.value;
                                var sh = new ActiveXObject("WScript.Shell");
                                sh.Exec("cmd /C wscript C:\\Users\\UserName\\Desktop\\speak\\Speak_Output.vbs " + txt);
                                sh.null;
                        }
                </script>
                <style type="text/css">
                        .btn-real-dent {
                                /*周りの凹み*/
                                display: inline-block;
                                position: relative;
                                text-decoration: none;
                                color: rgba(3, 169, 244, 0.54);
                                width: 100px;
                                height: 100px;
                                border-radius: 50%;
                                text-align: center;
                                background: #f7f7f7;
                                box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.08);
                        }
                        .btn-real-dent i {
                                /*ボタン自体*/
                                position: absolute;
                                content: '';
                                width: 80px;
                                height: 80px;
                                line-height: 80px;
                                left: 10px;
                                top: 9px;
                                border-radius: 50%;
                                font-size: 30px;
                                background-image: linear-gradient(#e8e8e8 0%, #d6d6d6 100%);
                                text-shadow: 1px 1px 1px rgba(255, 255, 255, 0.66);
                                box-shadow: inset 0 2px 0 rgba(255,255,255,0.5), 0 2px 2px rgba(0, 0, 0, 0.19);
                                border-bottom: solid 2px #b5b5b5;
                        }
                        .btn-real-dent .fa:active {
                                box-shadow: inset 0 1px 0 rgba(255,255,255,0.5), 0 2px 2px rgba(0, 0, 0, 0.19);
                                border-bottom: solid 2px #d8d8d8;
                        }
                        .textlines {
                                padding: 0.5em;          /* 内側の余白量 */
                                background-color: snow;  /* 背景色 */
                                width: 40em;             /* 横幅 */
                                height: 350px;           /* 高さ */
                                font-size: 1em;          /* 文字サイズ */
                                line-height: 1.2;        /* 行の高さ */
                        }
                </style>
        </head>
        <body>
                <form name="form1">
                        <p>
                                <textarea name="msg" cols="30" rows="7" class="textlines"></textarea>
                        </p>
                </form>
                <a href="#" class="btn-real-dent" onClick="OnLinkClickAudition()">
                        <i class="fa fa-home">試聴</i>
                </a>
                <a href="#" class="btn-real-dent" onClick="OnLinkClickOutput()">
                        <i class="fa fa-home">出力</i>
                </a>
        </body>
</html>


Speak_Audition.vbs ソースコード


cntArgs = WScript.Arguments.Count
 
If cntArgs <> 1 Then
        WScript.Echo "引数が" & intArgsCount & "個渡されました。" & vbCrLf _
                                & "指定可能な引数の数は 1 個なので処理を中止します。"
        ' 処理を中断
        WScript.Quit
End If
 
arg = WScript.Arguments(0)
 
Set tts = WScript.CreateObject("Speech.SpVoice")
tts.Rate = 2
tts.Speak(arg)


Speak_Output.vbs ソースコード


 
cntArgs = WScript.Arguments.Count
 
If cntArgs <> 1 Then
        WScript.Echo "引数が" & intArgsCount & "個渡されました。" & vbCrLf _
                                & "指定可能な引数の数は 1 個なので処理を中止します。"
        ' 処理を中断
        WScript.Quit
End If
 
arg = WScript.Arguments(0)
 
Set tts = WScript.CreateObject("Speech.SpVoice")
Set stream = WScript.CreateObject("Speech.SpFileStream")
tts.Rate = 2
stream.Open "speak.wav", 3
Set tts.AudioOutputStream = stream
tts.Speak(arg)
stream.Close



結果

インターフェースを図1 に示します。


図1 インターフェース


視聴ボタンを押すとテキストを読み上げた音声がスピーカーから流れます。

出力ボタンを押すとデスクトップに図2 のファイルが出来ます。

図2 出力ファイル



コメント

使い道はあまり思いつかないですが、たった 3 つのファイルを作成するだけで音声データが作成出来ました。



以上

python で単語感情極性対応表を使った感情分析〜失敗!?〜



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


この記事の目次



背景・目的


前回の記事で『単語感情極性対応表』という辞書の使い方について練習しました。

今度は実際に使ってみます。



動作環境


Windows 7
・winpython 64bit 3.4.4



プログラム

ソースコード


#-*- encoding: utf-8 -*-
from pyknp import Juman
import pandas as pd
 
strlen = 10
 
###############################################################################
# 形態素解析
###############################################################################
 
# 形態素分析器 juman のインスタンス作成
juman = Juman(jumanpp=False)
 
# 形態素解析
text = '最近、痛ましい事件や事故のニュースが多い。'
result = juman.analysis(text)
 
# 形態素解析結果表示 および numpy 配列作成
print('*** 形態素解析結果 ***')
print('原文'.ljust(strlen, ' ') + '原形'.ljust(strlen, ' ') + '品詞'.ljust(strlen, ' ') + '分類'.ljust(strlen, ' '))
targetwords = []
for mrph in result.mrph_list():
    print(mrph.midasi.ljust(strlen, ' ') + mrph.genkei.ljust(strlen, ' ') + mrph.hinsi.ljust(strlen, ' ') + mrph.bunrui.ljust(strlen, ' '))
    targetwords.append(mrph.genkei)
print()
 
###############################################################################
# 単語感情極性解析
###############################################################################
 
# 単語感情極性対応表 のパスを設定する
filepath='C:\\Users\\UserName\\Desktop\\dictionary\\pn_table.txt'
print('*** 単語感情極性対応表 ***')
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))
 
# 単語感情極性解析
print('*** 単語感情極性解析結果 ***')
for w in targetwords:
    if w in pn_dict.keys():
        print(w.ljust(strlen, ' ') + str(pn_dict[w]).ljust(strlen, ' '))
    else:
        print(w.ljust(strlen, ' ') + '無し'.ljust(strlen, ' '))
print()



結果


In [1]: runfile('C:/WPy64-3720/settings/.spyder-py3/jumanknptest5.py', wdir='C:/WPy64-3720/settings/.spyder-py3')
*** 形態素解析結果 ***
原文        原形        品詞        分類        
最近        最近        名詞        時相名詞      
、         、         特殊        読点        
痛ましい      痛ましい      形容詞       *         
事件        事件        名詞        普通名詞      
や         や         助詞        接続助詞      
事故        事故        名詞        普通名詞      
の         の         助詞        接続助詞      
ニュース      ニュース      名詞        普通名詞      
が         が         助詞        格助詞       
多い        多い        形容詞       *         
。         。         特殊        句点        
 
*** 単語感情極性対応表 ***
dictionary path = C:\Users\UserName\Desktop\dictionary\pn_table.txt
 
*** 単語感情極性解析結果 ***
最近        -0.0125929
、         無し        
痛ましい      -0.997224 
事件        -0.8599600000000001
や         -0.278384 
事故        -0.9970530000000001
の         無し        
ニュース      -0.391963 
が         無し        
多い        無し        
。         無し        
 
 
In [2]:



コメント

分析速度は悪くなかったと思います。

『最近』や『ニュース』がネガティブな数値を示しています。

辞書を見てみると、そんなにネガティブではない単語にネガティブな数値が与えられているモノが多数あります。

ポジティブとネガティブの閾値など、単語感情極性対応表をもっと理解する必要がありそうです。



以上

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 結果



コメント

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



以上