文章目录

  • 1.DCM介绍
  • 2.项目背景
  • 3.数据预处理
    • 3.1变量的分类
    • 3.2长宽数据转换
    • 3.3数据初筛
  • 4.模型构建
    • 4.1单因素分析
      • 卡方分析
      • MNL模型单因素回归分析
      • 结果汇总
    • 4.2共线性检测
    • 4.3哑变量处理
    • 4.4模型训练
  • 5.结果

1.DCM介绍

离散选择模型DCM(Discrete Choice Model)是一类模型族,这个名字听起来有些陌生,但其包含的模型却是我们熟知的LR(Logistics Regression,逻辑回归模型),以及其变种MNL(MultiNomial Logit,多项Logit模型)和NL(Nested Logit,嵌套Logit模型)。
DCM可用于经济学中的选择问题,是分析“从有限互斥选项集中进行单项选择”的计量模型。主要包括五个部分:决策者(决策者属性)、备选项集合、备选项属性、决策准则和选择结果,数学表达式如下:
选择结果=F(决策者,备选项集合,备选项属性)选择结果=F(决策者,备选项集合,备选项属性)选择结果=F(决策者,备选项集合,备选项属性)
FFF是决策准则,即效用最大化准则。模型最终实现的功能是在给定决策者、备选项集合、备选项属性后,基于效用最大化准则,得到选择结果。

消费者内心的满足感可以用经济学中的“效用”来表示,理性消费者面对一系列商品时,会选择效用最大的商品。

2.项目背景

数据集来自于biogeme官网数据集中的Airline Itinerary数据,这里是数据介绍。总结来说,波音公司进行了一个调查,给乘客提供三个备选项:1.直飞,2.中转但同一公司,3.中转但非同一公司。调查涉及各个备选项的飞行时间、价格、空间等备选项属性,以及乘客本身的收入、受教育程度、出行人数等决策者属性。
我们要做的流程:设计DCM效用函数→\rightarrow→用真实数据进行回归→\rightarrow→修改DCM效用函数→\rightarrow→对结果进行解读。

3.数据预处理

3.1变量的分类

原数据信息如下:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3609 entries, 0 to 3608
Data columns (total 56 columns):#   Column                             Non-Null Count  Dtype
---  ------                             --------------  -----  0   SubjectId                          3609 non-null   int64  1   OriginGMT                          3609 non-null   int64  2   DestinationGMT                     3609 non-null   int64  3   Direction                          3609 non-null   int64  4   q02_TripPurpose                    3609 non-null   int64  5   q03_WhoPays                        3609 non-null   int64  6   q11_DepartureOrArrivalIsImportant  3609 non-null   int64  7   q12_IdealDepTime                   3609 non-null   int64  8   q13_IdealArrTime                   3609 non-null   int64  9   q14_PartySize                      3609 non-null   int64  10  q15_Age                            3609 non-null   float6411  q16_Income                         3609 non-null   int64  12  Cont_Income                        3609 non-null   float6413  q17_Gender                         3609 non-null   int64  14  q19_Occupation                     3609 non-null   int64  15  q20_Education                      3609 non-null   int64  16  AirlineFirstFlight_1               3609 non-null   int64  17  AirlineFirstFlight_2               3609 non-null   int64  18  AirlineFirstFlight_3               3609 non-null   int64  19  AirlineSecondFlight_1              3609 non-null   int64  20  AirlineSecondFlight_2              3609 non-null   int64  21  AirlineSecondFlight_3              3609 non-null   int64  22  AirplaneFirstFlight_1              3609 non-null   int64  23  AirplaneFirstFlight_2              3609 non-null   int64  24  AirplaneFirstFlight_3              3609 non-null   int64  25  AirplaneSecondFlight_1             3609 non-null   int64  26  AirplaneSecondFlight_2             3609 non-null   int64  27  AirplaneSecondFlight_3             3609 non-null   int64  28  DepartureTimeHours_1               3609 non-null   float6429  DepartureTimeHours_2               3609 non-null   float6430  DepartureTimeHours_3               3609 non-null   float6431  DepartureTimeMins_1                3609 non-null   int64  32  DepartureTimeMins_2                3609 non-null   int64  33  DepartureTimeMins_3                3609 non-null   int64  34  ArrivalTimeHours_1                 3609 non-null   float6435  ArrivalTimeHours_2                 3609 non-null   float6436  ArrivalTimeHours_3                 3609 non-null   float6437  ArrivalTimeMins_1                  3609 non-null   int64  38  ArrivalTimeMins_2                  3609 non-null   int64  39  ArrivalTimeMins_3                  3609 non-null   int64  40  FlyingTimeHours_1                  3609 non-null   float6441  FlyingTimeHours_2                  3609 non-null   float6442  FlyingTimeHours_3                  3609 non-null   float6443  TripTimeHours_1                    3609 non-null   float6444  TripTimeHours_2                    3609 non-null   float6445  TripTimeHours_3                    3609 non-null   float6446  Legroom_1                          3609 non-null   int64  47  Legroom_2                          3609 non-null   int64  48  Legroom_3                          3609 non-null   int64  49  Fare_1                             3609 non-null   int64  50  Fare_2                             3609 non-null   int64  51  Fare_3                             3609 non-null   int64  52  BestAlternative_1                  3609 non-null   int64  53  BestAlternative_2                  3609 non-null   int64  54  BestAlternative_3                  3609 non-null   int64  55  TripPurpose                        3609 non-null   int64
dtypes: float64(14), int64(42)
memory usage: 1.5 MB

第0项是id,第1-15包含了决策者的个人信息,为决策者变量;16-51为备选项属性,后面的1、2、3区分三个选项;52-54为0-1型数据,代表是否选择该项。

3.2长宽数据转换

常用的机器学习模型大多使用宽数据,但Logit使用的是长数据,在这里使用pylogit.convert_wide_to_long方法进行宽转长的操作。

#决策者变量
ind_var=['OriginGMT', 'DestinationGMT', 'Direction', 'q02_TripPurpose','q03_WhoPays', 'q11_DepartureOrArrivalIsImportant', 'q12_IdealDepTime','q13_IdealArrTime', 'q14_PartySize', 'q15_Age', 'q16_Income','Cont_Income', 'q17_Gender', 'q19_Occupation', 'q20_Education','TripPurpose']
#备选项属性变量
spv=['AirlineFirstFlight','AirlineSecondFlight','AirplaneFirstFlight','AirplaneSecondFlight','DepartureTimeHours','DepartureTimeMins','ArrivalTimeHours','ArrivalTimeMins','FlyingTimeHours','TripTimeHours','Legroom','Fare']#备选项对应的字段
alt_varying_var={}
for n in spv:dic={}for i in 1,2,3:dic[i]=n+'_'+str(i)alt_varying_var[n]=dic#选项可用性
avail_var={1:'avil_1',2:'avil_2',3:'avil_3'}#备选项id
alt_id='ALT_ID'#观测id
obs_id='OBS_ID'
airline[obs_id]=np.arange(airline.shape[0],dtype=int)+1#选择结果
choice_id='choice'
long_df=pl.convert_wide_to_long(airline,ind_var,alt_varying_var,avail_var,obs_id,choice_id,new_alt_id_name=alt_id)

3.3数据初筛

当数据特征多且杂时,要在一开始对数据进行初步筛选,这一步要结合数据的信息与个人经验:

  • 删掉空值过多的特征。
  • 信息高度重合的特征只保留一个。
  • 删掉与目标无关联的特征。

除此之外要尽可能保留特征,被删掉的特征也不是被判了“死刑”,后续视情况决定是否恢复。可以用df.info()函数查看数据的格式及空值情况。
最后经过长宽转化、数据清洗及初筛后保留下的结果:

OBS_ID ALT_ID Direction q02_TripPurpose q03_WhoPays q11_DepartureOrArrivalIsImportant q14_PartySize q15_Age q16_Income q20_Education q17_Gender q19_Occupation FlyingTimeHours DepartureTimeHours ArrivalTimeHours TripTimeHours Legroom Fare choice
2 1 1 2 1 2 1 3.5 10 6 1 1 2.53333 7.5 10.0333 2.53333 2 315 0
2 2 1 2 1 2 1 3.5 10 6 1 1 3.03333 15 18.5333 3.53333 2 315 1
2 3 1 2 1 2 1 3.5 10 6 1 1 3.03333 12 16.5333 4.53333 3 350 0
3 1 1 2 1 1 2 3.5 6 6 1 2 2.53333 7.5 10.0333 2.53333 3 195 0
3 2 1 2 1 1 2 3.5 6 6 1 2 3.03333 9 13.5333 4.53333 1 160 1
3 3 1 2 1 1 2 3.5 6 6 1 2 3.03333 12 17.0333 5.03333 4 170 0
4 1 1 2 3 1 2 6 12 6 2 2 0.966667 18 18.9667 0.966667 3 135 0
4 2 1 2 3 1 2 6 12 6 2 2 1.46667 18 21.4667 3.46667 3 125 0
4 3 1 2 3 1 2 6 12 6 2 2 1.46667 12 13.9667 1.96667 1 140 1
6 1 2 4 1 1 1 3.5 7 5 2 5 4.56667 7 14.5667 4.56667 3 400 1
6 2 2 4 1 1 1 3.5 7 5 2 5 5.06667 13 22.0667 6.06667 1 330 0

4.模型构建

4.1单因素分析

简单来说,单因素分析方法就是检验分析一个因素与另外一个因素的关联的分析方法, 单因素分析只观察两个因素间的关联,不代表因果关系 。这里应用单因素分析对特征进行进一步筛选。

方法 应用数据类型 例子
卡方检验 定类和定类 性别和是否戴眼镜之间的关系
t检验、ANOVA 定类和定量 性别和身高的关系
pearson相关系数 定量和定量 身高和体重的关系

除上述方法外,还可以使用单因素回归分析,不同于单因素分析利用传统统计学手段,单因素回归分析是将单个特征和待拟合项纳入我们的回归模型,其效果作为我们筛选特征的依据。
在我们的例子中,因变量是定类的数据,所以选择卡方检验来分析定类的特征,对定量的特征我们直接代入Logit模型进行单因素回归分析。注意这里使用的是宽数据而非最终带入模型的长数据

卡方分析

##卡方分析
from scipy.stats import chi2_contingency
import statsmodels.api as sm
from sklearn import metrics
def Disc_var_test(df,col,target):p_value=[]for n in col:crosstab=pd.crosstab(df[n],df[target])p=chi2_contingency(crosstab)[1]p_value.append(p)df=pd.DataFrame({'features':col,'p_value':p_value})return dfcol=['Direction','q02_TripPurpose','q03_WhoPays','q11_DepartureOrArrivalIsImportant','q17_Gender','q19_Occupation']
Disc_var_test(df_wide,col,'choice')

MNL模型单因素回归分析

import pandas
import statsmodels.api as st#利用MNL模型单因素回归分析
def Mnl_var_test(df,col,target):l1,l2,l3,l4=[],[],[],[]for n in col:mdl = st.MNLogit(df_wide[target],df_wide[n])mdl_fit = mdl.fit()mdl_margeff = mdl_fit.get_margeff()l=list(mdl_margeff.summary_frame()['Pr(>|z|)'])l1.append(l[0])l2.append(l[1])l3.append(l[2])l4.append(mdl_fit.aic)df=pd.DataFrame({'features':col,'p_value_1':l1,'p_value_2':l2,'p_value_3':l3,'aic':l4})return dfcol=['q14_PartySize','q15_Age','q16_Income','q20_Education','FlyingTimeHours_1','FlyingTimeHours_2','FlyingTimeHours_3','DepartureTimeHours_1','DepartureTimeHours_2','DepartureTimeHours_3','ArrivalTimeHours_1','ArrivalTimeHours_2','ArrivalTimeHours_3','TripTimeHours_1','TripTimeHours_2','TripTimeHours_3','Legroom_1','Legroom_2','Legroom_3','Fare_1','Fare_2','Fare_3']
Mnl_var_test(df_wide,col,'choice')

结果汇总

定类数据结果 定量数据结果

剔除p>0.05的特征,即:
q11_DepartureOrArrivalIsImportant q17_Gender q19_Occupation

4.2共线性检测

由于Logit模型是线性模型,变量间严重的多重共线性会影响参数估计的准确性以及泛化能力,所以要对数值型数据进行线性共线性检测。这里使用variance indlation factor(方差膨胀因子)进行评估:
VIF的一般标准为:

  • 当0<VIF<5,没有共线性
  • 当5<VIF<10,弱复共线性
  • 当10<VIF<100,中等共线性
  • 当VIF>100,严重共线性。

在这里处理vif大于10的特征,保留单变量分析中aic最小的变量。

在这里插入代码片from statsmodels.stats.outliers_influence import variance_inflation_factor
X=df_wide[['q14_PartySize','q15_Age','q16_Income','q20_Education','FlyingTimeHours_1','FlyingTimeHours_2','FlyingTimeHours_3','DepartureTimeHours_1','DepartureTimeHours_2','DepartureTimeHours_3','ArrivalTimeHours_1','ArrivalTimeHours_2','ArrivalTimeHours_3','TripTimeHours_1','TripTimeHours_2','TripTimeHours_3','Legroom_1','Legroom_2','Legroom_3','Fare_1','Fare_2','Fare_3']]
vif=pd.DataFrame()
vif['VIF Factor']=[variance_inflation_factor(X.values,i) for i in range(X.shape[1])]
vif['features']=X.columns
print(vif)

剔除共线性前

      VIF Factor              features
0   4.197024e+00         q14_PartySize
1   1.538147e+01               q15_Age
2   8.150309e+00            q16_Income
3   1.385489e+01         q20_Education
4            inf     FlyingTimeHours_1
5            inf     FlyingTimeHours_2
6            inf     FlyingTimeHours_3
7   6.470689e+12  DepartureTimeHours_1
8   2.144571e+13  DepartureTimeHours_2
9   2.180920e+13  DepartureTimeHours_3
10  1.235555e+13    ArrivalTimeHours_1
11  5.060224e+13    ArrivalTimeHours_2
12  5.146971e+13    ArrivalTimeHours_3
13           inf       TripTimeHours_1
14  4.370305e+12       TripTimeHours_2
15  4.419627e+12       TripTimeHours_3
16  5.904812e+00             Legroom_1
17  5.905125e+00             Legroom_2
18  6.059211e+00             Legroom_3
19  5.584576e+01                Fare_1
20  5.883837e+01                Fare_2
21  5.442192e+01                Fare_3

剔除共线性后

   VIF Factor           features
0    3.900565      q14_PartySize
1    5.741539         q16_Income
2    9.107147  FlyingTimeHours_1
3    5.134774          Legroom_1
4    4.759455          Legroom_2
5    4.844795          Legroom_3
6    7.644040             Fare_1

4.3哑变量处理

对于三值以上的离散变量要进行哑变量处理

from sklearn.preprocessing import OneHotEncoder
col=['Direction','q02_TripPurpose','q03_WhoPays']
col1=['Direction','q02_TripPurpose','q03_WhoPays']
col2=['q14_PartySize','q16_Income']
col3=['OBS_ID','ALT_ID','TripTimeHours','Legroom','Fare','choice']
df_long=clean(long_df,col1,col2,col3)
# #将值作映射
def make_dummy(df,col):encode = pd.get_dummies(df[col])df=df.drop(col,1)df=pd.concat([df,encode],axis=1)return df
data=make_dummy(df_long,col)

4.4模型训练

MNL模型需要满足IIA假设,即无关选择独立性假设。具体来说对于任何决策者,选择两个备选项的概率之比与其他选项的存在无关。换句话说,选项之间不能有明显的从属关系,但在我们的例子中,选项二和选项三都有中转行为,明显区别于选项一,所以我们使用NL嵌套Logit模型代替MNL。

from collections import OrderedDict
User=['Direction_1', 'Direction_2', 'q02_TripPurpose_1','q02_TripPurpose_2', 'q02_TripPurpose_3', 'q02_TripPurpose_4','q03_WhoPays_1', 'q03_WhoPays_2', 'q03_WhoPays_3','q14_PartySize', 'q16_Income']
# User=[]
Dicision=['Legroom','Fare']
Features=User+Dicisionnest,basic_spec,basic_name=OrderedDict(),OrderedDict(),OrderedDict()
nest['one_flight']=[1]
nest['two_flight']=[2,3]basic_spec['intercept']=[1,2,3]
basic_name['intercept']=['ASC_1','ASC_2','ASC_3']for n in User:basic_name[n]=[n]basic_spec[n]=[[1,2,3]]for n in Dicision:basic_name[n]=[n+'_'+str(i) for i in range(1,4)]
#     basic_name[n]=[n]basic_spec[n]=[1,2,3]mnl=pl.create_choice_model(data=data,alt_id_col='ALT_ID',obs_id_col='OBS_ID',choice_col='choice',specification=basic_spec,model_type='Nested Logit',names=basic_name,nest_spec=nest
)
mnl.fit_mle(np.zeros(22))
mnl.get_statsmodels_summary()

5.结果

Dep. Variable: choice No. Observations: 1,761
Model: Nested Logit Model Df Residuals: 1,739
Method: MLE Df Model: 22
Date: Thu, 16 Jun 2022 Pseudo R-squ.: 0.358
Time: 21:18:13 Pseudo R-bar-squ.: 0.346
AIC: 2,260.567 Log-Likelihood: -1,108.283
BIC: 2,380.987 LL-Null: -1,727.465
coef std err z p_value [0.025 0.975]
one_flight 0 nan nan nan nan nan
two_flight 0.3720 0.254 1.466 0.143 -0.125 0.869
ASC_1 0.6701 nan nan nan nan nan
ASC_2 -0.2182 nan nan nan nan nan
ASC_3 -0.4519 nan nan nan nan nan
Direction_1 -2.395e-13 4.17e+21 -5.74e-35 1.000 -8.18e+21 8.18e+21
Direction_2 -1.131e-12 4.21e+21 -2.68e-34 1.000 -8.26e+21 8.26e+21
q02_TripPurpose_1 -2.475e-13 nan nan nan nan nan
q02_TripPurpose_2 -1.024e-12 nan nan nan nan nan
q02_TripPurpose_3 -1.863e-14 nan nan nan nan nan
q02_TripPurpose_4 -7.025e-14 nan nan nan nan nan
q03_WhoPays_1 -1.109e-12 nan nan nan nan nan
q03_WhoPays_2 -1.833e-13 nan nan nan nan nan
q03_WhoPays_3 -2.636e-14 nan nan nan nan nan
q14_PartySize -2.206e-12 2.09e+14 -1.06e-26 1.000 -4.09e+14 4.09e+14
q16_Income -1.147e-11 4.32e+13 -2.66e-25 1.000 -8.46e+13 8.46e+13
Legroom_1 0.1991 0.053 3.733 0.000 0.095 0.304
Legroom_2 0.1185 0.053 2.238 0.025 0.015 0.222
Legroom_3 0.1448 0.054 2.692 0.007 0.039 0.250
Fare_1 -0.0177 0.001 -15.623 0.000 -0.020 -0.015
Fare_2 -0.0201 0.001 -14.779 0.000 -0.023 -0.017
Fare_3 -0.0192 0.001 -14.381 0.000 -0.022 -0.017
TripTimeHours_1 -0.4809 0.095 -5.051 0.000 -0.668 -0.294
TripTimeHours_2 -0.2588 0.083 -3.130 0.002 -0.421 -0.097
TripTimeHours_3 -0.3010 0.083 -3.617 0.000 -0.464 -0.138

我们发现虽然前面做了那么多分析,从结果来看真正显著的项只有Legroom Fare TripTime,即座位空间、票价和旅行时间,与选择者本人的属性如收入、旅行人数等都无关联。
从系数来看,其中影响程度最大的为旅行时间,其次是座位空间,票价反倒影响不那么大。其中的缘由可能就是统计学实验中的选择性偏差吧,飞机属于较昂贵的出行方式,购买机票的群体本身对价格并不十分敏感,更看重飞行体验。
完整代码及数据

python数据分析实战:DCM模型设计及实现(以波音公司用户选择为例)相关推荐

  1. Python数据分析实战基础 | 初识Pandas

    这是Python数据分析实战基础的第一篇内容,主要是和Pandas来个简单的邂逅.已经熟练掌握Pandas的同学,可以加快手速滑动浏览或者直接略过本文. 01  重要的前言 这段时间和一些做数据分析的 ...

  2. 《Python数据分析实战》day2: Pandas中取得某行或者是某列的一点思考

    今天看了<Python数据分析实战>这本书的第四章:Pandas的简介的部分,大概看了一半,在实践代码的时候发现了jupyter notebook提示warning,研究了一下有了一些自己 ...

  3. python数据分析实战 fabio nelli百度云_Python数据分析实战 内利(Fabio Nelli),杜春晓 9787115432209...

    商品描述: 基本信息 书名:Python数据分析实战 定**价:59.00元 作者: 内利(Fabio Nelli) 著,杜春晓 译 出版社:人民邮电出版社 出版日期:2016-08-01 ISBN: ...

  4. python电影数据分析报告_【python数据分析实战】电影票房数据分析(二)数据可视化...

    在上一部分<[python数据分析实战]电影票房数据分析(一)数据采集> 已经获取到了2011年至今的票房数据,并保存在了mysql中. 本文将在实操中讲解如何将mysql中的数据抽取出来 ...

  5. Python数据分析实战:上海二手房价分析

    1 数据搜集 使用 urllib 库中的request 模块爬取赶集网发布的上海二手房信息,包括包括户型.面积.单价等,再使用BeautifulSoup 库解析爬取的HTML数据,最终将数据保存到CS ...

  6. Python数据分析实战学习与分享(一)

    学习的书籍: Python Data Analytics Python数据分析实战(尚未出版电子书) 1.1数据分析 当今世界对信息技术的依赖程度日渐加深,每天都会产生和存储海量的数据.数据的来源多种 ...

  7. Python数据分析实战学习

    Python数据分析实战学习\displaystyle\boxed{Python数据分析实战学习}Python数据分析实战学习​ AprilJulyOctober2015AprilJulyOctobe ...

  8. Python数据分析实战

    Python数据分析实战(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1nlHM1IW8MYg3z79TUwIsWg 提取码:ux8t 复制这段内容后打开百度网盘手 ...

  9. python数据分析实例-python数据分析实战

    Python数据分析实战(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1nlHM1IW8MYg3z79TUwIsWg 提取码:ux8t 复制这段内容后打开百度网盘手 ...

最新文章

  1. (前)首富许家印造车果然有一套:车还没量产上市,公司先冲刺科创板募资
  2. 2012年寒假•青年基金【修改后发表】
  3. 关于计算机与网络导论的论文,计算机科学与导论论文5
  4. 微软从安卓那里获取的盈利比重WinPhone 7还多
  5. css img 适配尺寸_img图片自适应布局_HTML5教程_郭隆邦技术博客
  6. 朴素版的Dijkstra算法
  7. 用记事本写表白html,抖音电脑弹窗表白代码怎么弄_记事本vbs告白代码写法介绍_抖音表白套路方法分享...
  8. 统一建模语言(UML)介绍和使用
  9. 蚂蚁金服2019实习生面经总结(已拿口头offer)
  10. while循环、do while循环for循环(重点)、break终止循环和continue结束本次循环。
  11. win7电脑桌面背景异常
  12. 2022年双非计算机保研经历分享(浙大、北航、中科院等)
  13. day030进程的两种创建方法,验证进程的空间隔离,join等待子进程
  14. MTK Android Led框架分析
  15. UE4中的GameMode、GameState、GameInstance
  16. 1100 校庆分数 25
  17. nkoj 中山纪念中学 trie
  18. c调用c++ qt_C#调用C++(QT5.5.1项目)的C++/CLI(CLR项目)项目技术笔记
  19. macOS 下显示目录下隐藏的文件
  20. 容迟网络中的路由算法笔记(三)

热门文章

  1. vue项目中,导出下载Excel表格
  2. 计算机搜索栏打字不显示,win10搜索栏无法输入文字怎么办_win10电脑搜索栏无法输入的解决方法...
  3. Screen Wonders for Mac (3D动态视频壁纸) v1.9.1
  4. Python机器学习-数据预处理(二)
  5. 【NB-ioT模组】移远BC35-G 基于STM32连接电信云(附代码)
  6. 解决win10内存占用逐渐变大(亲测有效)
  7. 华为用户的福利!1分钱就可以坐公交车,操作方法教程
  8. win32 24内存管理和文件操作
  9. 数学建模之稳定性模型详解
  10. 农业农村部回应长江刀鱼将正式禁捕:已严重过度捕捞