LoginSignup
62
58

More than 5 years have passed since last update.

会計データを学習して、仕訳の入力時に摘要の内容から勘定科目を予測してみる

Last updated at Posted at 2017-03-06

はじめに

確定申告の時期になり、会計データを再確認すると勘定科目の間違いがちらほら見つかるので、機械学習で会計データを学習させて、勘定科目を予測できると良いのではないかと思い試してみました。

会計データの読込

会計ソフトからCSV形式でデータをエクスポートし、それを使います。
ちなみに、今回のデータは「JDL IBEX出納帳」というソフトのものを例に使用しています。

以下のコードでデータを読み込みます。

import pandas as pd

filename = "JDL出納帳-xxxx-xxxx-仕訳.csv"
df = pd.read_csv(filename, encoding="Shift-JIS", skiprows=3)

読み込んだデータから使用するデータを絞り込む。
ここでは、摘要と借方科目のコードと名称を使用します。

columns = ["摘要", "借方科目", "借方科目正式名称"]
df_counts = df[columns].dropna()

形態素解析

摘要のデータについて形態素解析により、文字データを指向性のある数値としてベクトル化します。

形態素解析にはJanomeというライブラリを使用します。

もし、インストールされていなければ、以下のコマンドでインストールしておく必要があります。

$ pip install janome

以下のコードで、摘要のデータをトークンにわけたデータに変換します。

from janome.tokenizer import Tokenizer

t = Tokenizer()

notes = []
for ix in df_counts.index:
    note = df_counts.ix[ix,"摘要"]
    tokens = t.tokenize(note.replace(' ',' '))
    words = ""
    for token in tokens:
        words += " " + token.surface
    notes.append(words.replace(' \u3000', ''))

この結果、以下のような変換が行われ、単語毎に半角スペースを入れた文字列になります。

元の摘要データ 「手土産代 BLUESKY羽田」
変化後のデータ 「手土産 代 BLUESKY 羽田」

この文字列を以下のコードでベクトル化し、入力データとして使用します。

from sklearn.feature_extraction.text import TfidfVectorizer

vect = TfidfVectorizer()
vect.fit(notes)

X = vect.transform(notes)

また、教師データとして勘定科目のコードを使用します。

y = df_counts.借方科目.as_matrix().astype("int").flatten()

機械学習

数値に変換したデータをクロスバリデーションで学習データと検証データに分割します。

from sklearn import cross_validation

test_size = 0.2
X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=test_size)

分割したデータを使って学習します。
ここではモデルとしてLinearSVCを使用します。

from sklearn.svm import LinearSVC

clf = LinearSVC(C=120.0, random_state=42)
clf.fit(X_train, y_train)

clf.score(X_test, y_test)

スコアは「0.89932885906040272」でした。

予測

学習した結果から、以下のようにテストデータを入力して、どんな勘定科目が予測されるか確認してみます。

tests = [
    "高速道路利用料",
    "パソコン部品代",
    "切手代"
]

notes = []
for note in tests:
    tokens = t.tokenize(note)
    words = ""
    for token in tokens:
        words += " " + token.surface
    notes.append(words)

X = vect.transform(notes)

result = clf.predict(X)

df_rs = df_counts[["借方科目正式名称", "借方科目"]]
df_rs.index = df_counts["借方科目"].astype("int")
df_rs = df_rs[~df_rs.index.duplicated()]["借方科目正式名称"]

for i in range(len(tests)):
    print(tests[i], "\t[",df_rs.ix[result[i]], "]")

出力結果は...

高速道路利用料   [ 旅費交通 ]
パソコン部品代   [ 消耗品費 ]
切手代   [ 通信費 ]

かなり良い感じ(^-^)

ちなみに振替伝票はもう少し工夫が必要ですね。

他にも月や曜日、決算の情報とかも利用できるともっと良いかなと思ったのですが、学習データの扱い方がいまいちわからなかったので、また後日調べようと思います。

さて、次は何しようかな。

(おまけ)学習と予測の切り離し

上述のプログラムをそのまま使おうとすると、実行するたびに実データを読込、学習してから予測するため、効率的とは言えません。
そこで、学習データを保存し、予測する部分では学習済データを読み込んで予測するように変更してみます。

学習結果の保存

前述のプログラムの最後に以下のようなコードを追加すると、学習データを保存することができます。

from sklearn.externals import joblib

joblib.dump(vect, 'data/vect.pkl')
joblib.dump(clf, 'data/clf.pkl')
df_rs.to_csv("data/code.csv")

学習結果の読込

新しいプログラムで、以下のように学習データを読み込みます。

import pandas as pd

filename = "data/code.csv"
df = pd.read_csv(filename, header=None)
df.index = df.pop(0)
df_rs = df.pop(1)

from sklearn.externals import joblib

clf = joblib.load('data/clf.pkl')
vect = joblib.load('data/vect.pkl')

予測

学習データを読み込んだら、続けて予測を実行します。

from janome.tokenizer import Tokenizer

t = Tokenizer()
tests = [
    "高速道路利用料",
    "パソコン部品代",
    "切手代",
]

notes = []
for note in tests:
    tokens = t.tokenize(note)
    words = ""
    for token in tokens:
        words += " " + token.surface
    notes.append(words)

X = vect.transform(notes)

result = clf.predict(X)

for i in range(len(tests)):
    print(tests[i], "\t[",df_rs.loc[result[i]], "]")

実行結果は...

高速道路利用料   [ 旅費交通 ]
パソコン部品代   [ 消耗品費 ]
切手代   [ 通信費 ]

できた!

62
58
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
62
58