AREKORE

daikikatsuragawaのアレコレ

機械学習における反実仮想説明(Counterfactual Explanations)を生成するライブラリ“DiCE”を活用したサービス開発についての考察

個人的に、機械学習における反実仮想説明(Counterfactual Explanations)*1を生成するPythonのライブラリ“DiCE”に興味を持ちました。そして、DiCEを活用したサービス開発について考察をしました。本記事はその考察についてのメモです。

機械学習における意思決定を促進する説明

機械学習を活用した予測において予測対象者の行動を促す、つまり「意思決定の促進」を目的とする場合があります。このとき、意思決定者(予測対象者)に予測の根拠についての説明を提供することが重要です。そのゆえ、機械学習の文脈で説明についての研究、議論が進められています。

例えば、機械学習モデルの出力の解釈性を扱った手法の例としてSHAP(SHapley Additive exPlanations)というものがあります。

proceedings.neurips.cc

これは各予測の根拠として、各特徴量の貢献度(寄与度)を算出します。これを提供することで、予測に対して納得したり妥当だと感じることにつながります。このとき、その予測への信頼が高まると考えられるため「意思決定の促進」が期待されます。

反実仮想説明を生成するDiCE

DiCEとは?

上記で紹介した手法では、予測を実施したタイミングにおける、機械学習モデルの出力の解釈性として、各特徴量の貢献度などの出力が可能です。ただし、それらはあくまで事実における結果自体の根拠の説明です。もし、予測を覆したいシチュエーションだった場合、意思決定者は具体的にどの特徴量をどれだけ変動させたら良いのかが明らかではありません。意思決定者へ行動を促すためには、どれだけでもわかりやすく説明することが望ましいです。

それに対して「未来の状態を提示する」というアプローチで説明を提供するDiCEを紹介します。DiCEとは、目的とする出力を得るための反実仮想サンプルを生成するアルゴリズムおよびそれが実装されているライブラリです。DiCEはMicrosoft Researchにより開発されています。

www.microsoft.com

反実仮想、つまり「事実と反対のことを想定すること」という概念に基づき、予測結果が覆る(反対になる)特徴量の変動例を提示する説明を反事実的説明(Counterfactual Explanations)と呼びます。DiCEは反事実的説明を生成します。具体的には、DiCEは予測結果に対して、異なる結果が得られたであろう「入力の特徴量を変動させたサンプル」を生成することにより、説明を提供します。この説明を受け取った人は「どの特徴量をどれだけ変動させたら良いのか」といった指針を得ます。これにより「何にどれだけ取り組めば良いのか」といった具体的な行動を促すことが期待されます。「サンプルを生成することによる直接的な材料提供」という点において、他の類似するアルゴリズムとは異なります。

具体的なDiCEの活用シーンについて、README.rstなどでも紹介されている「金融会社におけるローン審査モデル」にDiCEを適用する例を説明します。

github.com

前提として、ある金融会社では、機械学習モデルの分類アルゴリズムを活用したローンの審査をサービスとして提供しているとします。これにDiCEを組み合わせてみると、DiCEは「ローンを申請したが拒否された人」に対して、特徴量を変動させてローンの申請が承認されるサンプルを提示します。例えばサービスは「もしあなたの収入が今より10,000ドル高かった場合、ローンを認めます。」と説明します。この説明を受けた人は、 「どの特徴量をどれだけ変動させたら良いのか」といった指針を得ることが可能です。指針を得ることにより「具体的に何をしたら良いのか」を想像できます。このように、DiCEは 予測に貢献した重要な特徴だけを提供するのではなく、反実仮想を考慮し、意思決定の対象者が望ましい結果を得るために次に何をすべきかを決定するのに役立ちます 。

また、DiCEは実現可能性やドメインの制約を考慮できます。事実サンプルと反実仮想サンプルのベクトルとしての距離を考慮し、実現可能性が高い反実仮想サンプルを提供します。そして、ドメインの制約を考慮して、特定の特徴量を変動の対象外にしたり、特徴量の値の上限と下限を設定することなども可能です。

DiCEの使用方法と動作の紹介

プログラムよってDiCEの使用方法と動作を紹介します。DiCEはPythonで実装されており、OSSオープンソースソフトウェア)としてGitHubで公開されています。

github.com

そして、PythonサードパーティーソフトウェアリポジトリであるPyPIに登録されています。PyPIにおけるDiCEの識別子はdice_mlです。

pypi.org

題材は「タイタニック号の生存者予測」とします。これは以下の点でDiCEの例を紹介するために適していると考えられます。

  • 生存か否かという2クラス分類であること
  • 予測対象者が一方のクラス(生存)に予測されることを望むであろうこと
  • 機械学習チュートリアルとして一般的に知られている例であること

シチュエーションとしては、「生存か否かを判別を事前に判別するサービス」があったとしてその開発を考えます。このシチュエーションは多少無理がある気もしますが、ローンなど良さそうなサンプルデータを見つけられなかったこともあり、あくまでDiCEの例を紹介するためなので流してもらえると幸いです。

実行環境はGoogle Colaboratoryとします。まずはDiCEをインストールします。

!pip install dice_ml

DiCEで反実仮想説明を生成するために、以下2点が必要です。

  • 学習データ/テストデータ
  • 学習済みモデル

はじめにこれらを準備します。「タイタニック号の生存者予測」のデータはseabornから取得します。最低限の前処理を実施します。ホールドアウト検証として、学習データとテストデータに分割します。モデルはロジスティック回帰を選定しました。scikit-learnで実装されているものを利用します。余談ですが、個人的にロジスティック回帰のような予測確率を算出できる手法はDiCEとの相性が良いと考えています。理由は組み合わせることによって説明に有用な情報を増すことができる点です。

import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
import seaborn as sns

titanic_df = sns.load_dataset("titanic")

titanic_df = titanic_df.drop(columns="alive")
titanic_df["age"] = titanic_df["age"].fillna(titanic_df["age"].median())
titanic_df["sex"], _ = pd.factorize(titanic_df["sex"], sort=True)
titanic_df["embarked"], _ = pd.factorize(titanic_df["embarked"], sort=True)
titanic_df["class"], _ = pd.factorize(titanic_df["class"], sort=True)
titanic_df["who"], _ = pd.factorize(titanic_df["who"], sort=True)
titanic_df["adult_male"], _ = pd.factorize(titanic_df["adult_male"], sort=True)
titanic_df["deck"], _ = pd.factorize(titanic_df["deck"], sort=True)
titanic_df["embark_town"], _ = pd.factorize(titanic_df["embark_town"], sort=True)
titanic_df["alone"], _ = pd.factorize(titanic_df["alone"], sort=True)

X = titanic_df.drop(columns="survived")
y = titanic_df["survived"]

train_x, test_x, train_y, test_y = train_test_split(X, y, test_size=0.2, random_state=123)

model = LogisticRegression()
model.fit(train_x, train_y_bin)

ここまでで以下の用意が完了しました。

  • 学習データ(train_xtrain_y)/テストデータ(test_xtest_y
  • 学習済みモデル(model

ここからはDiCEによる準備です。dice_ml.Dataでテストデータについての設定をし、dice_ml.Modelで学習済みモデルについての設定をします。

import dice_ml

d = dice_ml.Data(dataframe = pd.concat([test_x, test_y], axis=1),
                 continuous_features=['age', 'fare'], 
                 outcome_name = "survived")

m = dice_ml.Model(model=model, 
                  backend="sklearn")

exp = dice_ml.Dice(d, m)

それでは、試しにテストデータ1件(index == 524)の反実仮想説明を生成します。パラメータについては生成する反実仮想の数をtotal_CFsに、変動対象の特徴をfeatures_to_varyに、変数のとりうる値の上限と下限をpermitted_rangeに設定します。そして、望むクラス(0)をdesired_classに設定します。

pre_counter = test_x.query('index == 524')

dice_exp = exp.generate_counterfactuals(
    pre_counter,
    total_CFs=5,
    features_to_vary=["pclass", "sibsp", "parch", "fare", "embarked", "class", "deck"],
    permitted_range = {"fare":[0, 300]},
    desired_class = 1, 
)

dice_exp.visualize_as_dataframe(show_only_changes=True)

上記のような出力がなされます。もともと、生存予測の結果は否(0)でしたが、例えば、sibspを2、fareを約8.03、classを0に変動させると生存予測の結果が変わるというサンプルが生成されたということが示されています。また、このようなサンプルがtotal_CFsに基づき、5件生成されています。またこれらは、features_to_varypermitted_rangeで設定した制約を満たすものであり、より実現性の高いものが提示されています。

本記事では概要の理解までを目的としているためここまでとします。詳しくはドキュメントをご覧ください。

interpret.ml

以上より、DiCEを活用して反実仮想説明を生成することが可能です。

DiCEを活用したサービスの例

DiCEを活用したサービスの例について考察します。ユーザの意思決定の促進を目的としたサービスにおいてDiCEは有用であると考えられます。以下の例が考えられます。

  • 金融機関における機械学習に基づくローンの審査
  • 医療における機械学習に基づく病気の判定
  • 模擬試験の結果の通知とアドバイス
  • マーケティングにおけるファンクラブ加入者の分析と増加のための施策選定

“DiCEとは?”でも説明しましたが、ローンの審査結果として融資の可否を提示するとき、DiCEは有用です。ローンの審査結果として、拒否となってしまった人がいるとします。その人はローンを受けたいため、現状の課題を解決して再び挑もうとするはずです。そのとき、何をどれだけ改善すれば良いのかという情報が得られたら、それを参考に現状の課題の改善に取り組むことができます。少し先の未来で、その方がローンの審査を通過した場合、サービス提供元も利益が得られます。このように単にユーザのためだけでなく、サービス提供元も利益が得られるといった点で、投資する価値のあるサービスであると考えられます。このようにサービス提供元、提供先のともどもに利益が考えられます。

他にも医療において、機械学習を活用して病気の判定を実施するとき、DiCEは有用です。例えば、特定の病気である、もしくはその可能性が高いと判断された人がいるとします。その人はその病気に打ち勝つために行動を起こすはずです。また、その判定が医療の現場で行われる場合であっても、医師がその病気を治療するはずです。そのとき、何をどれだけ改善すれば良いのかという情報が得られたら、それを参考に現状の課題の改善に取り組むことができます。

予備校や通信教育など学習を提供する企業による模擬試験の結果の通知とアドバイスにもDiCEが有用であると考えられます。例えば大学入試、単純な点数の和ではなく、場合によっては必要十分条件などもあるかと思われます。それらも加味した上で、ある教科の点数をこれだけ上げて、その他の教科の点数をこれだけ上げると合格可能性が高いクラスに変動するということを説明できます。今後の学びの指針を明らかにすることで、現状の課題の改善に取り組むことができます。

上記3点は主にユーザによる、ユーザのための反実仮想説明の提示、つまり主な目的をUX(ユーザーエクスペリエンス)向上として掲げている場合です。サービス提供元も利益が得られる場合もありますが、ユーザが主なトリガーです。。それに対して、サービス提供者がユーザを動かすための施策を設計する参考として反実仮想説明を扱う場合もあり得ます。例えば、ファンクラブ加入者の分析と増加のための施策の設計はそれに当たります。企業はファンクラブ加入者を増やしたいと考えているとします。そのために、ファンクラブ加入者とそうでない人の特徴を分析し、比較してどうしたら、そうでない人をファンクラブ加入者にできるかということを考えます。DiCEを活用すると、各ユーザの何をどれだけ変動させることができたらファンクラブ加入者になる、もしくはファンクラブ加入者に近づけることができるということを理解できます。これは施策の設計におけるターゲットの選定、施策内容の決定、具体的な数値目標の設定の参考として活用が可能であることが考えられます。

上記のようにさまざまなサービスにおいてDiCEは有用です。特に、ユーザの現状に基づいた反実仮想サンプルを生成するため、行動を促すハードルは低くなるはずです。また、時間や費用と相談して、最適な意思決定につなげることはできるはずです。

DiCEを活用したサービス開発における課題と解決策

DiCEを活用したサービス開発について考えたとき、いくつかの課題が考えられました。その解決策として以下の点が考えられました。

  • 設計の工夫による現実に起こりうる反実仮想説明の生成
  • 複数の反実仮想説明に基づく施策の設計

これらについて説明、考察します。

設計の工夫による現実に起こりうる反実仮想説明の生成

DiCEは、各説明変数に対して「変動対象か否か」や「変動量の幅」の設定が可能です。これをサンプルのフィルタリングに用いることで、ドメインを考慮した実現可能性の高く、存在しうるサンプルを提供します。しかし、この時、以下が課題として挙げられます。

  • モデルは特徴に潜在的に存在するルールの解釈が難しいという点
  • モデルは特徴量間の関係を解釈が難しいという点
  • フィルタリングを厳しくした場合、モデルが解釈できない珍しく重要なサンプルを見逃してしまう可能性もあるという点

このような機械に解釈させるのが難しいドメインの制約については、DiCEに限らず機械学習を活用したサービス開発全体に発生しうる課題です。それゆえ、機械学習を活用したサービス開発において、機械学習ドメインとの付き合い方がとても重要であると考えられます。また、それは機械学習やDiCEの進展に任せ切ってしまう話ではなく、サービス全体で対応すべき課題であると考えています。DiCEを活用するサービス開発において、そもそも扱っているデータが何かの誤りで存在しないものだったり、DiCEでも設定しきれないドメインにおける制約を見逃してしまい、存在しないサンプルを提示しまうことも考えられます。以下ではそんなDiCEを活用したサービス開発について記述します。特に、ドメインを考慮した反実仮想クラスの設計による対応について紹介します。DiCEを活用したサービス開発において、ドメインを考慮した反実仮想サンプルの生成の方法を提案します。主な要素は以下の2つです。

  • 特徴間の関係を加味したクラスの設計
  • 特徴の扱い方としての値オブジェクトの採用

特徴間の関係を加味したクラスの設計

ある特徴量の値が、他の特徴量の値に影響を及ぼす場合があります。例えば、人によって、値の上限と下限が違う場合です。その場合、存在し得ない状態を提示してしまう可能性があります。そんな存在し得ない状態はドメインを考慮したクラスの設計により検知できます。

具体的なプログラムの例を紹介します。先に紹介した「タイタニック号の生存者予測」の例より、費用(fare)、年齢(age)のみを抜粋します。

例えば、以下のようなクラス(Sample)を用意しておきます。これは費用と年齢に制約を与えているため、生成されたインスタンスドメインにおける制約を満たすことになります。

import dataclasses

@dataclasses.dataclass(frozen=True)
class Sample:
    fare: float
    age: int

    def __post_init__(self):
      if self.fare <= 0 or 300 <= self.fare:
        raise Exception()
      if self.age <= 0 or 100 <= self.age:
        raise Exception()
      if self.age < 20 and 150 <= self.fare:
        raise Exception()

例えば、DiCEが以下のようなドメインにおける制約を満たすサンプルを生成したとし、これを表現するインスタンスを生成してみます。

sample = Sample(150, 20)
sample 

すると問題なく生成できます。これは反実仮想説明として提示しても良いでしょう。

Sample(fare=150, age=20)

逆に、DiCEが以下のようなドメインにおける制約を満たさないサンプルを生成したとし、これを表現するインスタンスを生成してみます。

sample = Sample(150, 19)

するとこのインスタンスの生成は失敗します。これによりサービスはあり得ないサンプルを説明として提示することを回避します。

---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-20-81b073a3d0d2> in <module>()
----> 1 sample = Sample(150, 19)

<string> in __init__(self, fare, age)

<ipython-input-17-cb29eedcdebf> in __post_init__(self)
     12         raise Exception()
     13       if self.age < 20 and 150 <= self.fare:
---> 14         raise Exception()

Exception: 

このように、特徴間の関係を加味したクラスの設計により、DiCEが生成した反実仮想説明に対して、現実に存在しうる反実仮想説明のみを抽出が可能であると考えられます。

特徴の扱い方としての値オブジェクトの採用

DiCEでは特徴に対して、変動の有無や変動の幅を設定できます。ただし、その設定もドメインに忠実に適応できない場合があると考えられます。それゆえ、設計でカバーすることも望ましいと考えられます。DiCEが生成した反実仮想サンプルに対して、現実に存在しうる反実仮想サンプルのみを抽出する方法として、値オブジェクトが考えられます。値オブジェクトとは、ドメイン駆動設計の要素のひとつです。簡単に説明すると、プログラムの中で、その値の振る舞いをドメインに基づくのもに制限するという設計です。上述したクラスの設計の例と同様に、これによりよりドメインに忠実に、異常な状態を検知できます。

具体的なプログラムの例を紹介します。

import dataclasses

@dataclasses.dataclass(frozen=True)
class fare:
    value: float
    def __post_init__(self):
      if self.value <= 0 or 300 <= self.value:
        raise Exception()

@dataclasses.dataclass(frozen=True)
class age:
    value: int
    def __post_init__(self):
      if self.value <= 0 or 100 <= self.value:
        raise Exception()

例えば、DiCEが以下のような全ての特徴量がドメインにおける制約を満たす値であるサンプルを生成したとし、それぞれを値オブジェクトとしてインスタンスを生成してみます。

fare = Fare(150)
fare

age = Age(20)
age

すると問題なく生成できます。これは実現可能性の高い説明として提示しても良いでしょう。

Fare(value=150)
Age(value=20)

逆に、DiCEが以下のような特徴量にドメインにおける制約を満たさない値を持つサンプルを生成したとし、それぞれを値オブジェクトとしてインスタンスを生成してみます。

fare = Fare(1000)
fare

するとこのインスタンスの生成は失敗します。これによりサービスはあり得ないサンプルを説明として提示することを回避します。

---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-33-4dbe6b6b540a> in <module>()
----> 1 fare = Fare(1000)
      2 fare

<string> in __init__(self, value)

<ipython-input-27-2319445039c4> in __post_init__(self)
      6     def __post_init__(self):
      7       if self.value <= 0 or 300 <= self.value:
----> 8         raise Exception()
      9 
     10 @dataclasses.dataclass(frozen=True)

Exception: 

このように、値オブジェクトを使うことで、DiCEが生成したサンプルに対して、現実に存在しうるサンプルのみをサービスとして扱うことが可能であると考えられます。

また、値オブジェクトは上述したクラスの設計と組み合わせて、クラスが持つプロパティ全てを値オブジェクトにすると効果的であると考えられます。例えば以下のような記述が考えられます。

@dataclasses.dataclass(frozen=True)
class Sample:
  fare: Fare = fare
  age: Age = age
  
  def __post_init__(self):
      if self.age.value < 20 and 150 <= self.fare.value:
        raise Exception()
fare = Fare(150)
age = Age(20)
sample = Sample(fare, age)
sample
Sample(fare=Fare(value=150), age=Age(value=20))

これらを実施することで、機械学習を活用したサービス開発における安全性・信頼性といった品質保証の担保にも貢献が可能です。

複数の反実仮想説明に基づく施策の設計

マーケティングにおけるファンクラブ加入者の分析と増加のための施策選定」のように多くの人を動かすこと、つまり複数の意思決定の促進を目的とする場合があります。前提として、人を動かすために、施策を設計します。施策の設計のために、反実仮想説明が有用であると考えられます。この時、DiCEが生成する反実仮想説明は一人を対象とした説明です。もちろん一人の反実仮想説明を確認して、特定の説明変数の値を変化させるためにどうすれば良いのかを考えることができると思います。しかし、複数人を動かそうとした場合は反実仮想説明を生成した後、施策を設計するまでにハードルがあることが考えられます。

まずは、各反実仮想説明を理解、解釈し、要約したうえで、施策を設計する必要があります。これを実現する手法(処理)が必要です。その理由はマーケティングにおいて、複数の意思決定を促進させるための各反実仮想説明への対応が現実的ではないことです。

上述した手法が確立されたとして、次は「その施策によって意思決定を促す人の数を最大化させる要望」も生まれます。例えば、ファンクラブ加入者をX人にすることをKGI(経営目標達成指標)とした時、それに向けて設定する施策が中間数値指標としてのKPI(重要業績評価指標)となります。このKPIを設定する際、最も効果がある施策は何なのかを設定することが難しいと考えられます。

それゆえ、「複数の反実仮想説明に基づく施策の設計」に関する議論が重要になってくると考えています。以下、「複数の反実仮想説明に基づく施策の設計」に関して私が考えていることを紹介します。まずは概念図を以下に示します。

複数の反実仮想説明に基づく施策の設計の概念図

予測対象1件に対して、m件の反実仮想説明を生成し、その合計をn件とします。これは施策の設計の参考になる情報であり、これらを包括して理解、解釈することで複数の反実仮想の実現につなげる施策を設計する際のヒントとなります。反実仮想×nの生成はDiCEにより実現が可能です。議論すべきは「反実仮想×nから施策を設計する処理」です。まずは反実仮想×nを要約する必要があります。

Minimum Viable Productに基づき実用最小限の手法を考えました。処理の流れを以下に示します。

  1. 反実仮想をクラスタリング(例:k平均法)
  2. クラスタをサマライズ(例:中央値)
  3. クラスタごとにサマライズされた情報を参考にしてマーケティング担当者が施策を設計

人が介入する必要はありますが、これにより「反実仮想×nから施策を設計する処理」がなんとか実現できるのではと考えています。これをベースラインにして、これらの方法については思案・調査中です。もし有識者の方から意見をいただけるととてもありがたいです。

反実仮想説明の関連研究

事実から反実仮想まで変動させるための状態遷移の考慮

事実から反実仮想を目指す場合、そのベクトルが直線でない場合も考えられます。具体的には「暗黙的に存在している状態」を経由する必要がある場合です。これを正しく理解しないと、事実を反実仮想まで変動させるのに想定以上の苦労がかかったり、そもそも不可能だったりする可能性が考えられます。それゆえ、事実から反実仮想まで変動させるための状態遷移を考慮した手法やサービスの設計が必要になります。このような背景から、事実から反実仮想まで変動させるための状態遷移を考慮した手法を提案する研究もなされています。

富士通研究所北海道大学は、実現の可能性と順序を考慮した適切な変化方法を見いだすことが課題であると捉え、反実仮想説明の考え方に基づき、事実を反実仮想に変動させる手順として、行動自体とその実現の順序を提示する方法を提案した。

pr.fujitsu.com

今回、両者による共同研究において開発した新技術は、反実仮想説明(注5)という考えに基づき、属性変更におけるアクションとその実施順序を手順として提示します。過去の事例の分析を通して非現実的な変更を避けつつ、属性値の変更がほかの属性値に与える因果関係などの影響をAIが推定し、それに基づいて実際に利用者が変更しなければならない量を計算することで、適切な順序、かつ一番少ない労力で最適な結果が得られるアクションの提示を可能としました。

上記の研究では「順序」を考慮しているという点により、実現可能性が高い反実仮想説明の生成されます。これにより、意思決定の促進が期待できます。

本記事のまとめ

本記事では、機械学習における反実仮想説明を生成するライブラリ“DiCE”を紹介しました。また、DiCEのサービスへの活用例を紹介しました。そして、DiCEを活用したサービス開発における課題と解決策について、以下2点を紹介しました。

  • 設計の工夫による現実に起こりうる反実仮想説明の生成
  • 複数の反実仮想説明に基づく施策の設計

関連研究でも紹介しましたが、ドメインへの対応が重要だと考えられます。設計で対応できることもあるので、ぜひ検討をしてください。そして、特定のシチュエーションにおいて施策の設計が必要とされると考えられます。今後、考えていこうと思います。

本記事は追記、修正する可能性があります。ご了承ください。もし意見、質問、指摘などがあれば、以下に記載されている連絡先に連絡をいただけるととても嬉しいです。

https://daikikatsuragawa.github.io/

*1:本記事ではCounterfactual Explanationsを反実仮想説明と和訳します。他にも反事実的説明、反実仮想的説明、反実仮想的な説明として和訳されている場合があります。

2021年8月のアレコレ

これは何?

「ブログの記事になるほどじゃないなー」といった規模で思ったこと、感じたことがいくつかあります。そんなある日、nishibaさんの記事を読んで、いろんなことを書く形式、とてもいいな!と思いました。

note.com

自分のための備忘録としてアレコレ書いてみます。

本にハマる

2021年3月中旬以降、あるキッカケがあり、書籍の魅力に気がつきました。人生で一番のペースで読んでいます。苦手意識はあったんですが、よく考えたら学生時代、論文はひたすら読んでいたので、流し読みや取捨選択はまあまあできました。現代、ウェブでも無料で欲しい情報は得られます。しかし、書籍には金額以上の価値がある気がしています。

そんなことを思った直後、奇跡のタイミングでこんなキャンペーンに出会いました。元々は本にお金を使いたくない派だったのですが、「今だな…」と思って奮発してしまいました。これをキッカケに気になった本を買う癖がつきました。

prtimes.jp

「今月は節約しよう…」と思った直後、奇跡のタイミングで大量の古本を頂く機会がありました。200X年~2013年くらいの本ばかりで、少し古いです。しかし、取捨選択できるとただの宝の山になります。

そんなこともあり、とんでもない量のインプットを得ました。「シン・エヴァンゲリオン劇場版:||」に出てくる「碇ゲンドウ」の気持ちが分かった気がしました。気になる方は是非見てください。とてもよかったです。

ただ、気持ちだけ大きくなって、何かアウトプットできているわけではありません。今後は成果を生み出すために、学んだことを実施していく段階に集中しようと思います。

「意思決定分析」に詳しくなりたい

「意思決定分析と予測の活用 基礎理論からPython実装まで」という本にすごくハマりました。

まだ読みかけですが、「意思決定分析」に詳しくなることを決意しました。ある分析・モデルがあったとして、それに対して以下のような疑問がありました。

  • 導入する場合の費用対効果はあるのか?
  • 取り組む価値があるのか?
  • 精度はどれだけあれば十分か?
  • 使い物になるのか?
  • 価値があるのか?

それらを明らかにする理論などが書いてあったりします。上述したことは研究をしていた時から悩んでいたことだったり、ビジネスにおいても重要だと思います。それゆえに使いこなせるようになりたいなと思いました。まずは学んだことを、プライベート・仕事に関わらず何かに落とし込んでみたいと思います。ただ、現実の事象に当てはめることは難しそうなので、まずは「なんとなく」を目標にします。

ドメイン駆動設計がとても大事かもしれない(特に機械学習を扱うプロダクトにおいて)

業務でサンプルデータを作成していた時、現実ではありえない値を生み出したりしてしまいました。まあ、それはただのポンコツミスではあるんですけど、「値オブジェクト(ドメイン駆動設計の一部)」を使ったらいいなと思い、ちょっとしたスクリプトですが使うようにしました。

ふと思ったんですが、データサイエンスにおいて「ドメイン知識大事!」って考えもあるので、ありえない値、作っちゃいけないなと思いました。

もしかしたら…予測結果として頓珍漢な値を出すことってあるんですかね? それも予測しちゃう前に値オブジェクト使うといいんじゃないかと思いました。

もしかしたら…現実的じゃないタイミングで予測や推薦などアプローチしちゃうことってあるんですかね? それも値オブジェクト使うといいんじゃないかと思いました。

正直、ドメイン駆動設計の真髄まで知れていないですが、機械学習を扱うプロダクトと現実世界の懸け橋になるんじゃないかと感じています。

OSSの草=勉強量?

ある人と話した時に「あなたのGitHubアカウント(おそらく草)を見て、他のエンジニアとともに『勉強量がすごい』と感心していた」ってありがたい言葉をいただいた。しかし…その草のほとんどは、ソフトウェアエコシステムの貢献のための活動だった(そのつもりだった)。正確には、勉強のためにやってたこともあるけど、純勉強はない。決してその方々が悪いって話ではなく、日本のGitHubユーザの多くが勉強の証として利用してあるからなのだろうなと感じた。確かにどんなことでも学びにはなるが、自分がやっている仕事に対して「毎日8時間ほど勉強をしている」と考えると少し違う。そこがモヤモヤした。一旦モヤモヤを整頓して、今後こんなことがあったらちゃんと言ってみよう。

「新卒3年目の目標」の途中経過(4ヵ月経過)

ブログやってみる(まさにこれ)

謎のペースですがやれています。思考がまとまる、そのキッカケになるのでいいですね。以下の書籍でですごくモチベーションが高まりました。

ただし、この書籍でも言及されているように、情報発信により時間を失ってしまうため費用対効果を高めていきたいです。

仕事でデータサイエンス的な成果をリリースする(もしくはリリース見込みまで)

これは…何かしら言える状態(外に情報を出せる状態)をゴールとします。ということで、まだですね。

Kaggleで何かしら言える結果を出す(時には称号も大事!)

実は「Notebooks Expert」になりました。

www.kaggle.com

AutoMLの布教のためにAutoML系ライブラリを使ったサンプル(特に入門用)をひたすら生成していました。 また汎用的にするためにほぼ同じNotebookで似たようなコンペに参加していました。 それでコツコツと「bronze medal」を頂き、気が付いたらなっていました。

なにか統計・データ関係の資格を取る(時には称号も大事!)

これは…とっていません!統計検定2級とDS検定は今年中に受けようかなと思っています。

何かOSSをリリースする

これはまあまあいい感じにできたと思います。自分発のOSSを3件リリースしました。

github.com

github.com

github.com

PePyと言うウェブサイトで利用数の確認が可能です。地味に利用されているんですかね🤔

https://pepy.tech/project/df4looppepy.tech

https://pepy.tech/project/autoarmpepy.tech

実は、いいことがいくつかありました。

  • 実業務でdf4loopを利用
  • clasp-actionへのプルリクエス

得意を伸ばしつつ苦手をなくす

これもなんとなくな目標ですね。これに関しては少し考え方が変わりました。なんとなくしか言語化できないですが、苦手をうまく使いこなして単純に得意のカバレッジを増やせるんじゃないかなと。

アソシエーションルールマイニングに基づく推薦を民主化するライブラリ「AutoARM」をリリースするまでの記録

はじめに

先日、アソシエーションルールマイニングに基づく推薦を民主化するライブラリ「AutoARM」をリリースしました。AutoARMはPythonで実装されており、PyPIで公開されています。

pypi.org

またオープンソースソフトウェア(OSS)としてGitHubで公開されています。

github.com

ゼロからアイデアを生み出したことからリリースするところまででさまざまな経験をしました。そこで、さまざまな学びがありました。本記事はAutoARMをリリースするまでの記録です。

開発に至る動機

AutoARMの開発に至る動機は3つあります。

“アソシエーションルールマイニングに基づく推薦”の提案

開発に着手する直前、「今こそ“アソシエーションルールマイニングに基づく推薦”が活きる時代なんじゃないか?」と思っていたことです。詳細については以下のブログを読んでください。

daikikatsuragawa.hatenablog.com

簡単にまとめると以下の点で改めて有用な手法だと思っています。

  • 推薦の根拠を説明可能
  • 推薦を実施したい相手に紐づく情報がなくても推薦可能

そして、上記2点は、データ提供・活用が実施されていないサービスに対して有効だと考えられます。そして、日本におけるデータ提供・活用をブレイクスルーするひとつのキッカケになるのではないかと期待しています。

また、ライブラリになっていた場合、プライベートにおける取り組みではあるものの、現在所属している組織でも簡単に再利用が可能になります。それゆえ、現在所属している組織における新規サービス・機能の提案の火種になることも期待していました。

過去の自分(=未来の誰か)の支援

学生時代、利用状況、推薦に関する研究をしていました。そこでアソシエーションルールマイニングに基づく推薦を実装していました。

https://ieeexplore.ieee.org/document/8445832ieeexplore.ieee.org

実は当時、実装がとても苦手で、比較的多くの時間をかけて保守の手間を無視する危なっかしいスクリプトを書いていました。というのも、アソシエーションルールマイニングに基づく推薦ってライブラリとして実装されていなかった(もしくは見つからなかった)のです。

もっと前にも似たようなことがありました。テーブルデータを用意した状態で、「こんな手法で予測したい」という方針は決まっているものの、スクリプトを書けないが故に手が止まってしまうということです。この日は状況共有の機会の前日だったこともあり、すぐにでも実現したいと思い、詳しい同期にスクリプトを書いてもらいました。すると一瞬でやりたいことが実現できました。この出来事をきっかけに学術研究、特に機械学習やデータ分析を必要とするものにおいて、技術がなく実現できない、提案できないアイデアがあるんじゃないかと思っていました。ただ近年、AutoMLが提案されており、機械学習という技術は民主化されています。これにより、上述した過去の自分が助かります。過去の自分の悩みは、未来の自分や誰かの悩みです。AutoMLにより未来の誰かの問題の解決に進んでくのではないかと思っています。

AutoML開発の動機についても技術にしてもとても共感していました。そんな中、“アソシエーションルールマイニングに基づく推薦”って実装されていない、つまり民主化されていないと思いました。個人的に有用な手法だと思っているため、過去の自分(=未来の誰か)のためにも実装し、誰もが利用できる状態にすることが望ましい状態と思いました。

(オーナーとして)OSSの開発

ソフトウェアエンジニアとして、意味のあるOSSを、自分がオーナーとして開発したいと思っていました。下記より既にOSSはリリースしたことがあるのですが、やはり、自分が貢献したいと思っているデータ分析、機械学習に関して、取り組みたいと思いました。

daikikatsuragawa.hatenablog.com

とにかく、ひとつを作りきることによって得られる経験値の大きさを期待していたため、単純にやってみたかったということがあります。OSSのスタンスについてもとても共感しています。完璧なものを開発しきるというよりは、「やりたいことの提示」を一番の目的としたいと思いました。自分よりも素晴らしいソフトウェアエンジニアが世界中にいることもあり、自分の思いに共感してくれた人が何かを直してくれたら、それがOSSのあるべき姿なんじゃないかと思ったためです。そのため、Minimum Viable Product(MVP)の考えに基づき、必要最小限の実装で、体験・価値を実現したいと思いました。このような思いを持ってOSS、特にPythonのライブラリを開発したいと思いました。

ライブラリの内容の設定

上述した動機に基づき、「アソシエーションルールマイニングに基づく推薦を民主化する」といったテーマでライブラリを開発しようと考えました。そこで、既存ライブラリを調査し、以下のような内容を定めました。

  • アソシエーションルールマイニングに基づく推薦に基づく過程を実装
    • テーブルデータの入力
    • 頻出パターンマイニング
    • アソシエーションルールマイニング
    • ルールに基づく推薦
  • 過程が首尾一貫しており誰でも簡単に利用可能
    • 参考とするインタフェースはAutoGluon*1

既存ライブラリに対する新規性は以下2点です。

  • アソシエーションルールマイニングに基づく推薦を対象
  • (アソシエーションルールのライブラリに対して)推薦までを実装

以上より、開発に着手しました。

推薦の流れ

新規性としてもアピールしていた「推薦」の流れを紹介します。MVPに基づき、最もシンプルな方法はこれだなと思う方法を実装しました。インプットは推薦対象の現状のアイテムリストと、事前に出力したルール群、推薦の基準とするメトリック(信頼度またはリフト)です。アウトプットは推薦の参考になるルールN件です。流れを以下に示します。

  • ルール群の結論部を分割(多:1のルールに)
  • 入力したアイテムリストと一致する条件部を持つルールを特定
  • 入力したアイテムリストと結論部が一致するルールを除外
    • この手順はスキップも可能
  • メトリックとして指定された信頼度またはリフトでルールを並び替え
  • 上位のルールに対して結論部が重複するルールを除外
  • 指定されたサイズ(N件)のルールを出力

詳細や実装についてはREADMEやソースコードを見ていただけると幸いです。

これにより、AutoARMは推薦の参考となるルールを出力します。ミソはアイテムではなく、ルール自体を出力することです。つまり、そのアイテムを推薦する根拠を残しています。これにより、根拠を説明しつつアイテムを推薦するため、相手の行動を促す推薦サービスが実現されます。

AutoARMの紹介

上記のような過程を経て開発を進めてAutoARMが完成しました。ざっくりと紹介します。

まず始めにデータを用意しておきます。サンプルとして適当なものを生成しています。

import pandas as pd

sample_dataset = {
    'transaction_id':
    [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7],
    'item_id': [
        "X", "Y", "Z", "X", "B", "Y", "A", "C", "A", "C", "X", "Y", "Z",
        "X", "Y", "B", "A", "X", "B"
    ],
}
df = pd.DataFrame.from_dict(sample_dataset)

つまりこのようなテーブルデータが必要です。transaction_id列、item_id列`にあたる列さえあれば他に何かあっても問題はありません。列名は後でしているため、異なっていても問題はありません。

transaction_id item_id
1 X
1 Y
1 Z
2 X
2 B
... ...
7 X
7 B

ここからAutoARMについてです。まずはインストールが必要です。Pypiで公開されているため、以下でインストールが可能です。

pip install autoarm

以下により、アソシエーションルールマイニングに基づく推薦を実現するオブジェクトを生成可能です。import文を除くと、4行です。

from autoarm import AssociationRules, Dataset, FrequentItemsets, Recommender

dataset = Dataset(df, "transaction_id", "item_id")
frequent_itemsets = FrequentItemsets(dataset, min_support=0.01)
association_rules = AssociationRules(frequent_itemsets,
                                     metric="confidence",
                                     min_threshold=0.1)
recommender = Recommender(association_rules)

以下により、推薦が可能です。

items = ["X", "Y"]
recommend_rules = recommender.recommend(items, n=3, metric="confidence")
recommend_rules

以下の表が出力されます。

rank antecedents consequents support confidence lift
1 (X, Y) (Z) 0.285714 0.666667 2.333333
2 (X) (B) 0.428571 0.600000 1.400000
3 (Y) (A) 0.285714 0.500000 1.166667

例えば、この出力に基づいて「既にあなたが購入を検討しているXとYを購入した人の66%がZも購入しています。Zを購入してみてはどうでしょうか?」といった説明を加えた推薦が実現されます。また、XとYの購入を検討している推薦を実施したい相手に紐づく情報がなくてもこのような推薦が実現されます。良いですね。

以上より、簡単にアソシエーションルールマイニングに基づく推薦が実現されます。

今後の展望

正直なことを言うと、“アソシエーションルールマイニングに基づく推薦を民主化”するためにまだまだ追加することが望ましい機能があると思っています。例えば以下です。

  • さまざまな形式の入力データの対応
  • パラメータの自動調整
  • アソシエーションルールマイニングに基づく別の推薦手法の実装

そして、OSSとしてもっとこんな状態にしたかったと思っていることがあります。例えば以下です。

  • Poetryによるプロジェクト管理
  • GitHub Actionsの有効活用
  • 値オブジェクト*2の実装

自分でガンガン開発してしまうのもいいのですが、せっかくGitHubで公開して、指針もあるため、プルリクエストを期待してひとまず手を動かすのは止めようかと思っています。特に、自分にはレビューしてくれる人がいないため、自らバグを混入してしまう可能性もあるためです。また、もっとやりたいこともあるため、世界のソフトウェアエンジニアに任せてみたいと言うこともあります。

そのため、ひとまず開発自体は小休止して、どのようにサービスに組み込むのかなどについて注力して考えようと思います。

最近のお寿司屋さん、タッチパネルでの注文が浸透していますよね。こことかで活躍しそうだなとか妄想しています。

おわりに

アソシエーションルールマイニングに基づく推薦を民主化するライブラリ「AutoARM」をリリースするまでの記録を紹介しました。是非とも使ってください!フィードバックください!コントリビュートしてください!スターください!

おまけ

本文に書くほどではないが、遺しておくべきだと感じた内容について、サクサクと記録します。

  • テストはとても大切(ユニットテスト〜運用テスト)
    • ユニットテストに何度も救われた
    • 運用テストに何度も救われた
    • しかしテスト設計はまだまだ未熟
  • AIソフトウェアのテストは非常に難しい
    • パフォーマンスの担保
    • 「AIソフトウェアのテスト」が参考になる?(めどがついたため未読)

  • 現実的な利用状況に適した速度およびアルゴリズム
    • プロトタイプ作成時はすごく遅かった(レコメンドに数分…)
    • 問題を解決するために別のライブラリ「df4loop」も誕生した

pypi.org

  • 初めてのリリース(Pypiへの公開)はすごく緊張する
    • 10分ほど精神を統一したのちヤケになって「ポチッ!」
    • 多分経験値は大きい
  • 社内LT会で少しだけ紹介した
    • 有識者・初学者それぞれから良いフィードバックが得られました
    • GUIで見せたかった…
    • サービスのイメージまで伝えたかった…
  • “サクっと”API作れるようになりたい
    • 一回テンプレートみたいなものを作るか…
    • 欲を言うとDocker、Kubernetes
  • “サクっと”ウェブアプリケーションを作れるようになりたい
    • Django
    • Flask?
    • 一回テンプレートみたいなものを作るか…(再)
    • 欲を言うとDocker、Kubernetes…(再)
  • 開発環境はほとんどGitpod+Colab!

*1:Amazon Web Services - LabsのAutoMLライブラリgithub.com

*2:ドメイン駆動設計を担う要素のひとつ

アソシエーションルールマイニングに基づく推薦のすゝめ2021

はじめに

2021年某日…「今こそ“アソシエーションルールマイニングに基づく推薦”の時代なんじゃないか!?」と感じました。その思いを綴ります。

アソシエーションルールマイニングに基づく推薦

まずはアソシエーションルールマイニングに基づく推薦についてサラッと説明します。

アソシエーションルールとはアイテム間の関連性の規則を指します。以下のように表現されます。

 \displaystyle
A \rightarrow B

これは「事象Aが起こると事象Bが起こる」という意味です。Aは条件部、Bは結論部と呼ばれます。例えば、「パンとバターを購入した人はミルクを購入する」という事象は“パンとバターを購入”→“ミルク購入”というルールとして表現されます。

任意のアソシエーションルールが有用か否かを判断する指標として、様々な評価値があります。どれだけ一般的なルールかを計る評価値として支持度(Support)があります。

 \displaystyle

支持度(Support)=
\frac{条件部(A)と結論部(B)を含むデータ数}{全データ数}

どれだけ関係の強いルールかを計る評価値として信頼度(Confidence)があります。

 \displaystyle

信頼度(Confidence)=
\frac{条件部(A)と結論部(B)を含むデータ数}{条件部(A)を含むデータ数}

信頼度に対して結論部の発生する頻度を考慮した評価値としてリフト値(Lift)があります。

 \displaystyle
リフト値(Lift)=
\frac{\frac{条件部(A)と結論部(B)を含むデータ数}{条件部(A)を含むデータ数}}{\frac{結論部(B)を含むデータ数}{全データ数}}

上記の評価値に基づいて、推薦に有用なルールを特定することが可能です。

膨大なデータからルールと評価値を出力する手法としてアソシエーションルールマイニングがあります。主に利用されているアルゴリズムであるaprioriにより、一定の支持度を超える有用なルールに絞ることも可能です。

アソシエーションルールマイニングによって得られたアソシエーションルールに基づいて以下のような順序で推薦ができると思われます。

  1. ルール群の条件部を推薦対象の現状でフィルタリング
  2. 信頼度(もしくはリフト値)に基づき結論部をランク付け
  3. 状況に合わせて上位N件を推薦

例えば、ECサイトにおいて「Aの他に何か買おうか」と思案している顧客に「Bがオススメ。(信頼度に基づき)Aの購入者の90%が同時に購入しています。」と伝えることができます。

これが本記事で紹介したい「アソシエーションルールマイニングに基づく推薦」です。

その理由(わけ)とは…

アソシエーションルールマイニング自体は素晴らしい手法です。ただし、最近発表されたものではなく、近年では様々な手法が提案されており、推薦の改善、進化が進んでいます。そんな中、2021年某日…「今こそ“アソシエーションルールマイニングに基づく推薦”の時代なんじゃないか!?」と思った理由を綴ります。その主な理由は以下2点です。

推薦の根拠を説明可能

アソシエーションルールマイニングはルールおよび評価値がシンプルで、どんな人でも理解しやすいため、推薦の根拠を説明できると思われます。Bを推薦するときに、その根拠として、「A→B」というルールに基づき、あなたがAだからという旨を伝えることができます。そして、信頼度に基づき、信頼度がX%である場合、「AのX%がBでもある」という旨も伝えることができます。「説明可能であること」は相手に行動を促すのために良い要素であると考えられます。「説明可能であること」までもサービスとして提供したい場合、有用な選択になるんじゃないかと考えています。

推薦を実施したい相手に紐づく情報がなくても推薦可能

アソシエーションルールマイニングに基づく推薦の場合、推薦を実施したい相手に紐づく情報が必要ありません。例えば、他の推薦手法では、相手の情報(生年月日、性別など)を説明変数として利用する場合があります。それに対して基本的なアソシエーションルールマイニングに基づく推薦では状態(買い物カゴの中身、閲覧履歴など)と過去のルールを組み合わせることで推薦が実現されます。つまり、匿名性が必要な場面や新規顧客にも対応可能です。

日本におけるデータ提供・活用文化の醸成に貢献?

近年モバイル決済が浸透しています。これにより消費者の特徴や行動に基づき様々な恩恵を受けることができる未来*1が想像できます。しかし、データ提供におけるプライバシーなどに関するリスクは存在するため、それを考慮した上で恩恵がない、想像できていない方々がいると言う現状*2もあるかと思います。特に上記2点は、そのような思いを持っている方々にもアプローチが可能です。それゆえ、現状を打破し、今後のデータ活用が浸透するキッカケになるのではないかと考えています。特に、データ提供・活用が実施されていないサービスに対して有効だと考えられます。そして、特に日本におけるデータ提供・活用をブレイクスルーするひとつのキッカケになるのではないかと期待しています。

おわりに

「今こそ“アソシエーションルールマイニングに基づく推薦”の時代なんじゃないか!?」と思ったその思いを綴りました。「推薦の根拠を説明可能」、「推薦を実施したい相手に紐づく情報がなくても推薦可能」という理由より、シチュエーションによってはニーズに応えられる手法なんじゃないでしょうか?今こそ、検討をしてみてはどうでしようか?

Google Apps Scriptへのpush/deployを実行するGitHub Action「Clasp Action」をリリースするまでの記録

先日、Google Apps Script(GAS)へのpush/deployを実行するGitHub Action「Clasp Action」をリリースしました。

github.com

はじめてのゼロからのOSS開発〜リリースだったこともあり、記録を残します。

「ゼロからのOSS開発」をしてみたい

個人的に「ゼロからのOSS開発」をしてみたいと思っていました。OSS開発自体に関しては、お世話になった、感動したOSSにコントリビュートすることがしばしばありました。しかし、自分でゼロから考えて生み出した物はないと思ったことが、今回の行動に至った動機です。また、せっかく作るなら、個人的なこだわりである以下の点を満たしたものをリリースしたいと思っていました。

  • 新規性がある
  • 誰かの課題を解決する
  • 他者でも利用しやすい形態で公開されている

しかし、何を作るかと言ったアイデアはなかなか生まれませんでした。

経験をヒントに思いついたアイデア

イデアは突然思いつきました。以下のような経験にヒントがありました。

  • 業務やOSS活動においてCIを書くのが好きだったこと
  • 業務でGASを数回使っていたこと
  • Gitフローによるバージョン管理を実現するためにclaspを導入したこと

以上より、clasp(ローカル環境からGASを操作するコマンド)を利用して「Google Apps Scriptへのpush/deployを実行するGitHub Action」を作りたいなと思いました。これは、GitHubでバージョン管理しているGASプロジェクトにおけるpush/deployを自動化するという点での貢献につながります。また、GASをGitHubで管理するハードルを下げることにもなるかと思われます。

このようなGitHub ActionをGitHub Marketplaceで公開できたら、自分のこだわりを満たした上で、やりたいことが実現できるなと思いました。

競合の調査

もし、思いついたアイデアを満たすGitHub Actionがすでに存在していた場合、車輪の再発明になってしまいます。個人的なこだわりである「新規性がある」も満たせません。経験としてはいいものの、個人的なこだわりである「誰かの課題を解決する」という点での他者への貢献はないなと思い、まずは競合の調査をしてみました。GitHub Marketplaceでそれっぽいキーワードで検索してみると「Clasp Token」というものがありました。

github.com

これは特定のGASを操作するための認証情報などが格納された「.clasprc.json」を生成するというものです。記述内容的に「.clasprc.jsonリポジトリに格納するのは現実的ではないため、その点で有用で素晴らしいものです。そんな.clasprc.jsonを生成することで、ローカルの環境以外、つまりGitHubのワークフロー上でのclaspの利用によるGASの操作が可能になります。これは拡張性もありいいですね。

差別化・新規性

競合として見つけた「Clasp Token」に対して、以下の点で差別化しようと考えました。

  • 目的をpush/deployに絞る
  • 利用者がclasp扱わなくても問題がない状態に

claspをGitHub Actionで扱う場面を考えた場合、やりたいことはコードの変更点をGASに反映させること、つまりpushやdeployだなと思いました。また、そこまで定まっているならpushもしくはdeployまでやりきってしまう方がいいなと思いました。そんな考えに基づき、claspに慣れていない人でも扱いやすいGitHub Actionにしようと考え、開発しました。

開発開始から完了まで

以上を踏まえて、開発を始めました。工期は1週間くらいで、スキマ時間を使って完了させました。

得られた知見も多いのですが、技術的なことの詳細はQiitaに書こうかと思っています。今回はポイントだけ以下に示します。

  • Dockerを使ったGitHub Actionにした(DockerかJavaScriptを使って実現可能)
  • エントリポイントはシェルスクリプトにした
  • トライアルアンドエラーの精神で何度もテストした
  • プライベートで初めてリリースタグを作った
  • 公式のドキュメントに沿ってGitHub Marketplaceに公開した
  • 最後の心的障壁は無理やり突破した

そんな「Clasp Action」と名付けたGitHub Actionは、現在GitHub Marketplaceで公開されています。これを見るととてもうれしい気持ちになりました😭

感想

Dockerを使ったGitHub Actionは意外と簡単に作れるんだなと思いました。今回、主に書いたのはシェルスクリプトです。ここに実現したい処理を書くのですが、「それだけでできるのか!」と思いました。他の方のリポジトリをみたところ、この部分を、例えばPythonで書いてあったりもしました。それゆえ、Dockerを使ったGitHub Actionは色んな人のやりたい方法で開発できる柔軟な方法だと思いました。新規性さえ見つけられたら(それが難しいんですが…)引き続き開発してみたいです。何より、工期も長くない、小さなものですが、自分がこだわっていた点を満たしたものを作れたのは本当に良かったです。

ひとまず「ゼロからのOSS開発〜リリース」実績解除!(実際やったことはかなりシンプルなのでOSSと言えるものなのかは不安ですが…)今後起こりうる、鬼のバグ報告、要望、バリバリのコントリビュータの出現、初めてのレビューなどを楽しみにしています。

何はともあれ、

  • 新規性がある
  • 誰かの課題を解決する
  • 他者でも利用しやすい形態で公開されている

と言ったこだわりも満たしている「Clasp Action」を是非使ってください🙏

おまけ

学生時代、アルバイトで「GitHubでソフトウェア開発者にフィードバックを与えるチャットボットの実現」を目的としたソフトウェア開発に携わっていた時期あります。課題を解決するためのアイデアを考えたり、壁打ちの壁になることにやりがいを持っていました。しかし、プログラミングが苦手だったため、自分の力不足で、自分の担当箇所は、うまくリリースに漕ぎ着けなかったという、苦い思い出です。もしうまくいけば、GitHub Marketplaceで公開する予定でした。2年がたった現在、偶然ですが、自分がゼロから開発したOSSGitHub Marketplaceに公開しました。少しだけ自分の中のモヤモヤが晴れた気がします。