投資のためのデータサイエンス

個人の投資活動に役立つデータ分析にまつわる話題を綴ります。

データサイエンスのおすすめオンライン記事(12月4日付)

「実質ゼロコロナ」で安心しかけたのもつかの間、「オミクロン株」の脅威に一喜一憂する日々となってしまった。ギリシャ文字が全部終わってもまだ新たな変異株が出現するのか?そうしたらどう名付けるのか?などど考えてしまう。今年も残すところ一ヶ月。来年こそはコロナに振り回されない一年になってもらいたいと願うばかりである。
今回も統計やPythonプログラミングなどの最近の記事からいくつかピックアップして紹介したい。

最急降下法入門
towardsdatascience.com
Pythonを用いる、機械学習の最適化で用いられる最急降下法チュートリアル記事

Python 3.9の新機能の解説
dev.to
Python 3.9で新たに加わった機能を具体的例題で解説している

線形回帰の実践的ガイド
towardsdatascience.com
線形回帰の入門チュートリアル記事。探索的データ解析(EDA)、Feature Engineeringといったデータ分析の実務面から入る形で解説されている。

よりよい関数を記述するための私のPython実践
towardsdatascience.com
「関数名の付け方」「より少ないコードが良い」など、筆者がおすすめするPython関数の書き方のコツを解説している。

ここ50年間での最も重要な統計学のアイデア
arxiv.org
無料ダウンロード可能なPDF形式の論文へのリンク。「ブートストラップやシミュレーションに基づく推論」「ベイジアン多段階モデル」「探索的データ解析」などの近年開発された統計学の概念が紹介されている。

TF-IDFとコサイン類似度を用いたおすすめ文書の抽出

昨今のECサイトでは、リコメンド機能によりユーザがさらに買いたいと思うような商品を提案して顧客体験を向上させることが一般的になっています。この背景にある技術は、一つには日本語を自動的に品詞に分解して「わかち書き」にする技術(形態素解析)、もう一つは文章間の「類似度」を評価する技術です。ここでは、あるPCユーザが使用しているアプリ名のリストから、関連するソフトウェアの脆弱性に関するニュース記事を抽出するプログラムを書いてみます。

# ライブラリのインポート
import pandas as pd
import numpy as np
from janome.tokenizer import Tokenizer
from janome.analyzer import Analyzer
from janome.tokenfilter import POSStopFilter
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

Python形態素解析のためのライブラリとしてはmecabjanomeがありますが、janomeの方がより高速なのでここではjanomeを用います。まず形態素解析のためのTokenizerインスタンスを生成し、名詞以外の品詞を読み捨てするように設定します。

tokenizer = Tokenizer()
# 読み捨てるトークンの品詞を指定する
token_filters = [POSStopFilter(['記号','助詞','助動詞','動詞'])]
anal = Analyzer(tokenizer=tokenizer, token_filters=token_filters)

次に、あらかじめスクレイピングで取得しておいたソフトウェアの脆弱性に関するニュース記事のデータを読み込みます。

 # 列'header','body'を持つ記事テキストのcsvファイルを読み込む
 df1 = pd.read_csv('/content/drive/My Drive/Colab Notebooks/Biglobe_articles.csv',encoding='cp932')
 df2 = df1.loc[:,['header','body']]
 df2.head(3)

f:id:nicjps230:20211201230005j:plain
次に、対象テキスト文字列を取り出して形態素解析により分かち書き文を作ります。

df2 = df2.assign(wakati='')
# 対象テキスト文字列を一行ずつ取り出して分かち書きに変換する
for i in range(len(df2)):
  texts_flat = df2.iloc[i,1]
  tokens = anal.analyze(texts_flat)
  df2['wakati'][i] = ' '.join([t.surface for t in tokens])
df3 = df2.dropna(how='all')
df3.head(3)

f:id:nicjps230:20211201230033j:plain
次に、類似度評価計算の準備をします。ユーザが使用しているアプリ名を空白で区切って並べ、最後に「脆弱性」を付け加えた文字列を作成します。

# コサイン類似度のしきい値を定める
sim_thresh = 0.05
# 分かち書きをリストに、ヘッダと本文をNumpy配列に格納する
corpus = df3['wakati'].tolist()
header = np.array(df3['header'].tolist())
body = np.array(df3['body'].tolist())
# ユーザの利用しているアプリケーションを記述した文書を指定する
user_app = ['Google Chrome Microsoft Excel PowerPoint Python Anaconda SAKURA Editor Adobe Acrobat 脆弱性']

最後に、ターゲット文書とのコサイン類似度(ベクトル空間モデルにおいて、文書同士を比較する際に用いられる類似度計算手法)を求め、近い文書を取り出します。まずTF-IDF(Term Frequency, Inverse Document Frequency: 文書中に含まれる単語の重要度を評価する手法の1つ)によりスコアベクトルを作成し、それをもとにコサイン類似度を計算します。

# 結果から取り除くエスケープ文字を指定する
bad_chars = ["\n","\t","\r"]
# ユーザアプリの文書をニュース記事リストの先頭に挿入する
docs = user_app + corpus
# TF-IDFベクトル化する
vectorizer = TfidfVectorizer(max_df=0.9)
X = vectorizer.fit_transform(docs)
# コサイン類似度を計算する
sim = cosine_similarity(X)
# ターゲット文書に関わる一行目だけ残し、最初の要素は自分との比較なので取り除く
simil = sim[0][1:]
# コサイン類似度がしきい値を超えるインデックスを取得する。np.where結果はtuple
relev_index = np.where(simil > sim_thresh)[0]
# 取得したインデックスでヘッダと本文を抽出する
relev_head = header[relev_index]
print(relev_head)
relev_body = body[relev_index]
relev_body_r = []
for s in relev_body:
  relev_body_r.append(''.join((filter(lambda i: i not in bad_chars, s))))
print(relev_body_r)

f:id:nicjps230:20211201230103j:plain
使用しているアプリに関連する脆弱性記事が取り出せました。

Dashによるwebアプリの構築の基礎

Pythonによってデータの分析をして得られたグラフなどのアウトプットについては、画像ファイルに保存して、Word文書やPowerPointのスライドに貼り付けて報告資料にする、というのが最も一般的でしょう。一方、実務ではエンドユーザが自ら分析したい変数や条件を指定してプログラムを動かして結果を得るようにする、すなわちプログラムを実装することが求められる場合も多くあります。
このためPythonにもエンドユーザが直接扱えるwebアプリを構築するためのツールが多数提供されています。ここでは、その中の一つであるDashライブラリを用いて、ユーザが指定したデータ表を出力できるプログラムを作成します。
DashをJupyter Notebook (Google Colaboratory)上で動かすためには、普通のDashの代わりにJupyter Dashライブラリを用います。ここでは全国都道府県の様々な指標を収録したエクセルファイル(データ出典:https://www.nstac.go.jp/SSDSE/)から、ドロップダウンリストで指定された都道府県のデータ表を表示してみます。

# ライブラリのインポート
import numpy as np
import pandas as pd
from jupyter_dash import JupyterDash
import pandas as pd
import numpy as np
import dash_html_components as html
import dash_core_components as dcc
from dash import dash_table as dt
import plotly.graph_objects as go
from dash.dependencies import Input, Output
from dash_table import DataTable, FormatTemplate
from dash_table.Format import Format

まず、原データのExcelファイルを読み込みます。

 df1 = pd.read_excel('/content/drive/My Drive/Colab Notebooks/都道府県各種指標.xlsx',sheet_name='data')
 df1.head(3)

f:id:nicjps230:20211127234202j:plain
このデータフレームの各種指標の列を縦に再展開します。

df501 = pd.melt(df1, id_vars=['年度','都道府県'], value_vars=df1.columns[3:])
df501.head()

f:id:nicjps230:20211127234222j:plain
次に、外部のスタイルシートを読み込み、JupyterDashの「箱」にあたるものと、画面に表示する列を定義します。

# 外部スタイルシートを読み込む
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
# JupyterDashの「箱」を作る
app = JupyterDash(__name__, external_stylesheets=external_stylesheets)
# 表示する列を定義する
columns1 = [
    dict(id='年度',name='年度'),
    dict(id='都道府県',name='都道府県'),
    dict(id='variable', name='指標'),
    dict(id='value', name='値')
]

次に、画面に表示するコンテンツとして、ドロップダウンリストとデータテーブルを定義します。ドロップダウンリストでは都道府県と指標を選び、これらをデータテーブルのフィルターとします。各コンテンツにはid=で参照用の名前をつけ、詳細は以下に続くコードで設定します。

# ドロップダウンリストを定義する
content1 = dcc.Dropdown(
    id = 'dropdown-for-pref', # id名はコールバックで必要
    options = [{'label':i,'value':i} for i in df501['都道府県'].unique()], # 値を選択する列を指定
    value = '東京都' # デフォルト値を設定
)
content2 = dcc.Dropdown(
    id = 'dropdown-for-variable', # id名はコールバックで必要
    options = [{'label':i,'value':i} for i in df501['variable'].unique()], # 値を選択する列を指定
    value = '総人口' # デフォルト値を設定
)
# データテーブルを定義する
content3 = html.Div(id='datatable-paging',children=[]) # id名はコールバックで必要

次に、上で定義した2つのコンテンツからなる画面のレイアウトを定義します。

# 画面のレイアウトを定義する
app.layout = html.Div([
                       html.Div(content1, style={'width': '25%', 'display': 'inline-block','margin-right': 10}),
                       html.Div(content2, style={'width': '25%', 'display': 'inline-block','margin-right': 10}),
                       content3
])

次に、データテーブルを描画する関数を定義します。データテーブルは一行おきに色を濃淡に分けて見やすくします。

# データテーブルを描画する関数を定義する
# 一行おきに色のコントラストをつけたデザインにする
def create_dash_table(df):
  return dt.DataTable(
      data=df.to_dict('records'),
      columns=columns1,
      style_cell={'fontsize':20, 'font-family':'IPAexGothic'},
      style_cell_conditional=[
                              {
                                  'if': {'column_id':c},
                                  'textAlign': 'left'
                              } for c in ['年度','都道府県']
      ],
      style_data={
          'color':'black',
          'backgroundColor':'white'
      },
      style_data_conditional=[
                          {
                              'if': {'row_index':'odd'},
                              'backgroundColor': 'rgb(220,220,220)',
                          }
      ],
      style_header={
          'backgroundColor':'rgb(210,210,210)',
          'color':'black',
          'fontWeight':'bold'
  })

続いてコールバックを定義します。ここでは、どこから入力してどこから出力するかを指定します。ここで上でつけたid名を使います。またcomponent_property=でその属性を指定します。コールバックにより起動される関数はその下に空行を挟まずに記述します。関数名は何でもかまいません。ここでは、ドロップダウンリストにより指定された都道府県と指標でデータをフィルターにかけ、データテーブルを再表示しています。

# コールバックを定義する(ドロップダウンリストで選択された値をもとに表を作成する)
# どこから入力し、どこへ出力するかを指定する
@app.callback(
    Output(component_id='datatable-paging',component_property='children'),
    [Input(component_id='dropdown-for-pref',component_property='value'),
    Input(component_id='dropdown-for-variable',component_property='value')]
)
def update_table(input_value1,input_value2): # 行間をあけずに関数部分を書く(関数名は何でも良い。引数は上で定義した入力が順に並ぶ)
  df511 = df501[df501['都道府県'] == input_value1] # 値を選択する列を指定
  df512 = df511[df511['variable'] == input_value2]
  df512.sort_values('年度', ascending=True,inplace=True)
  return create_dash_table(df512)

最後にサーバを起動します。この部分を実行すると、下にリンクのURLが表示され、それをクリックするとアウトプット画面が表示されます。

# サーバーを起動する
app.run_server()

f:id:nicjps230:20211127234318j:plain
上記画面のドロップダウンリストで都道府県と指標を選ぶとその都道府県の指標のデータテーブルが表示されます。
(2011/11/27 複数入力のドロップダウンリスト利用に変更しました)

データサイエンスのおすすめオンライン記事(11月4日付)

コロナ感染者もみるみるうちに「実質ゼロコロナ」といえるほどまで減少した。海外ではまだ多くの感染者を出している国もあり予断を許さないが、混雑した町並みや電車など、日常生活が戻ってきたと実感することが多くなった。
今回紹介する記事もストックにあったもので、夏頃に投稿されたものが多い。

DataSpell: データサイエンスのための新しいIDE
towardsdatascience.com
PyCharmを開発しているJet Brain社が新たに世に送り出すデータサイエンス用IDE。すでに日本語サイトもある。

fast.aiにおける多ラベル分類
towardsdatascience.com
一つの画像に複数の重要オブジェクトがある場合のラベル付けの方法について。
fast.aiは、理論や数学から入るBottom-upアプローチではなく、まずはコードを動かしてタスクを解くTop-downタイプのMOOC(大規模公開オンライン講座

Pythonを用いてGoogle Slidesの図を作る
towardsdatascience.com
Google APIとgslidesパッケージを利用して、Googleスライドを全てPythonで作る方法。

不動産、気象、機械学習における「場所」の重要性
medium.com
Kirk Borne氏のエッセイ。不動産や気象でよく言われる「一に場所、二に場所、三に場所」は機械学習アルゴリズムにもあてはまる。

実生活におけるマルコフモデルマルコフ連鎖
towardsdatascience.com
「マルコフ」は遷移確率が一つ前の状態にのみ依存するものであるが、一般にとっつきにくいこの概念を身近な生活上の例で説明している。

ログデータにおけるテキストデータ連続累積出現回数の算出

様々な活動を記録したログデータにおいて、あるパターンの文字列が何回連続して登場したかをカウントすることが必要になる場合があります。これは集計処理とは異なるため、コーディングは多少ややこしくなります。
ここでは例として、サッカーJリーグの歴代優勝チームのリストから、各年代毎に最多連覇のケースを求めます。

# ライブラリのインポート
import numpy as np
import pandas as pd

まず、Jリーグの歴代優勝チームを記録したデータファイルを読み込みます。

df1 = pd.read_excel('/content/drive/My Drive/Colab Notebooks/サッカーJリーグ.xlsx',sheet_name='winner')
df1.head()

f:id:nicjps230:20211027190938j:plain
次に、年代ごとに年間優勝チームの連続累積出現回数を求めます。
データフレームのあるカラムに対して、連続値の個数をカウントするには、値の変化点にフラグを立てて、cumsum()で階段状の累積和を求めます。 この累積和をグループ番号とすることで、ユニークなグループ化ができます。 あとはgroupbyのcumcount()で各グループの個数をカウントします。

df1.set_index('年代',inplace=True)
df1['win_cum'] = df1.groupby(level=0)['年間優勝'].transform(lambda y:y.groupby((y != y.shift()).cumsum()).cumcount()+1)
df1.head()

f:id:nicjps230:20211027191008j:plain
次に、年代毎に連続累積出現回数が最大の行を抽出します。 最大値タイが複数ケースある場合は複数行抽出されます。

df2 = df1.set_index('年度',append=True)
df3 = df2[df2.groupby(level=0)['win_cum'].apply(lambda x: x==x.max())]
df3

f:id:nicjps230:20211104102307j:plain

尚、2010年のJリーグ優勝チームは名古屋グランパスであり、年代で分けない場合でも鹿島アントラーズは三連覇で止まっています。
※2021年のJリーグ結果をふまえて更新しました。

データサイエンスのおすすめオンライン記事(10月20日付)

先週「ワーケーションツアー」なるものに参加した。様々な所から集まった参加者が観光を楽しみつつ、ある時間帯にはPCに向かって仕事をするのは異様な感じもしたが、休暇を楽しみつつ会社ネットワークにつないで「置いてきぼり」にならないようにするにはいい方法だとも思った。他の参加者との交流もできて有意義だった。

今週も7月~8月ごろに新たに掲載された記事をピックアップして紹介する。

Pythonを用いて無料で貴方の画像をラベル付けする簡単な方法
towardsdatascience.com
画層認識で重要になる画像のラベル付けに関するチュートリアル記事。

貴方のノートブックをJupyterLabテンプレートに同期させる
towardsdatascience.com
Jupyter Notebook上でコード開発をすると前に作ったコードのコピーペーストの連続になりがちだが、ここではよりスマートな方法が紹介されている。

データサイエンスをリードする10人の女性
www.siliconrepublic.com
2020年10月の記事。10人の女性データサイエンティストの紹介。

重要なデータサイエンスのソフトスキル:成長マインドセット
benjaminobi.medium.com
データサイエンティストとして必要なソフトスキル(定性的・人間的スキル)のうち、「成長マインドセットを持ち続ける」ための具体的な方策が述べられている。

データサイエンスの将来トレンド2022
www.datasciencecentral.com
データサイエンスの今後のトレンドについて、主に政策的視点から述べられている。「AIの民主化」「トッププログラミング言語は依然Python」など。

データサイエンスのおすすめオンライン記事(9月28日付)

事実上の次期首相を選ぶ選挙が翌日に迫ってきた。次のリーダーには是非長期的な視点で日本の経済的衰退を食い止める政策を打ってもらいたい。特にエネルギー政策は国の根幹に関わる重要課題であり、次期首相の政治家としての手腕に期待したい。
前回の投稿からかなり間が空いてしまい、記事のストックが積み上がってしまっている。今回紹介する記事も6月~7月ごろの記事が中心である。

貴社のCRMデータのよくある問題と解決法
www.datasciencecentral.com
Customer Relationship Management(顧客関係管理)データを扱う場合によく遭遇する問題とその解決策をまとめている。

データサイエンティストとして貴方の再利用可能なPythonコードを管理する
www.kdnuggets.com
プログラムコードの管理と再利用は仕事でコードを書く人なら誰でも直面する問題であろう。ここでは初心者向けに個人のコード再利用の方法が述べられている。

「バリュー」の定義:AI成功のカギ
www.datasciencecentral.com
おなじみ"Dean of Big Data"ことBill Schmarzo氏のエッセイ。「データサイエンティストのように考える」フレームワークの改訂版と「AIプロジェクトがもたらすバリューを定義する重要性を述べている。

Facebookの"Prophet"は時系列予測の救世主か、それともただのわんぱく小僧か
www.datasciencecentral.com
Facebookが開発し、最近注目を集めている時系列予測ツールProphetについての解説記事。

最新のAI研究論文を手早く分析する必須ツール
www.datasciencecentral.com
AIの最新論文をリサーチするのは骨のおれる作業だが、ここではData Science Centralによく寄稿している著者が利用している"labml.ai"というプラットフォーム上の論文サーチ機能を紹介している。