diff --git a/.idea/misc.xml b/.idea/misc.xml
index fccf0cb..de0b43c 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 9d36c46..73ee83b 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,7 +2,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/hire.iml b/.idea/salary02.iml
similarity index 76%
rename from .idea/hire.iml
rename to .idea/salary02.iml
index 8180d6b..16b41b0 100644
--- a/.idea/hire.iml
+++ b/.idea/salary02.iml
@@ -4,7 +4,7 @@
-
+
\ No newline at end of file
diff --git a/data_analysis.py b/data_analysis.py
index 57b4b7c..8a68813 100644
--- a/data_analysis.py
+++ b/data_analysis.py
@@ -1,10 +1,11 @@
import numpy as np
import pandas as pd
+import matplotlib.pyplot as plt
num_time_step = 200
num_iter = 10
-env_data = pd.DataFrame(pd.read_excel('env_data.xlsx', engine='openpyxl'))
+env_data = pd.DataFrame(pd.read_excel('env_data.xlsx', engine='openpyxl', sheet_name=0))
assert env_data.shape[0] == num_iter * (num_time_step + 1)
@@ -12,16 +13,16 @@ lst_df = []
for i in range(num_iter):
df_tmp = env_data.iloc[i * (num_time_step + 1): (i + 1) * (num_time_step + 1), 1:]
lst_df.append(df_tmp)
-# df_tmp = env_data.iloc[1: 21]
-# lst_df.append(df_tmp)
+lst_column = lst_df[0].columns[1:]
-x = np.array(env_data[['t']])
-y = np.array(env_data[['out_w_avg_salary']])
-
-import matplotlib.pyplot as plt
-
-plt.xlabel('t')
-plt.ylabel('out_w_avg_salary')
-plt.plot(x, y)
-plt.show()
+for str_col in lst_column:
+ x = np.arange(num_time_step+1)
+ for df in lst_df:
+ y = np.array(df[str_col]).flatten()
+ plt.xlabel('t')
+ plt.ylabel(str_col)
+ plt.plot(x, y)
+ # plt.show()
+ # plt.close()
+ plt.savefig(f'{str_col}.pdf', bbox_inches="tight")
diff --git a/env.py b/env.py
index 7c0ae1e..f099617 100644
--- a/env.py
+++ b/env.py
@@ -3,27 +3,26 @@ import numpy as np
from random import uniform
import math
-from traits.trait_types import self
-
from worker import WorkerAgent
from firm import FirmAgent
# plt.ion()
+
class Env(ap.Model):
float_market_size: float
- percent_rh: float
+ # percent_rh: float
percent_search: float
n_worker: int
n_firm: int
e_revenue: float
- a_lst_worker: ap.AgentList
- a_lst_firm: ap.AgentList
+ a_lst_worker: ap.AgentList[WorkerAgent]
+ a_lst_firm: ap.AgentList[FirmAgent]
"""
Worker: Mean(s), Gini(s)
- Firm: Mean(($$\pi_{j,t}$$)), Gini($$\pi_{j,t}$$)
+ Firm: Mean((pi_{j,t})), Gini(pi_{j,t})
Env: Percent(IsHired)
"""
out_w_avg_salary: float
@@ -44,7 +43,7 @@ class Env(ap.Model):
# 在工人列表中添加工人
for i in range(self.n_worker):
- # 初始化 workeragent,并把alpha属性传过去
+ # 初始化 worker agent,并把alpha属性传过去
w = WorkerAgent(self, self.p.alpha)
self.a_lst_worker.append(w)
@@ -74,13 +73,15 @@ class Env(ap.Model):
self.create_and_destroy_bankrupt_firms()
+ self.a_lst_worker.update_wd_by_is_hired()
+
# self.picture_out()
self.update()
if self.t == 200:
self.stop()
# self.picture_out()
- pass
+ # pass
def update(self):
lst_salary = []
@@ -94,11 +95,11 @@ class Env(ap.Model):
self.out_w_gini_salary = self.gini(lst_salary)
lst_profit = []
- n_w_firm = 0
+ # n_w_firm = 0
for f in self.a_lst_firm:
lst_profit.append(f.s_profit)
- if f.s_profit > 0:
- n_w_firm += 1
+ # if f.s_profit > 0:
+ # n_w_firm += 1
n_firms = len(lst_profit)
self.out_f_avg_profit = sum(lst_profit) / n_firms
self.out_f_gini_profit = self.gini(lst_profit)
@@ -111,54 +112,37 @@ class Env(ap.Model):
self.record('out_w_percent_hired')
def create_and_destroy_bankrupt_firms(self):
- n_bankrupt_firms = 0
for f in self.a_lst_firm:
if f.s_value < 0:
- # 直接淘汰企业(此处设定为清空企业员工,清空企业利润值和价值,相当于重新添加了一个新的企业?)
- n_bankrupt_firms += 1
- for work in f.l_senior_workers:
- work.s_is_hired = False
- for work in f.l_junior_workers:
- work.s_is_hired = False
- f.s_profit = 0
- f.s_value = 0
+ # 直接淘汰企业,并新增一个企业
+ for worker in f.l_senior_workers:
+ worker.s_is_hired = False
+ worker.working_firm = None
+ for worker in f.l_junior_workers:
+ worker.s_is_hired = False
+ worker.working_firm = None
+ self.a_lst_firm.remove(f)
+ del f
+ new_f = FirmAgent(self, self.p.is_RH_ratio >= uniform(0, 1), self.p.is_FH_ratio >= uniform(0, 1))
+ self.a_lst_firm.append(new_f)
else:
if f.s_profit < 0:
- if f.s_IsFH:
- # 第一种方式,末位淘汰制,淘汰所有员工中生产价值最低的
- f.l_junior_workers.sort(key=lambda x: x['s_yield'], reverse=True)
- for work in f.l_junior_workers:
- # f.l_junior_workers.sort(key=lambda x: x['s_yield'], reverse=True)
- if work == f.l_junior_workers[-1]:
- work.s_is_hired = False
- else:
- # 第二种方式,末位淘汰制,淘汰所有员工中单位产值(产值/工资)价值最低的
- f.l_all_w = f.l_junior_workers + f.l_senior_workers
- for work in f.l_all_w:
- work.unit_yield_salary = work.s_yield * 10000 / work.s_salary
- f.l_all_w.sort(key=lambda x: x['unit_yield_salary'], reverse=True)
- if work == f.l_all_w[-1]:
- work.s_is_hired = False
- # for f in self.a_lst_firm:
- # if f.s_profit < 0: # TODO
- # n_bankrupt_firms += 1
- # for work in f.l_senior_workers:
- # work.s_is_hired = False
- # for work in f.l_junior_workers:
- # work.s_is_hired = False
- # self.a_lst_firm.remove(f)
- # del f
- # if n_bankrupt_firms > 0:
- # for _ in range(n_bankrupt_firms):
- # f = FirmAgent(self, self.p.is_RH_ratio >= uniform(0, 1))
- # self.a_lst_firm.append(f)
+ f.l_all_w = f.l_junior_workers + f.l_senior_workers
+ min_unit_yield_salary, worst_worker = float('inf'), None
+ for worker in f.l_all_w:
+ unit_yield_salary = worker.s_yield if f.s_IsFH else worker.s_yield * 10000 / worker.s_salary
+ if unit_yield_salary < min_unit_yield_salary:
+ min_unit_yield_salary = unit_yield_salary
+ worst_worker = worker
+ worst_worker.s_is_hired = False
+ worst_worker.working_firm = None
assert len(self.a_lst_firm) == self.n_firm, \
f'current num firm {len(self.a_lst_firm)} != expected num firm {self.n_firm}'
-
def provide_lst_random_firms(self, the_worker: WorkerAgent):
- '''选择企业数量 = 企业总数*百分比
+ """
+ 选择企业数量 = 企业总数*百分比
选择企业的列表 = 随机选择的企业的个数
如果员工处于被雇佣的状态:
如果员工工作的企业在随机选定的企业列表中
@@ -167,7 +151,7 @@ class Env(ap.Model):
返回值:移除后,再重新选择随机选择企业
否则:
返回值:选择企业列表
- '''
+ """
n_select_firms = int(self.percent_search * self.n_firm)
a_lst_select_firms = self.a_lst_firm.random(n_select_firms)
if the_worker.s_is_hired:
@@ -194,6 +178,7 @@ class Env(ap.Model):
@staticmethod
def gini(x):
+ x = [ele for ele in x if ele > 0]
if len(x) == 0:
return 0
if sum(x) == 0:
@@ -223,9 +208,8 @@ if __name__ == '__main__':
parameters = {
'n_worker': 1000,
'n_firm': 100,
- 'percent_search': 0.2,
'alpha': 0.5,
- # 'alpha': ap.Range(0, 1, 0.5),
+ 'percent_search': 0.2,
'is_RH_ratio': 0.5,
'is_FH_ratio': 0.5,
}
@@ -235,4 +219,3 @@ if __name__ == '__main__':
exp = ap.Experiment(Env, sample, iterations=10, record=True)
results = exp.run()
results['variables']['Env'].to_excel('env_data.xlsx', engine='openpyxl')
-
diff --git a/env_data.xlsx b/env_data.xlsx
index f6a454f..b6a9cb6 100644
Binary files a/env_data.xlsx and b/env_data.xlsx differ
diff --git a/firm.py b/firm.py
index ec9d2a9..baeb0db 100644
--- a/firm.py
+++ b/firm.py
@@ -1,46 +1,42 @@
import math
-from typing import Union, Any
+# from typing import Union, Any
import agentpy as ap
from random import uniform, randint
-from typing import TYPE_CHECKING
+# from typing import TYPE_CHECKING
-import numpy as np
+# import numpy as np
-if TYPE_CHECKING:
- from worker import WorkerAgent
+# if TYPE_CHECKING:
+# from worker import WorkerAgent
class FirmAgent(ap.Agent):
c_incentive: float
s_IsRH: bool
s_IsFH: bool
- s_avg_senior_yield: float
- s_avg_junior_yield: float
- s_a_yield: float
+ s_avg_senior_yield: float # updated in self.update_yields
+ s_avg_junior_yield: float # updated in self.update_yields
+ s_a_yield: float # updated in self.update_yields
# s_salary: float
initial_f_salary: float
- s_revenue: float
- s_profit: float
- s_value: float
- firing_worker: 'WorkerAgent'
- l_senior_workers: list
- l_junior_workers: list
- l_applied_workers: list
+ s_revenue: float # updated in env.provide_logit_share
+ s_profit: float # updated in self.update_s_profit
+ s_value: float # updated in self.update_s_profit
+ # firing_worker: 'WorkerAgent'
+ l_senior_workers: list # updated in self.update_two_worker_list
+ l_junior_workers: list # updated in self.update_two_worker_list
+ l_applied_workers: list # updated in self.apply, self.empty_apply
- # def __init__(self, model, *args, **kwargs):
- # super().__init__(model, args, kwargs)
- # self.l_all_workers = None
-
- def setup(self, is_RH, is_FH):
+ def setup(self, is_rh, is_fh):
self.c_incentive = uniform(0, 1)
# self.s_profit = randint(10, 20)
self.l_senior_workers, self.l_junior_workers = [], []
- self.l_all_workers = []
+ # self.l_all_workers = []
self.l_applied_workers = []
- self.s_IsRH = is_RH
- self.s_IsFH = is_FH
+ self.s_IsRH = is_rh
+ self.s_IsFH = is_fh
self.initial_f_salary = randint(8000, 10000)
self.s_profit = 0
self.s_value = 0
@@ -52,13 +48,13 @@ class FirmAgent(ap.Agent):
self.l_applied_workers = []
def select_worker(self):
- '''
+ """
企业找到最想招聘的员工
:return:
- '''
+ """
n_workers = len(self.l_applied_workers)
if n_workers > 0:
- selected_worker = None
+ # selected_worker = None
if n_workers > 1:
# 对员工产出进行排队和比较
# 先判断是什么选择方式
@@ -70,35 +66,21 @@ class FirmAgent(ap.Agent):
best_worker = the_worker
selected_worker = best_worker
else:
- # selected_worker = self.l_applied_workers[0] # TODO
+ # selected_worker = self.l_applied_workers[0]
# 加入worker进入到某个企业,企业更新了自己的利润,利润差值作为该名员工能带来的单位利润,排序利润
# 但是代码中对于员工产出是(0,1)值,需要先更新员工所在列表,然后更新企业产出、利润、工资总额,再用假设利润-上期利润
# 问题是,当期的估算不能考虑到有员工会在下一期离指的问题,或许考虑换成?max_单位产出成本?
- max_unit_yield_salary, p_salary, best_worker= 0.0,0.0, None
+ max_unit_yield_salary, p_salary, best_worker = 0.0, 0.0, None
for the_worker in self.l_applied_workers:
if the_worker.s_salary == 0:
- the_worker.p_salary = self.initial_f_salary
+ p_salary = self.initial_f_salary
else:
- the_worker.p_salary = the_worker.s_salary*(1+self.c_incentive)
- the_worker.unit_yield_salary = the_worker.s_yield * 10000 / the_worker.p_salary
- if the_worker.unit_yield_salary > max_unit_yield_salary:
- max_unit_yield_salary = the_worker.unit_yield_salary
+ p_salary = the_worker.s_salary * (1 + self.c_incentive)
+ unit_yield_salary = the_worker.s_yield * 10000 / p_salary
+ if unit_yield_salary > max_unit_yield_salary:
+ max_unit_yield_salary = unit_yield_salary
best_worker = the_worker
selected_worker = best_worker
- # print(f'{self}: my best firm is {best_firm} from {n_firms} firms with utility {max_utility}')
- # return best_worker
- # 当企业是想要利用产出最高的员工时,从申请的员工中选出产出最高的员工
- # if self.s_IsRH :
- # # 计算该名员工的工资水平: 原有工资水平* (1+incentive)
- # # bw_salary = self.best_worker.salary()
- #
- # # 将该名员工的产出与公司原有员工的产出进行对比,如果高于senior列表中的最后一名的产出,就进入senior_list, 否则进入junior_list
- # self.l_senior_workers.append(best_worker)
- # else:
- # self.l_junior_workers.append(best_worker)
- # # best_worker.apply(self)
- # else:
- # # 计算由于改名员工下一期的薪资总数(根据薪资函数更新)以及企业下一期的利润的差值,并选出最大值
else:
selected_worker = self.l_applied_workers[0]
selected_worker.update_working_firm_is_hired(self)
@@ -106,7 +88,7 @@ class FirmAgent(ap.Agent):
def update_two_worker_list(self, new_worker):
lst_all_worker = self.l_senior_workers + self.l_junior_workers + [new_worker]
- lst_all_worker.sort(key=lambda x: x['s_yield'], reverse=True) # from highest yield to lowest
+ lst_all_worker.sort(key=lambda x: x['s_yield'], reverse=True) # from the highest yield to lowest
n_all_worker = len(lst_all_worker)
# 向上取整数值
n_senior_worker = math.ceil(n_all_worker * 0.2)
@@ -142,9 +124,9 @@ class FirmAgent(ap.Agent):
self.s_a_yield = 0.8 * self.s_avg_senior_yield + 0.2 * self.s_avg_junior_yield
def get_sum_salary(self):
- '''
+ """
计算某公司整体的薪金水平
- '''
+ """
l_all_workers = self.l_senior_workers + self.l_junior_workers
sum_salary = 0.0
for the_worker in l_all_workers:
@@ -155,5 +137,5 @@ class FirmAgent(ap.Agent):
self.s_profit = self.s_revenue - self.get_sum_salary()
self.s_value += self.s_profit
- def step(self):
- pass
+ # def step(self):
+ # pass
diff --git a/main.py b/main.py
deleted file mode 100644
index bf8b9e5..0000000
--- a/main.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# This is a sample Python script.
-
-# Press Shift+F10 to execute it or replace it with your code.
-# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.
-
-
-def print_hi(name):
- # Use a breakpoint in the code line below to debug your script.
- print(f'Hi, {name}') # Press Ctrl+F8 to toggle the breakpoint.
-
-
-# Press the green button in the gutter to run the script.
-if __name__ == '__main__':
- print_hi('PyCharm')
-
-# See PyCharm help at https://www.jetbrains.com/help/pycharm/
diff --git a/oa25.txt b/oa25.txt
new file mode 100644
index 0000000..99a1ab8
--- /dev/null
+++ b/oa25.txt
@@ -0,0 +1,25 @@
+000000
+011234
+022341
+033412
+044123
+101111
+112403
+124032
+130324
+143240
+202222
+214310
+223104
+231043
+240431
+303333
+310142
+321420
+334201
+342014
+404444
+413021
+420213
+432130
+441302
\ No newline at end of file
diff --git a/out_f_avg_profit.pdf b/out_f_avg_profit.pdf
new file mode 100644
index 0000000..ef20771
Binary files /dev/null and b/out_f_avg_profit.pdf differ
diff --git a/out_f_gini_profit.pdf b/out_f_gini_profit.pdf
new file mode 100644
index 0000000..c50d90a
Binary files /dev/null and b/out_f_gini_profit.pdf differ
diff --git a/out_w_avg_salary.pdf b/out_w_avg_salary.pdf
new file mode 100644
index 0000000..5946d3c
Binary files /dev/null and b/out_w_avg_salary.pdf differ
diff --git a/out_w_gini_salary.pdf b/out_w_gini_salary.pdf
new file mode 100644
index 0000000..6bcc439
Binary files /dev/null and b/out_w_gini_salary.pdf differ
diff --git a/out_w_percent_hired.pdf b/out_w_percent_hired.pdf
new file mode 100644
index 0000000..43ec28c
Binary files /dev/null and b/out_w_percent_hired.pdf differ
diff --git a/worker.py b/worker.py
index 1e68677..fc079e7 100644
--- a/worker.py
+++ b/worker.py
@@ -12,43 +12,33 @@ if TYPE_CHECKING:
class WorkerAgent(ap.Agent):
- select_firm: object
- c_effort: float
- s_is_hired: bool
+ # select_firm: object
+ c_effort: float # used in self.update_yield
+ s_is_hired: bool # updated in self.update_working_firm_is_hired, env.create_and_destroy_bankrupt_firms
# c_work_months: int
- s_work_duration: int
- working_firm: 'FirmAgent'
- s_salary: float
- s_yield: float
+ s_work_duration: int # updated in self.update_wd_by_is_hired
+ working_firm: 'FirmAgent' # updated in self.update_working_firm_is_hired, env.create_and_destroy_bankrupt_firms
+ s_salary: float # updated in self.update_salary
+ s_yield: float # updated in self.update_yield
# s_w_applied: bool
c_alpha: float
def setup(self, alpha):
- # super().__init__(unique_id, model)
- # self.num_workers = 10000
self.c_effort = uniform(0, 1)
- # self.c_work_months = randint(0, 60)
self.s_is_hired = False
- self.s_work_duration = randint(0, 60)
+ self.s_work_duration = randint(30, 60)
self.c_alpha = alpha
self.update_yield()
self.s_salary = 0
- # return
-
- # def A_Utility(self, c_w_weight=0.5):
- # a = np.exp(FirmAgent.c_f_incentive, c_w_weight)
- # b = np.exp(FirmAgent.s_f_profit/max(FirmAgent.s_f_profit), 1-c_w_weight)
- # self.select_firm = a * b
-
def select_firm(self):
- '''
+ """
挑选出来的企业列表
数量:列表的长度
- '''
+ """
lst_firms = self.model.provide_lst_random_firms(self)
- n_firms = len(lst_firms)
+ # n_firms = len(lst_firms)
# find the max incentive and profit among all firms
max_incentive, max_value = 0, 0
for f in lst_firms:
@@ -61,22 +51,14 @@ class WorkerAgent(ap.Agent):
return random.choice(lst_firms)
max_utility, best_firm = 0, None
for f in lst_firms:
- if self.s_salary < f.s_profit * 1 / 10:
+ if self.s_salary < f.s_profit / 10:
u = math.pow(f.c_incentive / max_incentive, self.c_alpha) * math.pow(f.s_value / max_value,
- 1 - self.c_alpha)
+ 1 - self.c_alpha)
if u > max_utility:
max_utility = u
best_firm = f
- # if self.s_salary < best_firm.s_profit * 5 / 100:
best_firm.apply(self)
-
- # print(f'{self}: my best firm is {best_firm} from {n_firms} firms with utility {max_utility}')
- # 选出能够给自己带来最好的效用的企业,并输出/返回
- # best_firm.apply(self)
- # return best_firm
- # self.update_wd_by_is_hired()
-
def update_wd_by_is_hired(self):
if self.s_is_hired:
self.s_work_duration += 1
@@ -84,22 +66,10 @@ class WorkerAgent(ap.Agent):
self.update_salary(self.working_firm)
def update_salary(self, the_firm: 'FirmAgent'):
-
if self.s_salary == 0:
self.s_salary = the_firm.initial_f_salary
- pass
else:
- if self.s_salary <= the_firm.s_profit*1/10:
- if self.s_salary * (1 + the_firm.c_incentive) <= the_firm.s_profit*1/10:
- self.s_salary = self.s_salary * (1 + the_firm.c_incentive)
- pass
- else:
- self.s_salary = the_firm.s_profit*1/10
- pass
- pass
- else:
- self.s_salary = the_firm.s_profit*1/10
-
+ self.s_salary = max(min(self.s_salary * (1 + the_firm.c_incentive), the_firm.s_profit / 10), self.s_salary)
def update_yield(self):
self.s_yield = 2 / (1 + math.exp(-0.01 * self.s_work_duration * self.c_effort)) - 1
@@ -108,9 +78,3 @@ class WorkerAgent(ap.Agent):
self.s_is_hired = True
self.working_firm = f
self.update_wd_by_is_hired()
-
- def step(self):
- self.update_wd_by_is_hired()
- '''
- 是否更换公司成功的状态转换?
- '''