Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A model and simulation of a human population

NotificationsYou must be signed in to change notification settings

billstam12/model-simulation-population

Repository files navigation

In what level does inheritance affect the capital distribution of a population?

Find out with the help of Python

Project summary

I theorized that the biggest reason this happened is cause of "old-money". This means that people that have accumulated wealth over the years can pass it over to their children and make heavy investments in their future, subsidizing in the process the future opportunities of those that are not this fortunate. If you look around you (in your university circles or the internet), you can notice that those that are educated in the greatest universities come from families with established wealth. This is mostly due to the fact that colleges have adopted business model and prefer money over bright students (or prefer money more than a poor bright kid, I am not implying that wealthy kids are not smart). This increases the opportunities of wealthy families keeping their wealth in the future while decreasing the opportunities of poorer families to get richer and "make it".

For this reason, I created a model based on real world data that simulates a N people population each having a set of characteristics and then i did what computers do best and simulated this population through time to see if inequality will change if we let people inherit the money of their parents. Inheritance has a lot more to do with the money one's parents have while they are alive and lot less while they are dead but in this way we can still get notable results while still staying true to the reality.

Footnote

The results of both the model and the simulation follow in the lines of code below. I have to be clear that this project was made for fun and for me to try to test my Python, statistics and R skills while finding out something I was really curious about. For this reason, I INSIST that you do take what is described with a big grain of salt as it is only a model of society and does not try to replicate every single aspect of reality. In the future I hope I improve on both the model and the simulation, adding more features and making it as close to reality as I can.

Person stats model

Creating a python module with functions that statistically calculate the following variables of a person

**Sex,Age,Social Class,Income,Marital Status,Capital,Children Status**

To achieve this I usedobject-oriented programming to create aPopulation comprised of objects of the classPerson.

The python code for this class is given in the following cell. While in the one below it I describe the attributes and methods used in it.

classPerson:def__init__(self,gender,social_class,age,income,capital,marital_status):globalid_countself.id=id_countself.social_class=social_classself.gender=genderself.age=ageself.income=incomeself.husband_wife=0self.children_id= []self.mother_id=0self.father_id=0self.children_status=0self.marital_status=marital_statusself.capital=capitalid_count+=1defget_married(self,id):self.marital_status=1self.husband_wife=iddefassign_child(self,id):self.children_status=1self.children_id.append(id)defassign_parents(self,father_id,mother_id):self.father_id=father_idself.mother_id=mother_iddefset_social_class(self,new_class):self.social_class=new_class#def update_income(self):defupdate_capital(self,costs):self.capital+=self.incomeself.capital-=costsdefincrement_age(self,increment):self.age+=incrementdefpass_capital(self,cap,siblings):self.capital+= (cap/siblings)def__repr__(self):return"<Person ID:%s, Gender:%s, Social Class:%s, Age:%s, Income:%s, Capital:%s, Husband/Wife ID:%s Children: %s Father: %s Mother: %s>"% (self.id,self.gender,self.social_class,self.age,self.income,self.capital,self.husband_wife,self.children_id,self.father_id,self.mother_id)
Variable NameDescription
ID

An identification number that distinguishes
one object instance from another.

Gender

The person's gender, can be male or female.

Age

The person's age is an integer in [0,100]

Social Class

The person's social class is an integer in [1,5]. 
The social classes are based in William Johnson's and
Joseph Hickey's 2005 model for social classes.1

Concretely, we have 5 classes.

  1. The Lower Class (20%)
  2. The Working Class (32%)
  3. The Lower Middle Class (32%)
  4. The Upper Middle Class (15%)
  5. The Upper Class (1%)

 

Income

The yearly income of a person, which depends on his age and gender (Figure 1) and his social class (Figures 2-6). As we can see in Figure 1 the income to age distribution follows a normal Gaussian distribution, which means that a person's income is on it's highest when he is middle aged. Moreover we can see from the data that women's income is lower than that of men.

The data used to create the income distribution's was provided byIPUMS and the tidying of the data was done in R. 

Specifically, I fitted the data in 5 different distributions (Figures 2-6), one for each social class.

Capital

The capital accumulated by each person. It depends on the income and the age of each person. More can be found about the heuristic used, in Charles Farell's book: "Your Money Ratios: 8 Simple Tools for Financial Security"2

 

Husband_wifeVariable that contains the id of the spouse of the individual.
Children_idList that contains the ids of the children of the individual.
Mother_idId of mother.
Father_idId of father.
Children_statusWhether or not the person has a child or more.
Marital_statusWhether or not the person is married.

 

Procedure NameDescription
set_social_class(new_class)  Assigns new class to the individual.
get_married(id)Sets spouse of individual to ID and marital_status to 1.
assign_child(id)Sets children_status to 1 and appends id to children_id list.
assign_parents(father_id, mother_id)Sets the parents' ids.
increment_age(increment)Increments age by a number.
update_capital(cap, siblings)Updates a person's capital after his/her parent has died. It adds it to the existing one after dividing it by the number of children in the family.

Gender

First, to create a person we need to make it a he or she. So we will be taking a random binary probability of thesex being 0 for males and 1 for females.

importnumpyasnpnp.random.seed(1)gender=np.random.randint(2)gender
1

Age

Next we will define that person'sage based on his/her gender and according to the UN's data (http://data.un.org/Data.aspx?d=POP&f=tableCode%3A22)

The age data follows this dataframe:

importpandasaspdages=pd.read_csv("data/ages.csv")ages_df=pd.DataFrame(ages)ages_df
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {    vertical-align: top;}.dataframe thead th {    text-align: right;}
</style>
Country or AreaYearAreaSexAgeRecord TypeReliabilitySource YearValueValue Footnotes
0United States of America2015TotalBoth SexesTotalEstimate - de jureFinal figure, complete2016.0321418820.01,2
1United States of America2015TotalBoth Sexes0Estimate - de jureFinal figure, complete2016.03978038.01,2
2United States of America2015TotalBoth Sexes0 - 4Estimate - de jureFinal figure, complete2016.019907281.01,2
3United States of America2015TotalBoth Sexes1Estimate - de jureFinal figure, complete2016.03968564.01,2
4United States of America2015TotalBoth Sexes1 - 4Estimate - de jureFinal figure, complete2016.015929243.01,2
5United States of America2015TotalBoth Sexes2Estimate - de jureFinal figure, complete2016.03966583.01,2
6United States of America2015TotalBoth Sexes3Estimate - de jureFinal figure, complete2016.03974061.01,2
7United States of America2015TotalBoth Sexes4Estimate - de jureFinal figure, complete2016.04020035.01,2
8United States of America2015TotalBoth Sexes5Estimate - de jureFinal figure, complete2016.04018158.01,2
9United States of America2015TotalBoth Sexes5 - 9Estimate - de jureFinal figure, complete2016.020487176.01,2
10United States of America2015TotalBoth Sexes6Estimate - de jureFinal figure, complete2016.04019207.01,2
11United States of America2015TotalBoth Sexes7Estimate - de jureFinal figure, complete2016.04148360.01,2
12United States of America2015TotalBoth Sexes8Estimate - de jureFinal figure, complete2016.04167887.01,2
13United States of America2015TotalBoth Sexes9Estimate - de jureFinal figure, complete2016.04133564.01,2
14United States of America2015TotalBoth Sexes10Estimate - de jureFinal figure, complete2016.04121289.01,2
15United States of America2015TotalBoth Sexes10 - 14Estimate - de jureFinal figure, complete2016.020622330.01,2
16United States of America2015TotalBoth Sexes11Estimate - de jureFinal figure, complete2016.04130328.01,2
17United States of America2015TotalBoth Sexes12Estimate - de jureFinal figure, complete2016.04101021.01,2
18United States of America2015TotalBoth Sexes13Estimate - de jureFinal figure, complete2016.04084306.01,2
19United States of America2015TotalBoth Sexes14Estimate - de jureFinal figure, complete2016.04185386.01,2
20United States of America2015TotalBoth Sexes15Estimate - de jureFinal figure, complete2016.04249742.01,2
21United States of America2015TotalBoth Sexes15 - 19Estimate - de jureFinal figure, complete2016.021108903.01,2
22United States of America2015TotalBoth Sexes16Estimate - de jureFinal figure, complete2016.04184296.01,2
23United States of America2015TotalBoth Sexes17Estimate - de jureFinal figure, complete2016.04194286.01,2
24United States of America2015TotalBoth Sexes18Estimate - de jureFinal figure, complete2016.04217995.01,2
25United States of America2015TotalBoth Sexes19Estimate - de jureFinal figure, complete2016.04262584.01,2
26United States of America2015TotalBoth Sexes20Estimate - de jureFinal figure, complete2016.04363440.01,2
27United States of America2015TotalBoth Sexes20 - 24Estimate - de jureFinal figure, complete2016.022739313.01,2
28United States of America2015TotalBoth Sexes21Estimate - de jureFinal figure, complete2016.04456790.01,2
29United States of America2015TotalBoth Sexes22Estimate - de jureFinal figure, complete2016.04529472.01,2
.................................
342United States of America2015TotalFemale78Estimate - de jureFinal figure, complete2016.0840960.01,2
343United States of America2015TotalFemale79Estimate - de jureFinal figure, complete2016.0803984.01,2
344United States of America2015TotalFemale80Estimate - de jureFinal figure, complete2016.0772956.01,2
345United States of America2015TotalFemale80 - 84Estimate - de jureFinal figure, complete2016.03386676.01,2
346United States of America2015TotalFemale81Estimate - de jureFinal figure, complete2016.0693056.01,2
347United States of America2015TotalFemale82Estimate - de jureFinal figure, complete2016.0671319.01,2
348United States of America2015TotalFemale83Estimate - de jureFinal figure, complete2016.0640387.01,2
349United States of America2015TotalFemale84Estimate - de jureFinal figure, complete2016.0608958.01,2
350United States of America2015TotalFemale85Estimate - de jureFinal figure, complete2016.0582641.01,2
351United States of America2015TotalFemale85 - 89Estimate - de jureFinal figure, complete2016.02422101.01,2
352United States of America2015TotalFemale86Estimate - de jureFinal figure, complete2016.0522563.01,2
353United States of America2015TotalFemale87Estimate - de jureFinal figure, complete2016.0487256.01,2
354United States of America2015TotalFemale88Estimate - de jureFinal figure, complete2016.0440879.01,2
355United States of America2015TotalFemale89Estimate - de jureFinal figure, complete2016.0388762.01,2
356United States of America2015TotalFemale90Estimate - de jureFinal figure, complete2016.0347555.01,2
357United States of America2015TotalFemale90 - 94Estimate - de jureFinal figure, complete2016.01261957.01,2
358United States of America2015TotalFemale91Estimate - de jureFinal figure, complete2016.0297448.01,2
359United States of America2015TotalFemale92Estimate - de jureFinal figure, complete2016.0246825.01,2
360United States of America2015TotalFemale93Estimate - de jureFinal figure, complete2016.0205146.01,2
361United States of America2015TotalFemale94Estimate - de jureFinal figure, complete2016.0164983.01,2
362United States of America2015TotalFemale95Estimate - de jureFinal figure, complete2016.0125996.01,2
363United States of America2015TotalFemale95 - 99Estimate - de jureFinal figure, complete2016.0366919.01,2
364United States of America2015TotalFemale96Estimate - de jureFinal figure, complete2016.090302.01,2
365United States of America2015TotalFemale97Estimate - de jureFinal figure, complete2016.069285.01,2
366United States of America2015TotalFemale98Estimate - de jureFinal figure, complete2016.047272.01,2
367United States of America2015TotalFemale99Estimate - de jureFinal figure, complete2016.034064.01,2
368United States of America2015TotalFemale100 +Estimate - de jureFinal figure, complete2016.061886.01,2
369footnoteSeqIDFootnoteNaNNaNNaNNaNNaNNaNNaNNaN
3701Excluding U.S. Armed Forces overseas and civil...NaNNaNNaNNaNNaNNaNNaNNaN
3712Postcensal estimates.NaNNaNNaNNaNNaNNaNNaNNaN

372 rows × 10 columns

The Age column contains data in bins of 5, but in theget_age_percents() function, we convert the bins to bins of 5 and then calculate theprobability density function of the data manually.

defget_age_percents():ages=pd.read_csv("data/ages.csv")ages_df=pd.DataFrame(ages)starting_columns= ["Total","0 - 4","5 - 9","10 - 14","15 - 19","20 - 24","25 - 29","30 - 34","35 - 39","40 - 44","45 - 49","50 - 54","55 - 59","60 - 64","65 - 69","70 - 74","75 - 79","80 - 84","85 - 89","90 - 94","95 - 99","100 +"]final_columns= ["Total","0 - 9","10 - 19","20 - 29","30 - 39","40 - 49","50 - 59","60 - 69","70 - 79","80 - 89","90 - 99","100 +"]# ages_1 = ages_df["Value"].loc[(ages_df["Age"].isin(starting_columns[5:7])) & (ages_df["Sex"] == "Male")]# print ages_1ages_m= []ages_f= []t=0foriinrange(1,11):ages_m .append(sum(ages_df["Value"].loc[(ages_df["Age"].isin(starting_columns[i+t:i+t+2]))& (ages_df["Sex"]=="Male")]))ages_f .append(sum(ages_df["Value"].loc[(ages_df["Age"].isin(starting_columns[i+t:i+t+2]))& (ages_df["Sex"]=="Female")]))t=t+1total_m=sum(ages_df["Value"].loc[(ages_df["Age"]=="Total")& (ages_df["Sex"]=="Male")])hundred_m=sum(ages_df["Value"].loc[(ages_df["Age"]=="100 +")& (ages_df["Sex"]=="Male")])total_f=sum(ages_df["Value"].loc[(ages_df["Age"]=="Total")& (ages_df["Sex"]=="Female")])hundred_f=sum(ages_df["Value"].loc[(ages_df["Age"]=="100 +")& (ages_df["Sex"]=="Female")])ages_m .append(hundred_m)ages_f .append(hundred_f)#Get percents of agesimportnumpyasnpages_m=np.array(ages_m)ages_f=np.array(ages_f)ages_m_percent= (ages_m/total_m)*100ages_f_percent= (ages_f/total_f)*100ages_m_percent= ["%.2f"%itemforiteminages_m_percent ]ages_f_percent= ["%.2f"%itemforiteminages_f_percent ]returnages_m_percent,ages_f_percent

When we have the p.d.f of the ages, we will use aget_age function to get a random age based on the gender of the individual like this:

importagesage=ages.get_age(gender)age
8

Social Class

Then we have to find the Social Class of the individual which follows the Thompson, Hickey 2005 model I described in the table above.

Concretely:

importscipy.statsasstsdefget_class():xk=np.arange(5)pk= (0.2,0.32,0.32,0.15,0.01)custm=sts.rv_discrete(name='custm',values=(xk,pk))returncustm.rvs()+1social_class=get_class()social_class
1

Income

I used R and some data collected from IPUMS.org, to achieve my goal.Then I used some R code to divide the data instances to the classes based on the proposed model[1], after I analysed the income to the gender and age of the people as shown in Figure 1.

Figure 1:Age to Income Scatterplot (Blue:Male, Red: Female)

R

With the following R code I divided the data I gathered from IPUMS.org to social classes based on the model proposed by Thompson and Hickey[1].

df<- read.csv(file="cps_00005.csv",header=TRUE,sep=",")#Remove nan, d$INCTOT == 99999999, d$INCTOT == 99999998,df<- na.omit(df)df<-df[!(df$FTOTVAL==99999999|df$FTOTVAL==99999998),]df<-df[!(df$INCTOT==99999999|df$INCTOT==99999998),]df<-df[order(df$FTOTVAL),]#We get the 5 classes. According to William Thompson & Joseph Hickey, 2005we havelc= (floor(.2*nrow(df)))wc= (floor(.52*nrow(df)))lmc= (floor(.84*nrow(df)))umc= (floor(.99*nrow(df)))uc= (floor(.01*nrow(df)))lower_class=df[1:lc,]working_class=df[(lc+1):wc,]lower_middle_class=df[(wc+1):lmc,]upper_middle_class=df[(lmc+1):umc,]upper_class=df[(umc+1):nrow(df),]#print(nrow(lower_class)/nrow(df)*100)  -> 20%#print(nrow(working_class)/nrow(df)*100) -> 32%#print(nrow(lower_middle_class)/nrow(df)*100) -> 32%#print(nrow(upper_middle_class)/nrow(df)*100) -> 15%#print(nrow(upper_class)/nrow(df)*100) -> 1%print(fitdist(lower_class$INCTOT,distr="unif",method="mme"))print(fitdist(working_class$INCTOT,distr="norm",method="mme"))print(fitdist(lower_middle_class$INCTOT,distr="norm",method="mme"))print(fitdist(upper_middle_class$INCTOT,distr="norm",method="mme"))print(fitdist(upper_class$INCTOT,distr="gamma",method="mme"))

Figure 2:Lower Class Distribution fit

 

Figure 3:Working Class Distribution fit

 

Figure 4:Lower Middle Class Distribution fit

 

Figure 5:Upper Middle Class Distribution fit

 

Figure 6:Upper Class Distribution fit

Turns out that the last 5 distributions give good enough results to model a Generation 0 population. To be honest, I tried creating a machine learning model to try and predict the Income, but the nature of the data(Age, social class and sex) didn't help that much in my endeavor. However, the code for the model created can be found in the stats.py under the name get_income2. But when we will simulate the generations, we will have to keep in mind that men tend to have higher incomes than women and that the age-income distribution is a Gaussian

 References:

1.Thompson, W. & Hickey, J. (2005). Society in Focus. Boston, MA: Pearson, Allyn & Bacon; Beeghley, L. (2004). The Structure of Social Stratification in the United States. Boston, MA: Pearson, Allyn & Bacon.

2.Farell, C. (2018). How The Ratios Work « Your Money Ratios. [online] Yourmoneyratios.com. Available at:http://www.yourmoneyratios.com/how-the-ratios-work/ [Accessed 16 Aug. 2018].

 

Python

According to Figures 2-6, I fit each social class' income to the following distributions respectively:

**Lower Class**: Uniform**Working Class**: Normal**Lower Middle Class**: Normal**Upper Middle Class**: Normal**Upper Class**: Gamma

The python function to get the income based on the social class is the following:

*I did not take into account the age or gender of the individual as far as the model goes, in the simulation process later I took this variables into account. The reason for this is that I did not have enough data to make something valuable and that the nominal variables *Gender, Social Class, will hardly provide a good Income prediction in a machine learning algorithm, as the prediction value is nominal. In testing this theory I found out I was right as the maximum correlation i got was about 0.5.

defget_income(social_class):#Got classes from https://en.wikipedia.org/wiki/Household_income_in_the_United_States  Social_Class#lower_class = 1 (14-20%) , working_class =  2 (20 -52%), lower_middle_class = 3 (52-84%), upper_middle_class= 4 (84-99%), upper_class = 5 (99-100%)if(social_class==1):inc=np.random.uniform(-3744.26,15749.78)elif(social_class==2):inc=np.random.normal(15879.603,9528.182)elif(social_class==3):inc=np.random.normal(27564.15,19854.43)elif(social_class==4):inc=np.random.normal(55957.25,48711.24)else:inc=np.random.gamma(1/0.6346247,1/0.000002982905)returninc# ro.r.source("income.R")# ro.r('''source("income.R")''')# inc = ro.globalenv['income']# x = inc(18,2,3)# return xincome=get_income(social_class)if(age<15):income=0income
0

Capital

To compute a person's capital we usedCharles Farell's heuristic[2] (I won't be posting heuristic code as they are quite long and trivial)

importstatscapital=stats.get_capital(age,social_class,income)capital
0.0

We then compute other statistical relevant features as if the person is married or not and if he/she is the number of children they have.

The functions used are get_marital_status(gender, age), get_children_status(mother, father),get_number_of_children are heuristics based on real life data.[3,4,5]

fromfamilyimport*marital_status=family.get_marital_status(gender,age)#1 for yes, 0 for nomarital_status
0

To get the children status we will first have to create the Person object in Python.

person=Person(gender,social_class,age,income,capital,marital_status)printperson
<Person ID:1, Gender:1, Social Class:1, Age:8, Income:0, Capital:0.0, Husband/Wife ID:0 Children: [] Father: 0 Mother: 0>

Generation 0

The model works in the following way.For as long as a people's list calledpopulation does not exceedN, we will be creating people.If a person is married than we will create his/her partner and his/her partner's parents, along with his/her own.Then it runs a probability of the couple having kids and creates kids for them according to a probability and adds all these people in the first Generation of the simulation.

defmodel(N):population= []while(len(population)<N ):# Create a person, if it aged more than 18, run a probability of it being married, else just give his parents# If he/she is create a partner for him/her and give them a child# If it's a male the social class has chances of being lower, females on the other hand, tend to marry upgender=np.random.randint(2)social_class=get_class()age=ages.get_age(gender)marital_status=0partner=0if(age<15):inc=0else:inc=get_income(social_class)cap=get_capital(age,social_class,inc)person=Person(gender,social_class,age,inc,cap,marital_status)#print ( "Created person-id %d" % person.id)marital_status=get_marital_status(gender,age)if(marital_status==1):#Create another human being with different gender, if male then social class is same or lower,#if female marry only to same classpartner=create_partner(person)#Give parents to partnerpartner_mother,partner_father=create_parents(partner)if(partner_mother!=0):partner.mother_id=partner_mother.idpopulation.append(partner_mother)if(partner_father!=0):partner.father_id=partner_father.idpopulation.append(partner_father)#Marry Thempopulation.append(partner)person.get_married(partner.id)partner.get_married(person.id)#Check for and give them Childrenif(person.gender==1):m=personf=partnerelse:m=partnerf=person#m = mother, f = father of childif(get_children_status(m,f)):no_of_children=get_number_of_children(m,f)if(no_of_childrenisNone):no_of_children=1for_inrange(no_of_children):child=create_child(person,partner,1)if (child!=0):partner.assign_child(child.id)person.assign_child(child.id)child.assign_parents(f.id,m.id)population.append(child)mother,father=create_parents(person)population.append(person)if(mother!=0):person.mother_id=mother.idpopulation.append(mother)if(father!=0):person.father_id=father.idpopulation.append(father)returnpopulation

Results

The results of the model for a population of a 1000,2000 and 5000 people, in respect to theclass-capital distribution are the following

importnumpyasnpnp.random.seed(1)population1=model(1000)population2=model(2000)population3=model(5000)
defplot_capital_to_class(population,N):# Check the capital to social class distributioncapital= []total_cap=0class_size= [0]*5class_cap= [0]*5tot_inc=0class_inc= [0]*5forpinpopulation:capital.append(p.capital)total_cap+=p.capitaltot_inc+=p.incomeclass_size[p.social_class-1]+=1class_cap[p.social_class-1]+=p.capitalclass_inc[p.social_class-1]+=p.incomeclass_inc=np.array(class_inc)print"Income:"print  (class_inc/tot_inc)*100class_cap=np.array(class_cap)print"Capital:"arr= (class_cap/total_cap)*100printarrclass_size=np.array(class_size)print"Population:"pop= (class_size/float(N))*100printpopprint"Capital:Population ratio"print (arr/pop)importmatplotlib.pyplotaspltind=np.arange(5)plt.bar(ind,arr,align='center',width=0.5)plt.xticks(ind,("Lower Class","Working Class","Lower Middle Class","Upper Middle Class","Upper class") )plt.ylabel("Capital")plt.title("Capital distribution per social class (Simulation)")plt.tight_layout()plt.ylim(0.0,60.0)plt.show()returncapital
cap1=plot_capital_to_class(population1,1000)cap2=plot_capital_to_class(population2,2000)cap3=plot_capital_to_class(population3,5000)
Income:[ 3.25754056 17.64907108 27.34955917 36.03464325 15.70918595]Capital:[ 2.94931656 14.77192988 27.60128711 35.05683699 19.62062946]Population:[16.9 33.3 31.1 18.   1.4]Capital:Population ratio[ 0.17451577  0.4436015   0.88750119  1.94760205 14.01473533]

png

Income:[ 3.60685866 17.54332042 32.38809354 26.961163   19.50056438]Capital:[ 2.92336124 14.31667082 31.78975533 29.25399279 21.71621981]Population:[17.95 32.5  33.4  14.65  1.55]Capital:Population ratio[ 0.16286135  0.44051295  0.95178908  1.99685958 14.01046439]

png

Income:[ 4.81334394 17.38036787 33.43219905 28.23697775 16.13711139]Capital:[ 3.92188299 14.30665683 32.61451713 29.31294689 19.84399616]Population:[21.52 29.48 33.76 14.1   1.16]Capital:Population ratio[ 0.18224363  0.48530044  0.96606982  2.0789324  17.10689324]

png

As we can see, the upper class despite it's size, has a substantial percentage of the capital of the population, which increases with the increase of the size of the population. This can be further proved by examining the capital to population ratio of each class which is proportionally larger for the upper class.

A good estimator to give also would be the gini coefficient of our population[5],which is defined as:

401e1c01c8d1985a6d2ecee4a8398938db4568b5.svg

To do this we create agini_index function that takes as input a numpy array and returns the single index of capital in our population.

defgini_index(capital):capital=capital.flatten()ifnp.amin(capital)<0:# Values cannot be negative:capital-=np.amin(capital)# Values cannot be 0:capital+=0.0000001# Values must be sorted:capital=np.sort(capital)# Index per array element:index=np.arange(1,capital.shape[0]+1)# Number of array elements:n=capital.shape[0]# Gini coefficient:return ((np.sum((2*index-n-1)*capital))/ (n*np.sum(capital)))printgini_index(np.array(cap1))printgini_index(np.array(cap2))printgini_index(np.array(cap3))
0.196175876285178350.182059035083937060.12080484386107655

These numbers show that the population's we created have diminishing gini indexes as the population get bigger (and thus more representative of reality), making the model pretty unequal

Simulation

Now that we have our unequal population we will simulate the one with 1000 people, to try to check how more unequal it will be in the future, if each dying parent passes his/her capital to his/her children.

The code that will perform the simulation is the following and it is programmed to run for as many years as we want.In each year it will output the number of people in the population as well as the statistics provided before.

defmarriage_query(person,partner):if(partner.marital_status==0):if(partner.gender!=person.gender):if(person.gender==0):#if(partner.age in xrange((person.age/2) + 7, person.age + 8)):if(partner.social_class<=person.social_class):person_marital_status=get_marital_status(person.gender,person.age)partner_marital_status=get_marital_status(partner.gender,partner.age)if((person_marital_status)& (partner_marital_status)):return1else:return0#else:#    return 0else:#if(partner.age in xrange((person.age) , person.age + 21)):person_marital_status=get_marital_status(person.gender,person.age)partner_marital_status=get_marital_status(partner.gender,partner.age)if((person_marital_status)& (partner_marital_status)):return1#    else:#return 0else:return0else:return0# This function updates the people's classes after each iterationdefupdate_class(population):# Sort ascending based on capitalpopulation.sort(key=lambdax:x.capital)# Get classesT=len(population)l=int(0.2*T)w=int(0.32*T)lm=int(0.32*T)um=int(0.15*T)u=int(0.01*T)# Set new social classfori,pinenumerate(population):if(i<=l):p.social_class=1elif(i<=l+w):p.social_class=2elif(i<=l+w+lm):p.social_class=3elif(i<=l+w+lm+um):p.social_class=4else:p.social_class=5returnpopulationdefrun_simulation(population,years):foryearinrange(years):printlen(population)forpinpopulation:if(check_death(p)==0):p.increment_age(1)# TODO:#Create a costs variable from data and initialize that too#Then adjust income and capital according to the already given data?! or make them interact?!#ADJUST Incomeif(p.age==15):p.income=get_income(p.social_class)else:#p.update_income()p.income+=p.income*0.01costs=0p.update_capital(0)#If not married, run probability of him getting get_marriedif(p.marital_status==0):#Find a potential marriage partnerpartners= [partnerforpartnerinpopulationif(marriage_query(p,partner))]if(partners):prtnr=random.choice(partners)prtnr.get_married(p)p.get_married(prtnr)#If married  run probability of giving birthif((p.marital_status==1)):forpersoninpopulation:if(person.id==p.husband_wife):if(person.gender==0):husband=personwife=pelse:wife=personhusband=pchild_status=family.get_children_status(wife,husband)if(child_status==1):child=family.create_child(husband,wife,0)husband.assign_child(child.id)wife.assign_child(child.id)child.assign_parents(husband.id,wife.id)population.append(child)breakelse:#If that person has children, then pass its capital to his/her kidschildren= [childforchildinpopulationif (child.idinp.children_id) ]no_of_children=len(children)forcinchildren:c.pass_capital(p.capital,no_of_children)population= [personforpersoninpopulationifp.id!=person.id]population=update_class(population)cap=plot_capital_to_class(population,len(population))printgini_index(np.array(cap))
run_simulation(population1,20)
10071462188122772650304334043723402843794688498252635543582060936358662168567104Income:[ 1.96802942 20.26639224 34.34630328 30.3449897  13.07428536]Capital:[-2.49912499  9.9415439  33.48622741 41.4580972  17.61325647]Population:[20.01363327 31.99727335 31.99727335 14.99659168  0.99522836]Capital:Population ratio[-0.12487113  0.31069972  1.04653378  2.7645013  17.69770359]

png

0.18507320299921423

What we see from the above graph is that with the passage of time if capital keeps being passed from parents to children, then the distribution of capital between the social classes, is getting even more unequal with the top classes getting most of the spoils while the lower ones are almost non-existent.

Can we do better?

Next goal of this simulation is to remove inheritance from the equation and see if the inequality persists.

About

A model and simulation of a human population

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp