# ライブラリを読み込む
import scipy as sp
import numpy as np
from scipy.optimize import minimize # 最適化
from scipy.stats import entropy # エントロピー計算
# 表示桁数の設定
%precision 3
# エントロピー計算
probs = np.array([0.8, 0.2])
H = -1*probs[0]*sp.log(probs[0]) - probs[1]*sp.log(probs[1])
print('情報エントロピー')
print(H)
print('情報エントロピー(関数使用)')
print(entropy(probs))
# 最も大きなエントロピー
probs = np.array([0.5, 0.5])
entropy(probs)
# 価格の比率
cost_ratio = np.array([1,3])
# 目的関数
def target_func(user_ratio):
return (float)(-1 * entropy(user_ratio)/(sum(user_ratio * cost_ratio)))
# 制約条件式
# 「0よりも大きい」を表すために、小さな値を足しこんでいる(デフォルトだと0以上の設定)
cons = (
{'type': 'ineq','fun': lambda p: p[0]},
{'type': 'ineq','fun': lambda p: p[1]},
{'type': 'eq', 'fun': lambda p: p[0] + p[1] - 1}
)
# 初期値
p = np.array([0.5,0.5])
# ソルバーを実行
result = minimize(target_func,
x0=p,
constraints=cons,
method="SLSQP",
options={'maxiter': 10000, 'ftol': 1e-10})
# 結果の表示
print('エントロピーモデルにより計算された購入比率')
print(result.x)
# エントロピーモデルの1因子情報路モデルの推定
def entropy_model_one(cost_ratio):
'''
エントロピーモデルの1因子情報路モデルの推定
Arguments:
cost_ratio -- 商品コストの比率。金額の比率や消費時間の比率等。
'''
# ランクの数
rank_num = len(cost_ratio)
# 最適化の目的関数
target_func = lambda user_ratio: (float)(-1 * entropy(user_ratio)/(sum(user_ratio * cost_ratio)))
# 制約条件の作成
construction = []
# すべての確率が0以上という制約
for i in range(0, rank_num):
construction.append({'type': 'ineq','fun': lambda p: p[i]})
# 確率の合計が1であるという制約
construction.append({'type': 'eq','fun': lambda p: sum(p) - 1})
# 初期値
p0 = np.tile(1/rank_num, rank_num)
# ソルバーを実行
result = minimize(fun=target_func,
x0=p0,
constraints=construction,
method="SLSQP",
options={'maxiter': 10000, 'ftol': 1e-10})
return result
# 1因子情報路モデルによる理論上の購入比率
print(entropy_model_one(np.array([1,3])).x)
# コスト比率を変えて、商品Bをさらに2倍お得にした時のユーザー比率
print(entropy_model_one(np.array([1,6])).x)
# コスト比率を細かく分けた時
print(entropy_model_one(np.array([1,2,3,4,5])).x)
# 価格の比率
cost_ratio = np.array([3,1])
print('価格の比率')
print(cost_ratio)
# 理論上の選択率
user_ratio_by_cost = entropy_model_one(cost_ratio).x
print('金額の比率から求められる、理論上の商品選択率')
print(user_ratio_by_cost)
# 実際の選択率
true_user_ratio = np.array([0.7,0.3])
print('実際の選択率')
print(true_user_ratio)
# 目的関数(エントロピー最大化)
def target_function(p):
return (float)(-1*(entropy(p) + p[2]*entropy(user_ratio_by_cost)))
# 制約条件:確率は0以上で合計値は1
# 制約条件:実際の選択率と等しくなる
cons = (
{'type': 'ineq','fun': lambda p: p[0]},
{'type': 'ineq','fun': lambda p: p[1]},
{'type': 'ineq','fun': lambda p: p[2]},
{'type': 'eq', 'fun': lambda p: p[0] + p[1] + p[2] - 1},
{'type': 'eq', 'fun': lambda p: p[0] + p[2] * user_ratio_by_cost[0] - true_user_ratio[0]}
)
# 初期値
p = np.array([0.7,0.3,0])
# ソルバーを実行
stable_user_ratio = minimize(target_function,
x0=p,
constraints=cons,
method="SLSQP",
options={'maxiter': 10000, 'ftol': 1e-10})
print('商品Aの固定層:商品Bの固定層:価格によって購入するものを変える層')
print(stable_user_ratio.x)
# 実際の選択率と一致していることの確認
stable_user_ratio.x[0] + stable_user_ratio.x[2]*user_ratio_by_cost[0]
# 実際の選択率と一致していることの確認
stable_user_ratio.x[1] + stable_user_ratio.x[2]*user_ratio_by_cost[1]
# 価格の比率
cost_ratio = np.array([1,2,4])
print('価格の比率')
print(cost_ratio)
# 所要時間の比率
time_ratio = np.array([8,3,1])
print('所要時間の比率')
print(time_ratio)
# 価格の比率に基づく理論上の選択率
user_ratio_by_cost = entropy_model_one(cost_ratio).x
print('価格の比率に基づく理論上の選択率')
print(user_ratio_by_cost)
# 所要時間の比率に基づく理論上の選択率(無理やり並び替えた)
user_ratio_by_time = entropy_model_one(time_ratio).x
print('所要時間の比率に基づく理論上の選択率')
print(user_ratio_by_time)
# 実際の選択率
true_user_ratio = np.array([0.1,0.4,0.5])
print('実際の選択率')
print(true_user_ratio)
# 目的関数(エントロピー最大化)
def target_function(p):
return (float)(-1*(entropy(p) + p[3]*entropy(user_ratio_by_cost) + p[4]*entropy(user_ratio_by_time)))
# 制約条件:実際の選択率と等しくなる
cons = (
{'type': 'ineq','fun': lambda p: p[0]},
{'type': 'ineq','fun': lambda p: p[1]},
{'type': 'ineq','fun': lambda p: p[2]},
{'type': 'ineq','fun': lambda p: p[3]},
{'type': 'ineq','fun': lambda p: p[4]},
{'type': 'eq', 'fun': lambda p: p[0] + p[1] + p[2] + p[3] + p[4] - 1},
{'type': 'eq', 'fun': lambda p: p[0] + p[3]*user_ratio_by_cost[0] + p[4]*user_ratio_by_time[0] - true_user_ratio[0]},
{'type': 'eq', 'fun': lambda p: p[1] + p[3]*user_ratio_by_cost[1] + p[4]*user_ratio_by_time[1] - true_user_ratio[1]}
)
# 初期値
p0 = np.array([0.5,0.3,0.2,0,0])
# ソルバーを実行
user_pattern_ratio = minimize(target_function,
x0=p0,
constraints=cons,
method="SLSQP",
options={'maxiter': 10000, 'ftol': 1e-10})
print('商品Aの固定層:商品Bの固定層:商品Cの固定層:価格によって変える層:消費時間によって変える層')
print(user_pattern_ratio.x)