見出し画像

【Python】画像検索で優良銘柄を探す!

画像化した財務情報を比較する事で
「似ている銘柄・優良銘柄を探せないか?」
というのが、今回の趣旨である。

Pythonを使えば、類似画像の検索ができそうだという事が分かり、画像化した財務データがあれば、優良銘柄を探すのに使えるのではないか?と思い付いたのだ。

今回の話は、多くの人には、あまり役に立たないかもしれない。財務データを画像化したデータが大量にある事を前提としているからだ。(しかし、Pythonを使って自動で大量の画像が準備できれば、このアイデアは役に立つかもしれない。)

私は、まだまだ、Pythonを勉強しだしたところで、私のパイソンのスキルなんて、初心者に毛が生えた程度である。略して言うと、パイ〇ンに毛が生えた程度である。略してしまうと、生えているのか生えていないのかどちらなのか良く分からなくなるが、

機械学習とか高度なことはやっていないことを予め断わっておきたい。

今回実施したことは、もっと単純で、画像データをハッシュ化して、その差分の大きさ(ハミングディスタンス)から類似画像を見つけるという事をやっただけである。

とりあえず、やった事を説明したい。

1.実例を使いながら概要の説明

簡単な実例を使いながら概要を説明したい。

まずは、「いらすとや」からフリー素材の画像をいつくか用意する。

画像3

それを下記の様に、Google Colabに画像をアップロードする。

画像4

次に必要なライブラリをインストールする。

pip install imagehash

下記のコードを実行する。

ポイントは、画像からハッシュ値を取得している部分と、差分を取得している部分ぐらいである。

ハッシュ値取得:imagehash.average_hash(Image.open(a))
差分取得   :diff = hash_org - hash_comp
from PIL import Image
import imagehash
import os
import cv2
import matplotlib.pyplot as plt
%matplotlib inline

#比較対象のオリジナル画像
org="./dog_pomeranian.png"
#画像を保存したディレクトリ
userpath = "./"

#画像の一覧をリスト化
image_files = []
f = [os.path.join(userpath, path) for path in os.listdir(userpath)]
for i in f:
   if i.endswith('.jpg') or i.endswith('.png'):
       image_files.append(i)
       
#画像をハッシュ化する関数(4種類あり)
def img_hash(a):
 hash_return = imagehash.average_hash(Image.open(a))
 # hash_return = imagehash.phash(Image.open(a))
 # hash_return = imagehash.dhash(Image.open(a))
 # hash_return = imagehash.whash(Image.open(a))
 return hash_return

#オリジナルをハッシュ化 
hash_org=img_hash(org)

#結果を保存する領域
result = []

#ハッシュ値を比較するループ処理
for comp in sorted(image_files):
#比較対象をハッシュ化
 hash_comp = img_hash(comp)
#差分を取得
 diff = hash_org - hash_comp
#ハミングディスタンスが20以下の物を保存
 if diff < 20:
   result.append([diff,comp])
result.sort()

#オリジナル画像を表示 
img = Image.open(org)
plt.imshow(img)
plt.axis("off")
plt.figure(figsize=(12,12))
plt.subplots_adjust(wspace=0.1,hspace=0.1)

#ハミングディスタンスが20以下の画像を表示 
for i, item in enumerate(result):
   plt.subplot(3, 5, i+1)
   img = Image.open(item[1])
   plt.imshow(img)
   plt.title(item[0])
   plt.axis("off")

#文字列として結果を表示   
display(result)

実行すると下記の様な結果が出力される。

ポメラニアンの画像と似ている順(ハミングディスタンスが近い)に並べると下記の通りである。

画像3

画像の上の数値(ハミングディスタンス)が小さい程、画像が似ていることを示しているのだが、確かに、「7の人間ドック」(この画像もよくわからないが・・・)ぐらいまではある程度似ているようにも思える。しかし、「16あたりになると、目潰しをし合って」いて何が起こっているのか良く分からない状態になる

もう一度、実行し、アヒルの画像と似ている順(ハミングディスタンスが近い)に並べると下記の通りである。

画像4

画像の上の数値(ハミングディスタンス)が「0には眉毛を書いたアヒル」が並んでいていい感じである。しかし「15にはアヒルぐちの女性」がならんでいて、おまけには、なんやら「怪獣か半魚人みたいなのも」並んでいてカオスである。「アヒルのおまるは19」になっているのは意外である。

次に、バーニーズマウンテンドッグの画像と似ている順(ハミングディスタンスが近い)に並べると下記の通りである。

画像7

まぁ、それなりに、いい感じに並んでいるようにも見えるが、19ぐらいまで離れると、中二病を発症してしまっていてカオスである。

この画像、よく見ると、左目に眼帯をして、右手に包帯を巻いて、二か所の力を封印しているようである。そして、魔法陣の上でなんやらを召喚しようとしていて、何重にも秘めた力が感じられる画像になっている。なんの解説か分からなくなってきたので、話を戻そう。

これらを見てみると、ハミングディスタンスが遠くなると、カオスだが、小さいものは確かに似ていそうだという事が分かる。

因みにハミングというのは鼻歌ではなく、アメリカの数学者、計算機科学者のリチャード・ハミングに由来する。

2.類似画像の判定を銘柄分析に適用

では、類似画像の判定を銘柄分析に適用していこう。

まず、大量の財務データの準備します!
(ここからハードルが上がってしまい恐縮です…)

実は、少し前に、有名な企業や、良さそうな条件でフィルタリングした数百銘柄の財務データを手作業でグラフ化して、下記の様に画像で保存したことがあったのです。(今では、気の遠くなる様な作業だが、Netflixでスパイダーマンやフラッシュを見ながらやっていたような記憶がある。そんな作業が、業種ごとの傾向や、企業の財務の良し悪しや、儲かり易い業種は何か?みたいなざっくりとした感覚を養うのに役立ったように思う。)

画像5

この画像化した財務情報は、10年間のPL,BS,CF,成長率や自社株買い、キャッシュコンバージョンサイクル配当性向など、いろいろな情報を網羅しており、結構優れものである。

画像6

この画像データを使い、下記のコードを使って、類似画像を抽出する。

from PIL import Image
import imagehash
import os
import cv2
import pandas as pd

#画像の保存ディレクトリ
search_path = "./"

#画像一覧の取得
image_files = []
f = [os.path.join(search_path, path) for path in os.listdir(search_path)]
for i in f:
   if i.endswith('.png') or i.endswith('.jpg') :
       image_files.append(i)

#処理データの保存領域
df=pd.DataFrame(data=None, index=None, columns=None, dtype=None, copy=False)
df2=pd.DataFrame(data=None, index=None, columns=None, dtype=None, copy=False)

#すべての画像のハッシュ値の算出
for img in sorted(image_files):
   comp_img_path = img
   try:
       comp_hash = imagehash.average_hash(Image.open(comp_img_path))
       #処理データ保存領域に追記
       df=df.append({"img":img,"hash":comp_hash},ignore_index=True)
   except cv2.error:
       ret = 100000

#繰り返し処理でハミングディスタンスを計算(重複しているのでコーディング的に美しくないです・・・)
for i in range(len(df)):
   for j in range(len(df)-1):
       if df.img[i] == df.img[j]:
           continue
       haming = df.hash[i] - df.hash[j]
       #ハミングディスタンスが2以下のものを保存領域へ追記
       if haming < 2:
           df2=df2.append({"targ_img":df.img[i],"comp_img":df.img[j],"haming":haming},ignore_index=True)
print("----END-----")

#結果をソートしてCSVファイルへ出力
df2.sort_values(by="haming",ascending=True).to_csv("ruiji.csv")

上記を実行すると、ハミングディスタンスが「2以下」の類似した企業がリスト化される。前の例で確認した様に2以下という数値はかなり似ている事を表している。

実行結果から、全てではないが、ハミングディスタンスが「0」と判定された企業をいくつか列挙してみようかと思う。

コルゲートとキンバリークラークス

画像8

画像9

NVIDIAとADI

画像10

画像11

セールスフォースとガートナー

画像12

画像13

ゼネラルミルズとユニリーバとケロッグ

画像14

画像15

画像16

どうだろうか?
結構、似た画像になっていないだろうか?
これらの結果が示すのは、似た業種は似た様なPL,BS,CFになるという事を示している様に思う。

余程の突出した独自性や経営判断の違いがない限り、業界全体の盛衰に従いながら、同業種の企業と似た売上の推移になり、利益率キャッシュフローバランスシートの配分配当性向も、棚卸資産回転率キャッシュコンバージョンサイクルも似てくるという事を表している様に思う。

「突出した独自性や経営判断の違いが無い限り」と、述べたのは、例えば、例外的な事例を言うと、VisaとMasterCardのBSは著しく異なる。これは、VisaがM&AでVisaヨーロッパを買収したことにより、無形資産の割合が大きくなっているためである。この様に、M&A戦略の違いにより、BSが大きく異なったりすることもある。しかし、大きな傾向として、似た業種は似た財務になって来るように思われる。

これらを踏まえて、思うのは、
儲かっている業界を見つけて投資する!」
成長している業界を見つけて投資する!」
儲かり易い業種・事業を見つけて投資する!」
という事の様に思われる。

後半は、実施するにはハードルが高くなってしまいましたが、試みとしては、なかなか興味深い内容になったのではないでしょうか?

何かの役に立てば幸いです。

おつかれさん「缶コーヒー一杯ぐらい、ご馳走してあげよう」という太っ腹な方がいれば、よろしくお願いします!
課金しなくても、参考になったら、「ハートボタン」をクリックしたり、「リツイート」してくれると読まれる可能性があがるので嬉しいです。やる気が出ます。よろしくお願いします!

おまけ

出力された類似する企業のリストを確認すると、テンセントバークシャーが似ていると表示されていて、「えっ!?」ってびっくりしたんだけど、画像を開いて確認してみたら、テンセントの財務データを、間違えてバークシャーの名前で保存していただけでした・・・

ここから先は

0字

¥ 100

この記事が気に入ったらサポートをしてみませんか?