一、知识点
1.matplotlib图例legend语法及设置
loc 设置图例位置 其他用法参考
https://blog.csdn.net/helunqu2017/article/details/78641290
2.seek_choice = np.random.choice([0, 1, 2], 80000, p=weights)
是指以p([0.1, 0.2, 0.7])概率随机抽取seek_choice的[0,1,2]8000次,形成一个数组
seek_ind = seek_choice[2]提取数组第3个元素
3.n = numpy.random.random() 生成一个0~1随机的浮点数
weights/=np.sum(n) 依据上述生成的随机数生成比例
4.scipy 使用文档https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.fmin_bfgs.html
二、模型
from abcimport ABCMeta, abstractmethod
import matplotlib.pyplotas plt
import six
import numpyas np
import pandasas pd
from mpl_toolkits.mplot3dimport Axes3D
K_INIT_LIVING_DAYS =27375
class Person(object):
def __init__(self):
self.living = K_INIT_LIVING_DAYS
self.happiness =0
self.wealth =0
self.fame =0
self.living_day =0
def live_one_day(self, seek):
consume_living, happiness, wealth, fame = seek.do_seek_day()
self.living -=consume_living
self.happiness += happiness
self.wealth +=wealth
self.fame +=fame
self.living_day +=1
class BaseSeekDay(six.with_metaclass(ABCMeta, object)):
def __init__(self):
self.living_consume =0
self.happiness_base =0
self.wealth_base =0
self.fame_base =0
self.living_factor = [0]
self.happiness_factor = [0]
self.wealth_factor = [0]
self.fame_factor = [0]
self.do_seek_day_cnt =0
self._init_self()
@abstractmethod
def _init_self(self, *args, **kwargs):
pass
@abstractmethod
def _gen_living_days(self, *args, **kwargs):
pass
def do_seek_day(self):
if self.do_seek_day_cnt >=len(self.living_factor):
# 超出len(self.living_factor), 就取最后一个living_factor[-1]
consume_living = \
self.living_factor[-1] *self.living_consume
else:
# 每个类自定义这个追求的消耗生命常数,以及living_factor,比如
# HealthSeekDay追求健康,living_factor序列的值即由负值->正值
# 每个子类living_factor会有自己特点的变化速度及序列长度,导致每个
# 追求对生命的消耗随着追求的次数变化不一
consume_living =self.living_factor[self.do_seek_day_cnt] \
*self.living_consume
# 幸福指数=happiness_base:幸福常数 * happiness_factor:可变序列
if self.do_seek_day_cnt >=len(self.happiness_factor):
# 超出len(self.happiness_factor), 就取最后一个
# 由于happiness_factor值由:n—>0 所以happiness_factor[-1]=0
# 即随着追求一个事物的次数过多后会变的没有幸福感
happiness =self.happiness_factor[-1] *self.happiness_base
else:
# 每个类自定义这个追求的幸福指数常数,以及happiness_factor
# happiness_factor子类的定义一般是从高->低变化
happiness =self.happiness_factor[self.do_seek_day_cnt] *self.happiness_base
# 财富积累=wealth_base:积累常数 * wealth_factor:可变序列
if self.do_seek_day_cnt >=len(self.wealth_factor):
# 超出len(self.wealth_factor), 就取最后一个
wealth =self.wealth_factor[-1] *self.wealth_base
else:
# 每个类自定义这个追求的财富指数常数,以及wealth_factor
wealth =self.wealth_factor[self.do_seek_day_cnt] *self.wealth_base
# 权利积累=fame_base:积累常数 * fame_factor:可变序列
if self.do_seek_day_cnt >=len(self.fame_factor):
# 超出len(self.fame_factor), 就取最后一个
fame =self.fame_factor[-1] *self.fame_base
else:
# 每个类自定义这个追求的名望权利指数常数,以及fame_factor
fame =self.fame_factor[self.do_seek_day_cnt] *self.fame_base
# 追求了多少天了这一生 + 1
self.do_seek_day_cnt +=1
# 返回这个追求这一天对生命的消耗,得到的幸福,财富,名望权利
return consume_living, happiness, wealth, fame
def regular_mm(group):
# 最小-最大规范化
return (group - group.min()) / (group.max() - group.min())
class HealthSeekDay(BaseSeekDay):
"""
HealthSeekDay追求健康长寿的一天:
形象:健身,旅游,娱乐,做感兴趣的事情。
抽象:追求健康长寿。
"""
def _init_self(self):
# 每天对生命消耗的常数=1,即代表1天
self.living_consume =1
# 每天幸福指数常数=1
self.happiness_base =1
# 设定可变因素序列
self._gen_living_days()
def _gen_living_days(self):
# 只生成12000个序列,因为下面的happiness_factor序列值由1->0
# 所以大于12000次的追求都将只是单纯消耗生命,并不增加幸福指数
# 即随着做一件事情的次数越来越多,幸福感越来越低,直到完全体会不到幸福
days = np.arange(1, 12000)
# 基础函数选用sqrt, 影响序列变化速度
living_days = np.sqrt(days)
"""
对生命消耗可变因素序列值由-1->1, 也就是这个追求一开始的时候对生命
的消耗为负增长,延长了生命,随着追求的次数不断增多对生命的消耗转为正
数因为即使一个人天天锻炼身体,天天吃营养品,也还是会有自然死亡的那
一天
"""
# *2-1的目的:regular_mm在0-1之间,HealthSeekDay要结果在-1,1之间
self.living_factor = regular_mm(living_days) *2 -1
# 结果在1-0之间 [::-1]: 将0->1转换到1->0
self.happiness_factor = regular_mm(days)[::-1]
class StockSeekDay(BaseSeekDay):
"""
StockSeekDay追求财富金钱的一天:
形象:做股票投资赚钱的事情。
抽象:追求财富金钱
"""
def _init_self(self, show=False):
# 每天对生命消耗的常数=2,即代表2天
self.living_consume =2
# 每天幸福指数常数=0.5
self.happiness_base =0.5
# 财富积累常数=10,默认=0
self.wealth_base =10
# 设定可变因素序列
self._gen_living_days()
def _gen_living_days(self):
# 只生成10000个序列
days = np.arange(1, 10000)
# 针对生命消耗living_factor的基础函数还是sqrt
living_days = np.sqrt(days)
# 由于不需要像HealthSeekDay从负数开始,所以直接regular_mm 即:0->1
self.living_factor = regular_mm(living_days)
# 针对幸福感可变序列使用了np.power4,即变化速度比sqrt快
happiness_days = np.power(days, 4)
# 幸福指数可变因素会快速递减由1->0
self.happiness_factor = regular_mm(happiness_days)[::-1]
"""
这里简单设定wealth_factor=living_factor
living_factor(0-1), 导致wealth_factor(0-1), 即财富积累越到
后面越有效率,速度越快,头一个100万最难赚
"""
self.wealth_factor =self.living_factor
class FameSeekDay(BaseSeekDay):
"""
FameTask追求名望权力的一天:
追求名望权力
"""
def _init_self(self):
# 每天对生命消耗的常数=3,即代表3天
self.living_consume =3
# 每天幸福指数常数=0.6
self.happiness_base =0.6
# 名望权利积累常数=10,默认=0
self.fame_base =10
# 设定可变因素序列
self._gen_living_days()
def _gen_living_days(self):
# 只生成12000个序列
days = np.arange(1, 12000)
# 针对生命消耗living_factor的基础函数还是sqrt
living_days = np.sqrt(days)
# 由于不需要像HealthSeekDay从负数开始,所以直接regular_mm 即:0->1
self.living_factor = regular_mm(living_days)
# 针对幸福感可变序列使用了np.power2
# 即变化速度比StockSeekDay慢但比HealthSeekDay快
happiness_days = np.power(days, 2)
# 幸福指数可变因素递减由1->0
self.happiness_factor = regular_mm(happiness_days)[::-1]
# 这里简单设定fame_factor=living_factor
self.fame_factor =self.living_factor
# 初始化我, 你一生的故事:HealthSeekDay
def my_life(weights):
seek_health = HealthSeekDay()
seek_stock = StockSeekDay()
seek_fame = FameSeekDay()
seek_list = [seek_health, seek_stock, seek_fame]
me = Person()
seek_choice = np.random.choice([0, 1, 2], 80000, p=weights)
while me.living >0:
seek_ind = seek_choice[me.living_day]
seek = seek_list[seek_ind]
me.live_one_day(seek)
return round(me.living_day /365, 2), round(me.happiness, 2), round(me.wealth, 2), round(me.fame, 2)
# living_day, happiness, wealth, fame = my_life([0.4, 0.3, 0.3])
# print('活了{}年,幸福指数{}, 积累财富{}, 名望权力{}'.format(living_day, happiness, wealth, fame))
result = []
for _in range(20):
weights = np.random.random(3)
weights /= np.sum(weights)
result.append((weights, my_life(weights)))
sorted_scores =sorted(result, key=lambda x:x[1][1], reverse=True)
living_day, happiness, wealth, fame = my_life(sorted_scores[0][0])
# print('活了{}年,幸福指数{}, 积累财富{}, 名望权力{}'.format
# (living_day, happiness, wealth, fame))
#
# print('人生最优权重:追求健康{:.3f},追求财富{:.3f},追求名望{:.3f}'.format(
# sorted_scores[0][0][0], sorted_scores[0][0][1],
# sorted_scores[0][0][2]))
result_show = np.array([[r[0][0], r[0][1], r[0][2], r[1][1]]for rin result])
fig = plt.figure(figsize=(9, 6))
ax = fig.gca(projection='3d')
ax.view_init(30, 60)
"""
x:追求健康长寿快乐的权重, y:追求财富金钱的权重
z:追求名望权力的权重, c:color 幸福指数, 颜色越深越幸福
"""
ax.scatter3D(result_show[:, 0], result_show[:, 1], result_show[:, 2],
c=result_show[:, 3], cmap='spring')
ax.set_xlabel('health')
ax.set_ylabel('stock')
ax.set_zlabel('fame')
# 幸福指数
happiness_result = result_show[:, 3]
# 使用qcut分10份
print(pd.qcut(happiness_result, 10).value_counts())
plt.show()
(本文学习自阿布量化https://www.abuquant.com)