Python、Streamlit、および Docker を使用して顧客離反予測モデルを開発およびデプロイする方法

画像5 1

顧客離れは、今日の企業にとって数百万ドルの問題です。 SaaS市場はますます飽和状態になりつつあり、顧客は多くのプロバイダーから選択できます。 定着と育成は困難です。 オンラインビジネスは、顧客が商品やサービスの購入を停止すると、顧客を解約と見なします。 顧客の解約は業界固有の要因に依存する可能性がありますが、一般的な要因には、製品の使用状況の欠如、契約期間、他の場所での価格の安さなどがあります。

解約を制限すると、収益源が強化されます。 企業やマーケターは、顧客離れを予測し、防止して持続可能な状態を維持する必要があります。 そのための最善の方法は、顧客を知ることです。 そして、履歴データで行動パターンを見つけることは、これに非常に役立ちます。 では、どうすればそれらを発見できますか? 

機械学習(ML)を顧客データに適用することで、企業は焦点を絞った顧客維持プログラムを開発することができます。 たとえば、マーケティング部門は ML 解約モデルを使用してリスクの高い顧客を特定し、プロモーション コンテンツを送信して顧客を誘惑できます。 

これらのモデルが新しいデータで予測できるようにするには、モデルがユーザー向けの対話型アプリケーションとしてパッケージ化される方法を知っていることが不可欠です。 このブログでは、 ML モデルを Jupyter ノートブック 環境からコンテナー化されたアプリケーションに取り込みます。 アプリケーション フレームワークとして Streamlit を使用して、UI コンポーネントを構築し、モデルをパッケージ化します。 次に、Docker を使用してモデルをエンドポイントとして発行します。 

Docker のコンテナー化は、このアプリケーションをハードウェアと OS に依存しないようにするのに役立ちます。 ユーザーは、エンドポイントを介してブラウザーからアプリにアクセスし、顧客の詳細を入力すると、ほんの一瞬で解約確率を受け取ることができます。 顧客の解約スコアが特定のしきい値を超えた場合、その顧客はターゲットを絞ったプッシュ通知と特別オファーを受け取る可能性があります。 次の図は、これを視野に入れています。 

合理化されたドッカー図

ストリームリットを選ぶ理由

Streamlit は、トレーニング済みのモデルから UI と強力な ML アプリを構築するための、オープンソースの Python ベースのフレームワークです。 最小限のPythonコードとシンプルなAPIを必要とする迅速なWebアプリ開発を可能にするため、機械学習エンジニアやデータサイエンティストの間で人気があります。 このAPIを使用すると、ユーザーはバックエンドコード、ルート、またはリクエストを気にすることなく、純粋なPythonを使用してウィジェットを作成できます。 アプリケーションのニーズを満たすためにチャート、表、およびさまざまな図を作成できるいくつかのコンポーネントを提供します。 Streamlitは、アプリに保存またはピクルスしたモデルも利用して予測を行います。

逆に、FastAPI、Flask、Shinyなどの代替フレームワークでは、インタラクティブなフロントエンドアプリを構築するためにHTML / CSSを十分に把握する必要があります。 Streamlit は、データ アプリを構築して共有するための最速の方法です。 ストリームライトAPIは最小限で、非常に理解しやすいです。 対話型ダッシュボードを作成するには、基になる Python スクリプトに最小限の変更を加える必要があります。

始める

git clone https://github.com/dockersamples/customer-churnapp-streamlit

主要コンポーネント

  • IDE またはテキスト エディター 
  • パイソン 3.6+ 
  • PIP(またはアナコンダ)
  • 必須ではないが推奨: pipenv、venv、virtualenv、conda などの環境管理ツール
  • Docker Desktop

開始する前に、Python 3.6+ をインストールしてください。 その後、次の手順に従って、モデルを実行するために必要なすべてのライブラリをシステムにインストールします。 

プロジェクトのディレクトリ構造は次のようになります。

$ tree
.
├── Churn_EDA_model_development.ipynb
├── Churn_model_metrics.ipynb
├── Dockerfile
├── Pipfile
├── Pipfile.lock
├── WA_Fn-UseC_-Telco-Customer-Churn.csv
├── train.py
├── requirements.txt
├── README.md
├── images
│   ├── churndemo.gif
│   ├── icone.png
│   └── image.png
├── model_C=1.0.bin
└── stream_app.py

仮想環境でのプロジェクトの依存関係のインストール 

ライブラリを使用して Pipenv 仮想 Python 環境を作成し、Streamlit の実行に必要な依存関係をインストールします。 このツールは、 Pipenv プロジェクト パッケージをインストールまたはアンインストールするときに、プロジェクト パッケージ Pipfile を自動的に管理します。 また、 Pipfile.lock 決定論的なビルドの生成に役立つファイルを生成し、作業環境のスナップショットを作成します。 開始するには、次の手順に従ってください。

1)プロジェクトディレクトリを入力します

cd customer-churnapp-streamlit

2)ピペンフをインストールします

pip install pipenv

3)依存関係をインストールする

pipenv install

4)pipenv仮想環境に入る

pipenv shell

これらの手順を完了すると、仮想環境からスクリプトを実行できます。 

単純な機械学習モデルの構築

機械学習では、アルゴリズムと統計モデルを使用します。 これらは履歴データを分析し、明示的なプログラミングなしでパターンから推論を行います。 最終的な目標は、受信データに基づいて結果を予測することです。 

この例では、過去の顧客データからモデルを作成して、どの顧客が離脱する可能性が高いかを予測しています。 顧客を解約または解約なしのいずれかに分類する必要があるため、シンプルでありながら強力な分類モデルをトレーニングします。 このモデルでは、通信会社の 過去の顧客データセットに対してロジスティック回帰を使用します。 このセットは、顧客の人口統計、保有期間、月額料金などを追跡します。 ただし、1つの重要な質問にも答えがあります:顧客は解約しましたか? 

ロジスティック回帰は、独立変数の特定のデータセットに基づいてイベントの確率を推定します。 結果は確率であるため、従属変数は 0 から 1 の間に制限されます。 モデルは複数回反復され、各変数の最適適合係数が計算されます。 これにより、それぞれがチャーンにどの程度影響するかが定量化されます。 これらの係数を使用して、モデルは 0 から 1 までの解約可能性スコアを新規顧客に割り当てることができます。 1を獲得した人は、解約する可能性が非常に高くなります。 0の人が解約する可能性は非常に低いです。 

Python には、Pandas、NumPy、Matplotlib など、データ分析をサポートする優れたライブラリがあります。 Scikit Learn のようなオープンソース フレームワークには、さまざまな ML モデル用のラッパーが事前に構築されています。 API を使用して、ロジスティック回帰モデルをトレーニングします。 この基本的なチャーン予測モデルがどのようにして生まれたかを理解するには、 Churn_EDA_model_development.ipynb を参照してください。 ML モデルを正しく行うには、多くの試行が必要です。 そのため、Jupyter ノートブックまたは IDE を使用することをお勧めします。 

簡単に言うと、次の手順を実行してチャーン予測モデルを作成しました。

  1. 初期データ準備 
    • データ型と列名の健全性チェックを実行する 
    • 必要に応じてデータ型を修正する 
  2. データと特徴の理解 
    • 数値特徴の分布を確認する
    • カテゴリ特徴量の個別の値を確認する 
    • ターゲット特徴量の分布を確認する 
  3. 探索的データ分析 
    • 欠損値を処理する 
    • 外れ値を処理する 
    • 相関関係を理解し、偽の相関関係を特定する 
  4. 特徴エンジニアリングと重要性 
    • さまざまなコホートや機能グループにわたる解約率とリスクスコアを分析する 
    • 相互情報量を計算する 
    • 特徴量の相関関係の確認 
  5. カテゴリ特徴のエンコードと数値特徴のスケーリング 
    • Scikit-Learnのヘルパー関数を使用してカテゴリ特徴を数値に変換します:辞書ベクトル化 
    • 数値特徴量をスケーリングして固定範囲に標準化する 
  6. モデルトレーニング 
    • 適切な ML アルゴリズムを選択する 
    • カスタム パラメーターを使用してモデルをトレーニングする 
  7. モデル評価 
    • Churn_model_metrics.ipynbを参照してください。 
    • 精度、混同表、精度、再現率、ROC 曲線、AUROC、交差検証など、さまざまなメトリックを使用してモデルを評価します。
  8. さまざまなアルゴリズムとモデルのハイパーパラメータに対して手順 6 と 7 を繰り返し、最適なモデルを選択します。

ベスト プラクティスは、Python スクリプトを使用してトレーニング プロセスを自動化することです。 新しいパラメーターまたは新しいデータセットを使用してモデルを再トレーニングすることを選択するたびに、このスクリプトを実行して結果のモデルを保存できます。 

モデルのトレーニングを自動化するスクリプトにモデルをパッケージ化する方法については 、train.py をご覧ください。 

最適なモデルが見つかったら、上記のトレーニング コード スクリプトを実行せずに後で再利用するために保存する必要があります。 始めましょう。

モデルを保存する

機械学習では、トレーニング済みのモデルをファイルに保存し、復元して他のモデルと比較します。 新しいデータを使用してそれらをテストすることもできます。 保存プロセスは Serializationと呼ばれ、復元プロセスは と呼ばれます Deserialization

モデルを保存するために呼び出され Pickle るヘルパー Python ライブラリを使用します。 この Pickle モジュールは、Python オブジェクト構造をシリアライズおよびデシリアライズするための基本的でありながら強力なアルゴリズムを実装しています。 

以下の機能を使用することもできます。 

  • pickle.dump を使用してオブジェクト階層 dump()をシリアル化します。
  • pickle.load 関数を使用して load() データ ストリームを逆シリアル化します。

Scikit-Learnフレームワークを使用して作成されたモデルをサポートし、優れた読み込みパフォーマンスを提供するため、このモデルを選択し Pickle ました。 TensorflowやKerasのような同様のトレーニングフレームワークには、モデルを保存するための独自の組み込みライブラリがあり、アーキテクチャで適切に機能するように設計されています。 

モデルとディクショナリベクタライザのダンプ

import pickle

with open('model_C=1.0.bin', 'wb') as f_out
   pickle.dump((dict_vectorizer, model), f_out)
   f_out.close() ## After opening any file it's necessary to close it

という名前の model_C=1.0.bin バイナリファイルを保存してforone dict_vectorizer Hot Encoding を書き、その中に配列として含め Logistic Regression Model ました。 

新しい Python ファイルを作成する

次に、アプリのレイアウトとトリガー可能なバックエンド ロジックの両方を定義するスクリプトを作成します stream_app.py 。 このロジックは、ユーザーがさまざまな UI コンポーネントを操作するとアクティブになります。 重要なのは、このファイルはどのモデルでも再利用できることです。 

これは単なる例です。 Streamlitライブラリからより多くのコンポーネントと設計オプションを調べることを強くお勧めします。HTML と JavaScript に精通している場合は、独自の Streamlit コンポーネントを作成して、アプリのレイアウトをより細かく制御できます。 

まず、必要なライブラリをインポートします。

import pickle
import streamlit as st
import pandas as pd
from PIL import Image

次に、前に保存したのと同じバイナリ ファイルをロードして、モデルとディクショナリ ベクタライザーを逆シリアル化する必要があります。

model_file = 'model_C=1.0.bin'

with open(model_file, 'rb') as f_in:
    dv, model = pickle.load(f_in)

次のコードスニペットは、画像をロードして画面に表示します。 この st.image 部分は、フロントエンドに画像を表示するのに役立ちます。

image = Image.open('images/icone.png') 
image2 = Image.open('images/image.png')
  
st.image(image,use_column_width=False)

サイドバーに項目を表示するには、次のコードスニペットが必要です。

add_selectbox = st.sidebar.selectbox("How would you like to predict?",
("Online", "Batch"))

st.sidebar.info('This app is created to predict Customer Churn')
st.sidebar.image(image2)

Streamlitのサイドバーは、ユーザーがバッチスコアリング(複数の顧客の予測)やオンラインスコアリング(単一の顧客の場合)など、実行するモデルスコアリングのタイプを選択できる垂直の折りたたみ可能なバーをレンダリングします。 また、サイドバーを飾るためにテキストや画像を追加します。 

次のコードは、メインのタイトルを表示するのに役立ちます。

st.title("Predicting Customer Churn")

入力ウィジェットを表示して、ユーザーが「オンライン」オプションを選択したときに、顧客の詳細を収集し、予測を生成できます。

if add_selectbox == 'Online':
  
		gender = st.selectbox('Gender:', ['male', 'female'])
		seniorcitizen= st.selectbox(' Customer is a senior citizen:', [0, 1])
		partner= st.selectbox(' Customer has a partner:', ['yes', 'no'])
		dependents = st.selectbox(' Customer has  dependents:', ['yes', 'no'])
		phoneservice = st.selectbox(' Customer has phoneservice:', ['yes', 'no'])
		multiplelines = st.selectbox(' Customer has multiplelines:', ['yes', 'no', 'no_phone_service'])
		internetservice= st.selectbox(' Customer has internetservice:', ['dsl', 'no', 'fiber_optic'])
		onlinesecurity= st.selectbox(' Customer has onlinesecurity:', ['yes', 'no', 'no_internet_service'])
		onlinebackup = st.selectbox(' Customer has onlinebackup:', ['yes', 'no', 'no_internet_service'])
		deviceprotection = st.selectbox(' Customer has deviceprotection:', ['yes', 'no', 'no_internet_service'])
		techsupport = st.selectbox(' Customer has techsupport:', ['yes', 'no', 'no_internet_service'])
		streamingtv = st.selectbox(' Customer has streamingtv:', ['yes', 'no', 'no_internet_service'])
		streamingmovies = st.selectbox(' Customer has streamingmovies:', ['yes', 'no', 'no_internet_service'])
		contract= st.selectbox(' Customer has a contract:', ['month-to-month', 'one_year', 'two_year'])
		paperlessbilling = st.selectbox(' Customer has a paperlessbilling:', ['yes', 'no'])
		paymentmethod= st.selectbox('Payment Option:', ['bank_transfer_(automatic)', 'credit_card_(automatic)', 'electronic_check' ,'mailed_check'])
		tenure = st.number_input('Number of months the customer has been with the current telco provider :', min_value=0, max_value=240, value=0)
		monthlycharges= st.number_input('Monthly charges :', min_value=0, max_value=240, value=0)
		totalcharges = tenure*monthlycharges
		output= ""
		output_prob = ""
		input_dict={
				"gender":gender ,
				"seniorcitizen": seniorcitizen,
				"partner": partner,
				"dependents": dependents,
				"phoneservice": phoneservice,
				"multiplelines": multiplelines,
				"internetservice": internetservice,
				"onlinesecurity": onlinesecurity,
				"onlinebackup": onlinebackup,
				"deviceprotection": deviceprotection,
				"techsupport": techsupport,
				"streamingtv": streamingtv,
				"streamingmovies": streamingmovies,
				"contract": contract,
				"paperlessbilling": paperlessbilling,
				"paymentmethod": paymentmethod,
				"tenure": tenure,
				"monthlycharges": monthlycharges,
				"totalcharges": totalcharges
			}
          
		if st.button("Predict"):
			X = dv.transform([input_dict])
			y_pred = model.predict_proba(X)[0, 1]
			churn = y_pred >= 0.5
			output_prob = float(y_pred)
			output = bool(churn)
		st.success('Churn: {0}, Risk Score: {1}'.format(output, output_prob))

アプリのフロントエンドは、選択ボックス、スライダー、数値入力などのStreamlitの入力ウィジェットを活用します。 ユーザーは、値を入力してこれらのウィジェットを操作します。 その後、入力データは Python ディクショナリにパッケージ化されます。 予測スコアの計算ロジックを処理するバックエンドは、 st.button レイヤー内で定義され、ユーザー トリガーを待機します。 この場合、ディクショナリはディクショナリ ベクタライザに渡され、カテゴリ特徴のエンコードが実行され、モデルで使用できるようになります。 

Streamlit は、変換された入力をモデルに渡し、チャーン予測スコアを計算します。 しきい値の 0.5 を使用すると、チャーン スコアはバイナリ クラスに変換されます。 リスクスコアと解約クラスは、Streamlitの成功コンポーネントを介してフロントエンドに返されます。 これにより、成功メッセージが表示されます。 

ユーザーがサイドバーから「バッチ」を選択したときにファイルアップロードボタンを表示するには、次のコードスニペットが役立つ場合があります。

if add_selectbox == 'Batch':
		file_upload = st.file_uploader("Upload csv file for predictions", type=["csv"])
		if file_upload is not None:
			data = pd.read_csv(file_upload)
			X = dv.transform([data])
			y_pred = model.predict_proba(X)[0, 1]
			churn = y_pred >= 0.5
			churn = bool(churn)
			st.write(churn)

ユーザーが顧客をバッチ スコアリングする場合、ページ レイアウトはこの選択に合わせて動的に変更されます。 Streamlitのファイルアップローダーコンポーネントは、関連するウィジェットを表示します。 これにより、ユーザーは CSV ファイルをアップロードするよう求められ、そのファイルは panda ライブラリを使用して読み取られ、ディクショナリ ベクタライザーとモデルによって処理されます。 を使用してフロントエンド st.writeに予測スコアを表示します。 

上記のアプリケーションスケルトンは、以下のスクリプトのmain関数内にラップされています。 スクリプトを実行すると、main 関数が呼び出されます。 最終的なスクリプトは次のようになります。

import pickle
import streamlit as st
import pandas as pd
from PIL import Image
model_file = 'model_C=1.0.bin'


with open(model_file, 'rb') as f_in:
    dv, model = pickle.load(f_in)


def main():
	image = Image.open('images/icone.png') 
	image2 = Image.open('images/image.png')
	st.image(image,use_column_width=False) 
	add_selectbox = st.sidebar.selectbox(
	"How would you like to predict?",
	("Online", "Batch"))
	st.sidebar.info('This app is created to predict Customer Churn')
	st.sidebar.image(image2)
	st.title("Predicting Customer Churn")
	if add_selectbox == 'Online':
		gender = st.selectbox('Gender:', ['male', 'female'])
		seniorcitizen= st.selectbox(' Customer is a senior citizen:', [0, 1])
		partner= st.selectbox(' Customer has a partner:', ['yes', 'no'])
		dependents = st.selectbox(' Customer has  dependents:', ['yes', 'no'])
		phoneservice = st.selectbox(' Customer has phoneservice:', ['yes', 'no'])
		multiplelines = st.selectbox(' Customer has multiplelines:', ['yes', 'no', 'no_phone_service'])
		internetservice= st.selectbox(' Customer has internetservice:', ['dsl', 'no', 'fiber_optic'])
		onlinesecurity= st.selectbox(' Customer has onlinesecurity:', ['yes', 'no', 'no_internet_service'])
		onlinebackup = st.selectbox(' Customer has onlinebackup:', ['yes', 'no', 'no_internet_service'])
		deviceprotection = st.selectbox(' Customer has deviceprotection:', ['yes', 'no', 'no_internet_service'])
		techsupport = st.selectbox(' Customer has techsupport:', ['yes', 'no', 'no_internet_service'])
		streamingtv = st.selectbox(' Customer has streamingtv:', ['yes', 'no', 'no_internet_service'])
		streamingmovies = st.selectbox(' Customer has streamingmovies:', ['yes', 'no', 'no_internet_service'])
		contract= st.selectbox(' Customer has a contract:', ['month-to-month', 'one_year', 'two_year'])
		paperlessbilling = st.selectbox(' Customer has a paperlessbilling:', ['yes', 'no'])
		paymentmethod= st.selectbox('Payment Option:', ['bank_transfer_(automatic)', 'credit_card_(automatic)', 'electronic_check' ,'mailed_check'])
		tenure = st.number_input('Number of months the customer has been with the current telco provider :', min_value=0, max_value=240, value=0)
		monthlycharges= st.number_input('Monthly charges :', min_value=0, max_value=240, value=0)
		totalcharges = tenure*monthlycharges
		output= ""
		output_prob = ""
		input_dict={
				"gender":gender ,
				"seniorcitizen": seniorcitizen,
				"partner": partner,
				"dependents": dependents,
				"phoneservice": phoneservice,
				"multiplelines": multiplelines,
				"internetservice": internetservice,
				"onlinesecurity": onlinesecurity,
				"onlinebackup": onlinebackup,
				"deviceprotection": deviceprotection,
				"techsupport": techsupport,
				"streamingtv": streamingtv,
				"streamingmovies": streamingmovies,
				"contract": contract,
				"paperlessbilling": paperlessbilling,
				"paymentmethod": paymentmethod,
				"tenure": tenure,
				"monthlycharges": monthlycharges,
				"totalcharges": totalcharges
			}
		if st.button("Predict"):
           
			X = dv.transform([input_dict])
			y_pred = model.predict_proba(X)[0, 1]
			churn = y_pred >= 0.5
			output_prob = float(y_pred)
			output = bool(churn)
 
		st.success('Churn: {0}, Risk Score: {1}'.format(output, output_prob))

	if add_selectbox == 'Batch':

		file_upload = st.file_uploader("Upload csv file for predictions", type=["csv"])
		if file_upload is not None:
			data = pd.read_csv(file_upload)
			X = dv.transform([data])
			y_pred = model.predict_proba(X)[0, 1]
			churn = y_pred >= 0.5
			churn = bool(churn)
			st.write(churn)


if __name__ == '__main__':
	main()

完全なスクリプトは、 Dockersamples GitHub ページからダウンロードできます。

スクリプトを実行する

streamlit run stream_app.py

ストリームライト アプリを表示する

これで、ブラウザでストリームライトアプリを表示できます。 次の場所に移動します。

画像3 1

Docker を使用した Streamlit アプリのコンテナー化

Docker の公式イメージを使用して、Docker コンテナー内でこのアプリを簡単に実行する方法を見てみましょう。 まず、 Dockerデスクトップをダウンロードする必要があります。 Docker Desktop は、有用なイメージを見つけやすくしながら、イメージ構築プロセスを高速化します。 ダウンロードが完了したら、このインストールプロセスを完了します。

Docker は Dockerfile を使用して、各イメージの "レイヤー" を指定します。 各レイヤーには、基本イメージの標準構成に起因する重要な変更が格納されます。 ストリームライトプロジェクトに空 Dockerfile を作成します。

touch Dockerfile

次に、お気に入りのテキストエディタを使用してこれ Dockerfileを開きます。 この新しいファイルを少しずつ構築していきます。 まず、基本イメージを定義しましょう。

FROM python:3.8.12-slim

次に、最新のpipモジュールがインストールされていることを確認します。

RUN /usr/local/bin/python -m pip install --upgrade pip

次に、イメージのアプリケーション コードを格納するディレクトリをすばやく作成しましょう。 これは、アプリケーションの作業ディレクトリです。

WORKDIR /app

次の手順 COPY では、要件ファイルをホスト コンピューターからコンテナー イメージにコピーします。

COPY requirements.txt ./requirements.txt
RUN pip install -r requirements.txt

この命令は EXPOSE 、コンテナが実行時に指定されたネットワークポートでリッスンしていることをDockerに通知します。

EXPOSE 8501

最後に、イメージを実行可能にするためにを作成します ENTRYPOINT

ENTRYPOINT ["streamlit", "run"]
CMD ["stream_app.py"]

各ピースを組み立てた後、ここにあなたの完全な Dockerfileものがあります:

FROM python:3.8.12-slim
RUN /usr/local/bin/python -m pip install --upgrade pip
WORKDIR /app
COPY requirements.txt ./requirements.txt
RUN pip install -r requirements.txt
EXPOSE 8501
COPY . .
ENTRYPOINT ["streamlit", "run"]
CMD ["stream_app.py"]

イメージをビルドする

docker build -t customer_churn .

アプリを実行する

docker run -d -p 8501:8501 customer_churn

Docker デスクトップ内でアプリを表示する

これを行うには、実行中のアプリケーションを名前付きコンテナーとして一覧表示する Containers インターフェイスに移動します。

画像1 2

アプリにアクセスする

まず、一覧からアプリ コンテナーを選択します。 これにより、[ログ] ビューが開きます。 [統計] ペインの横にある四角いアイコン (斜めの矢印) が付いたボタンをクリックします。 これにより、ブラウザーでアプリが開きます。

画像2 1
画像3 2

または、リスト内のコンテナにカーソルを合わせ、右側のツールバーが表示されたらそのアイコンをクリックすることもできます。

今すぐ次の機械学習モデルを開発してデプロイしましょう

万丈!Streamlit と Docker を使用して顧客離れ予測モデルを構築してデプロイする方法を正常に調べました。 単一の Dockerfileで、インタラクティブなフロントエンドを簡単に構築し、このアプリケーションを数秒でデプロイできることを示しました。 

このチュートリアルを使用して、いくつかの追加手順を実行するだけで、はるかに複雑なアプリケーションを構築できます。 アプリにプッシュ通知ロジックを実装して、マーケティングチームが解約率の高い顧客にプロモーションメールを送信できるようにすることで、アプリをより便利にすることができます。 ハッピーコーディング。

フィードバック

「Python、Streamlit、およびDockerを使用して顧客解約予測モデルを開発および展開する方法」に関する0の考え