决策树在幸福感预测中的应用与挑战
1. 寻找最佳分割点
在数据处理中,我们可以通过特定的方法找到每个变量的最佳分割点。以
hhmmb
变量(记录受访者的家庭成员数量)为例,我们可以使用以下代码来找到它的最佳分割点:
allvalues = list(ess.loc[:,'hhmmb'])
predictedvalues = list(ess.loc[:,'happy'])
print(get_splitpoint(allvalues,predictedvalues))
输出结果可能如下:
(1.0, 60860.029867951016, 6.839403436723225, 7.620055170794695)
这意味着
hhmmb
变量的最佳分割点是 1.0,我们可以将调查受访者分为独居(1 个家庭成员)和与他人同住(超过 1 个家庭成员)两组。同时,我们还可以看到这两组的平均幸福感水平分别约为 6.84 和 7.62。
2. 选择分割变量
在决策树中,我们需要决定在每个分支节点使用哪个变量进行分割。我们采用的原则是选择导致最小误差的分割方式。以下是实现这一功能的代码:
def getsplit(data,variables,outcome_variable):
best_var = ''
lowest_error = float('inf')
best_split = None
predictedvalues = list(data.loc[:,outcome_variable])
best_lowermean = -1
best_highermean = -1
for var in variables:
allvalues = list(data.loc[:,var])
splitted = get_splitpoint(allvalues,predictedvalues)
if(splitted[1] < lowest_error):
best_split = splitted[0]
lowest_error = splitted[1]
best_var = var
best_lowermean = splitted[2]
best_highermean = splitted[3]
generated_tree = [[best_var,float('-inf'),best_split,best_lowermean],[best_var,best_split,float('inf'),best_highermean]]
return(generated_tree)
我们可以使用以下代码来运行这个函数:
variables = ['rlgdgr','hhmmb','netusoft','agea','eduyrs']
outcome_variable = 'happy'
print(getsplit(ess,variables,outcome_variable))
输出结果可能如下:
[['netusoft', -inf, 4.0, 7.041597337770383], ['netusoft', 4.0, inf, 7.73042471042471]]
这表明我们得到了一个简单的“树”,它只有两个分支。第一个分支对应互联网使用频率(
netusoft
)小于等于 4.0 的人群,平均幸福感约为 7.0;第二个分支对应互联网使用频率大于 4.0 的人群,平均幸福感约为 7.7。
这个简单树的结构可以用以下 mermaid 流程图表示:
graph TD;
A[所有调查受访者] --> B[互联网使用 <= 4];
A --> C[互联网使用 > 4];
B --> D[平均幸福感: 7.0];
C --> E[平均幸福感: 7.7];
3. 增加树的深度
为了使决策树更复杂,我们需要增加树的深度。以下是更新后的
getsplit
函数:
maxdepth = 3
def getsplit(depth,data,variables,outcome_variable):
# --snip--
generated_tree = [[best_var,float('-inf'),best_split,[]],[best_var,best_split,float('inf'),[]]]
if depth < maxdepth:
splitdata1=data.loc[data[best_var] <= best_split,:]
splitdata2=data.loc[data[best_var] > best_split,:]
if len(splitdata1.index) > 10 and len(splitdata2.index) > 10:
generated_tree[0][3] = getsplit(depth + 1,splitdata1,variables,outcome_variable)
generated_tree[1][3] = getsplit(depth + 1,splitdata2,variables,outcome_variable)
else:
depth = maxdepth + 1
generated_tree[0][3] = best_lowermean
generated_tree[1][3] = best_highermean
else:
generated_tree[0][3] = best_lowermean
generated_tree[1][3] = best_highermean
return(generated_tree)
我们可以使用以下代码来运行这个函数:
variables = ['rlgdgr','hhmmb','netusoft','agea','eduyrs']
outcome_variable = 'happy'
maxdepth = 2
print(getsplit(0,ess,variables,outcome_variable))
输出结果将是一个深度为 2 的决策树,它以嵌套列表的形式表示。通过观察这些嵌套列表,我们可以逐步构建出整个决策树。
4. 评估决策树
生成决策树后,我们需要评估其性能。我们可以编写一个函数
get_prediction
来根据决策树预测一个人的幸福感水平:
def get_prediction(observation,tree):
j = 0
keepgoing = True
prediction = - 1
while(keepgoing):
j = j + 1
variable_tocheck = tree[0][0]
bound1 = tree[0][1]
bound2 = tree[0][2]
bound3 = tree[1][2]
if observation.loc[variable_tocheck] < bound2:
tree = tree[0][3]
else:
tree = tree[1][3]
if isinstance(tree,float):
keepgoing = False
prediction = tree
return(prediction)
然后,我们可以使用以下代码来对整个数据集进行预测,并计算预测误差:
predictions = []
for k in range(0,len(ess.index)):
observation = ess.loc[k,:]
predictions.append(get_prediction(observation,thetree))
ess.loc[:,'predicted'] = predictions
errors = abs(ess.loc[:,'predicted'] - ess.loc[:,'happy'])
print(np.mean(errors))
运行这段代码后,我们发现决策树的平均预测误差为 1.369。虽然这个误差大于零,但比使用更差的预测方法可能得到的误差要低,说明决策树目前的预测效果还算不错。
5. 过拟合问题
在评估决策树时,我们发现使用与生成决策树相同的数据集来评估其准确性是不合理的,这会导致过拟合问题。过拟合是指机器学习模型在训练数据上表现良好,但在新数据上表现不佳的现象。
为了避免过拟合,我们需要将数据集分为训练集和测试集。以下是具体的操作步骤:
1. 导入
numpy
模块。
2. 设置随机种子,确保结果的可重复性。
3. 打乱数据集的顺序。
4. 将数据集分为训练集和测试集。
代码如下:
import numpy as np
np.random.seed(518)
ess_shuffled = ess.reindex(np.random.permutation(ess.index)).reset_index(drop = True)
training_data = ess_shuffled.loc[0:37000,:]
test_data = ess_shuffled.loc[37001:,:].reset_index(drop = True)
通过这种方式,我们可以使用训练集来构建决策树,使用测试集来评估决策树的准确性。如果训练集的误差很低,而测试集的误差很高,那么我们就可能存在过拟合问题。
决策树在幸福感预测中具有一定的应用价值,但我们需要注意过拟合问题,并通过合理的数据集划分来提高模型的泛化能力。同时,我们还可以通过调整变量和树的深度来进一步优化决策树的性能。
决策树在幸福感预测中的应用与挑战(续)
6. 不同参数下的决策树
我们可以尝试使用不同的变量集合和最大深度来生成决策树,以观察决策树的变化。例如:
variables = ['sclmeet','rlgdgr','hhmmb','netusoft','agea','eduyrs','health']
outcome_variable = 'happy'
maxdepth = 3
print(getsplit(0,ess,variables,outcome_variable))
运行这段代码后,我们得到了一个与之前不同的决策树。输出结果如下:
[['health', -inf, 2.0, [['sclmeet', -inf, 4.0, [['health', -inf, 1.0, [['rlgdgr', -inf, 9.0, 7.9919636617749825], ['rlgdgr', 9.0, inf, 8.713414634146341]]], ['health', 1.0, inf, [['netusoft', -inf, 4.0, 7.195121951219512], ['netusoft', 4.0, inf, 7.565659008464329]]]]], ['sclmeet', 4.0, inf, [['eduyrs', -inf, 25.0, [['eduyrs', -inf, 8.0, 7.9411764705882355], ['eduyrs', 8.0, inf, 7.999169779991698]]], ['eduyrs', 25.0, inf, [['hhmmb', -inf, 1.0, 7.297872340425532], ['hhmmb', 1.0, inf, 7.9603174603174605]]]]]], ['health', 2.0, inf, [['sclmeet', -inf, 3.0, [['health', -inf, 3.0, [['sclmeet', -inf, 2.0, 6.049427365883062], ['sclmeet', 2.0, inf, 6.70435393258427]]], ['health', 3.0, inf, [['sclmeet', -inf, 1.0, 4.135036496350365], ['sclmeet', 1.0, inf, 5.407051282051282]]]]], ['sclmeet', 3.0, inf, [['health', -inf, 4.0, [['rlgdgr', -inf, 9.0, 6.992227707173616], ['rlgdgr', 9.0, inf, 7.434662998624484]]], ['health', 4.0, inf, [['hhmmb', -inf, 1.0, 4.948717948717949], ['hhmmb', 1.0, inf, 6.132075471698113]]]]]]]]
可以看到,第一个分支现在基于
health
变量进行分割,而不是之前的
netusoft
变量。不同的参数设置会导致决策树的结构和分支发生变化,这体现了决策树方法的灵活性,但也意味着不同的研究者可能会因为参数选择的不同而得到不同的结论。
7. 决策树的可视化理解
虽然嵌套列表可以准确地表示决策树,但阅读起来并不直观。我们可以通过逐步分析嵌套列表来构建决策树的可视化结构。例如,对于前面得到的深度为 2 的决策树,部分结构如下:
graph TD;
A[所有调查受访者] --> B[互联网使用 <= 4];
A --> C[互联网使用 > 4];
B --> D[家庭成员 <= 4];
B --> E[家庭成员 > 4];
D --> F[年龄 <= 15];
D --> G[年龄 > 15];
E --> H[受教育年限 <= 11];
E --> I[受教育年限 > 11];
C --> J[家庭成员 <= 1];
C --> K[家庭成员 > 1];
J --> L[年龄 <= 66];
J --> M[年龄 > 66];
K --> N[宗教程度 <= 5];
K --> O[宗教程度 > 5];
F --> P[平均幸福感: 8.035714285714286];
G --> Q[平均幸福感: 6.997666564322997];
H --> R[平均幸福感: 7.263969171483622];
I --> S[平均幸福感: 8.0];
L --> T[平均幸福感: 7.135361428970136];
M --> U[平均幸福感: 7.621993127147766];
N --> V[平均幸福感: 7.743893678160919];
O --> W[平均幸福感: 7.9873320537428025];
通过这个流程图,我们可以更清晰地看到决策树的分支结构和每个分支对应的平均幸福感。
8. 决策树的进一步探索
我们还可以从多个方面对决策树进行进一步的探索:
-
变量选择的影响
:尝试不同的变量组合,观察决策树的结构和预测性能的变化。例如,增加或减少某些变量,看是否能提高决策树的预测准确性。
-
深度的调整
:改变决策树的最大深度,分析深度对过拟合和预测性能的影响。一般来说,深度过深可能会导致过拟合,而深度过浅可能无法捕捉到数据的复杂关系。
-
不同数据集的应用
:将决策树应用到不同的数据集上,验证其泛化能力。不同的数据集可能具有不同的特征和分布,决策树在不同数据集上的表现可以帮助我们评估其通用性。
9. 总结
决策树是一种强大的机器学习工具,在幸福感预测等领域具有广泛的应用。通过寻找最佳分割点、选择分割变量、增加树的深度等步骤,我们可以构建出能够有效预测幸福感水平的决策树。
然而,决策树也面临着过拟合的挑战。为了避免过拟合,我们需要将数据集分为训练集和测试集,使用训练集构建决策树,使用测试集评估其准确性。
同时,决策树的灵活性使得不同的参数选择会导致不同的结果,这需要我们在实际应用中仔细权衡和选择。通过不断地探索和调整,我们可以优化决策树的性能,使其更好地适应不同的数据集和预测任务。
以下是一个总结表格,展示了决策树构建和评估的关键步骤:
|步骤|操作|代码示例|
|----|----|----|
|寻找最佳分割点|使用
get_splitpoint
函数|
print(get_splitpoint(allvalues,predictedvalues))
|
|选择分割变量|使用
getsplit
函数|
print(getsplit(ess,variables,outcome_variable))
|
|增加树的深度|更新
getsplit
函数并设置最大深度|
maxdepth = 2; print(getsplit(0,ess,variables,outcome_variable))
|
|评估决策树|使用
get_prediction
函数进行预测并计算误差|
predictions = []; for k in range(0,len(ess.index)): ...; print(np.mean(errors))
|
|避免过拟合|将数据集分为训练集和测试集|
import numpy as np; np.random.seed(518); ...; training_data = ess_shuffled.loc[0:37000,:]; test_data = ess_shuffled.loc[37001:,:].reset_index(drop = True)
|
通过以上步骤和方法,我们可以充分发挥决策树的优势,同时避免其潜在的问题,实现更准确的预测和分析。
超级会员免费看
68

被折叠的 条评论
为什么被折叠?



