实战项目一:地铁人流量预测

您所在的位置:网站首页 地铁站人流量统计 实战项目一:地铁人流量预测

实战项目一:地铁人流量预测

2024-07-06 12:33:19| 来源: 网络整理| 查看: 265

项目简介 地铁人流量预测项目背景项目宗旨项目简介01数据清洗;02特征提取;03数据初步分析;04数据深度分析05数据模型的创建;06数据模型的评估07模型的优化改进08引入复杂模型——XGBoost

地铁人流量预测 项目背景 为了帮助纽约市的地铁运输管理局(MTA)省钱并使地铁更安全;为了更准确地预测每日将有多少人访问某些地铁站点,从而让MTA更好地分配员工并预测否则会出乎意料的高峰期。 项目宗旨 预测在任何时候有多少人会在纽约市(纽约市)使用地铁;探讨当前的天气状况是否有助于预测进出地铁站的人数; 项目简介 01数据清洗; 02特征提取;

进行数据清洗和特征提取后的有效特征字段合计22列,可分为2种类型的数据:(1)站点数据和天气数据。具体包括如下:

特征功能UNIT站点DATEn进站日期TIMEn进站时间DESCn目的地ENTRIESn_hourly进站人数EXITSn_hourly出站人数maxpressurei天气的气压maxminpressurei天气的气压minmeanpressurei天气的气压meanmaxdewpti风力maxmindewpti风力minmeandewpti风力meanfog雾量rain雨量maxtempi温度maxmintempi温度minmeantempi温度meanprecipi降水量thunder打雷 03数据初步分析;

(a)绘制“任意时刻(DateTimeN)下,进站人数(ENTRIESn_hourly)和出站人数(EXITSn_hourly)的分布折线图”; 结论 1、地铁进出入人流量呈现“间歇性密集”分布; 2、入口和出口每天似乎都有几次峰值,但很难判断这些峰值何时出现; 3、需要深入挖掘了一下。 首先,分析星期几如何影响每小时的进站/出站人流量; (b)绘制“不同星期(day)下,进站人数(ENTRIESn_hourly)和出站人数(EXITSn_hourly)的分布条形图”; 结论 1、星期五和星期六是进/出站的人流量最少的日子。 2、下一步可尝试绘制了按小时分组后,各小时的进站人数和出站人数,以查看哪些小时比其他小时更繁忙; (c)绘制“以小时分组后,不同小时下,进站人数(ENTRIESn_hourly)和出站人数(EXITSn_hourly)的分布折线图”; 结论 1、可以发现白天确实存在多个尖峰。但是详细的分布关系需进一步精细绘图; 2、接下来考虑降雨对使用地铁的人数的影响,我们的天气数据中有一个“rain”列,如果不下雨则为0,如果下雨为1。 3、通过df.describe()发现:在下雨时,每小时进入和退出的中位数和平均数比在没有下雨时高。 然而,数值差异非常小; 4、进一步绘制数据的核密度估计值(KDE)。 KDE可以被认为是“平滑直方图”,通过此图进行对我们数据的概率分布函数(PDF)的估计,即“此时这个值的[0,1]的概率是多少? (d)对进站人数(ENTRIESn_hourly)取对数log10得到新增特征(ENTRIESn_hourly_log10)。绘制“ENTRIESn_hourly_log10核密度图KED,hue为是否下雨”; 结论 1、通过在x轴上绘制ENTRIESn_hourly_log10的核密度曲线KED,可以更容易地在同一图表中拟合具有极值的数据,实现降噪的目的; 2、“以小时分组后,不同小时下,进站人数(ENTRIESn_hourly)和出站人数(EXITSn_hourly)的分布折线图”表明,貌似在下雨时每小时有更多人出行,但差距并不明显。 通过绘制KDE发现:在MTA上不同“出行模式”下的人流量不会根据下雨而改变。

04数据深度分析

下一步我们将以一种数字方式分析确定存在差异,例如:(1)给定两组数据,我们需要比较,两组数据是否具有相同的平均值。(2)考察“所给数据是否正常分布,以便我可以对其进行 t-检验? (d)绘制“进站人数(ENTRIESn_hourly)的计数直方图”; 结论 “进站人数(ENTRIESn_hourly)的计数直方图”表明:“进站人数(ENTRIESn_hourly)”的数据貌似不呈现“正态分布”特征;

(e)为进一步确定“进站人数(ENTRIESn_hourly)”的数据分布特征,引入 (k2,pvalue) = scipy.stats.normaltest(turnstile_data[“ENTRIESn_hourly”]) 模块,对“进站人数(ENTRIESn_hourly)”进行“正态性检验”(返回值pvalue——表示“假设检验的双侧卡方概率”); 结论 1、在正态性检验中,Shapiro-Wilk测试(scipy.stats.shapiro),只适用于具有5000以下的数据集样本; 2、在本项目的正态性检验(scipy.stats.normaltest)中,返回了接近0的p值,这意味着数据确实不呈现正态分布,即:我们不能使用t-检验! 3、接下来,由于假设数据不是正态分布的,故尝试用Mann-Whitney U测试。 4、Mann-Whitney U检验是应用最广泛的两独立样本的秩和检验方法。简单的说,该检验是与独立样本t-检验相对应的方法(即:当正态分布、方差齐性等不能达到t-检验的要求时,可以使用该检验)。其假设基础是:若两个样本有差异,则他们的中心位置将不同。 (f)将样本数据按照是否下雨分开,即df_raining和df_not_raining,之后 计算样本df_raining和df_not_raining的Mann-Whitney秩检验; 适用如下计算方法:

(u,pvalue) = scipy.stats.mannwhitneyu(not_raining["ENTRIESn_hourly"],raining["ENTRIESn_hourly"]) print("p-value of test statistic: %.4f" % (pvalue * 2,) ) # 输出样本df_raining和df_not_raining的Mann-Whitney秩检验的p-value >>> p-value of test statistic: 0.0500

结论 1、由于scipy.stats.mannwhiteneyu返回的是单侧p值,并且在收集数据之前我们没有预测哪个组具有更高的平均值,所以,我们使用单侧p值 * 2 得到双侧p值。 2、有上述计算结果,可知在5%的确定度(degree of certainty)下,每小时入站人流量的平均值的差异,取决于是否正在下雨。

05数据模型的创建;

通过绘制各种图表并使用统计测试,我们已经确定了“星期”,“一天中的小时”以及“下雨与否”会影响乘坐MTA的人数。 然而,我们预期目标是——预测在任何特定时间有多少人使用纽约市的地铁,为实现这一目标,我们需引入机器学习算法模型。 在机器学习中,预测连续变量(如高度,重量,每小时的条目数等)的任务称为 “回归”。该项目采用线性回归的方法,通过我们已经使用图表确认的变量来预测每小时进站人数的条目数量。 特征工程 由于算法模型仅能识别numerical型的数据,所以需要根据数据特征的类型对其进行处理转换:

连续变量:对连续变量需要考虑归一化、特征缩放 本项目中的连续变量包括:(1)“降雨量”(“precipi”列)(2)“一天中的小时(0到23)”(“Hour”列)(3)“华氏温度的平均值”(“meantempi”列);类别变量:对于类别变量需进行“独热编码”转化为numerical型(数值型)

本项目中的类别变量包括:“站点”(“UNIT”列)。 线性回归模型的损失函数 J ( θ ) = 1 2 m ∑ i = 1 m ( predictions − actuals ) 2 = 1 2 m ∑ i = 1 m ( θ T x − y ) 2 \begin{aligned} J(\theta) ;= \frac{1}{2m} \displaystyle \sum_{i=1}^{m} \left( \textrm{predictions} - \textrm{actuals} \right) ^ 2 \\ ;= \frac{1}{2m} \displaystyle \sum_{i=1}^{m} \left( \theta^T x - y \right) ^ 2 \end{aligned} J(θ)​=2m1​i=1∑m​(predictions−actuals)2=2m1​i=1∑m​(θTx−y)2​

#定义线性回归的损失函数 def compute_cost(features, values, theta): m = len(values) predictions = features.dot(theta) return (1/ (2 * m)) * np.square(predictions-values).sum()

问题转化为求解使得线性回归的损失函数取得min值,解决方法:使用梯度下降法,寻找使损失函数最小化的theta值。

梯度下降法 θ j = θ j − α m ∑ i = 1 m ( θ T x − y ) x 其 中 , α 为 学 习 率 ( l e a r n i n g − r a t e ) \begin{aligned} ;\theta_j = \theta_j - \frac{\alpha}{m} \displaystyle \sum_{i=1}^{m} \left( \theta^T x - y \right ) x \\;其中,\alpha 为学习率( learning-rate) \end{aligned} ​θj​=θj​−mα​i=1∑m​(θTx−y)x其中,α为学习率(learning−rate)​

#定义梯度下降法,寻找使损失函数最小化的一组theta值 def gradient_descent(features, values, theta, alpha, num_iterations): m=len(values) cost_history = [] for i in range(num_iterations): loss = features.dot(theta) - values delta = (alpha/m) * loss.dot(features) theta -= delta cost_history.append(compute_cost(features, values, theta)) return theta, pd.Series(cost_history)

特征缩放 使用梯度下降法求解线性回归的损失函数min值之前,需要进行特征缩放,以加快收敛速度(备注:特征缩放不会影解决方案的正确性)。 因为如果我们不使用特征缩放将每个输入特征,缩放到-1≤??≤1的范围,那么我们的算法将花费很长时间才能收敛。

#定义特征缩放函数 def normalize_features(array): mu = array.mean() sigma = array.std() normalized = (array - mu) / sigma return (normalized, mu, sigma)

定义预测函数

# 定义预测函数 def predictions(features, values, alpha, num_interations): m = len(values) theta = np.zeros(features.shape[1]) theta, cost_history = gradient_descent(features, values, theta, alpha, num_interations) predictions = features.dot(theta) predictions[predictions>> '0.465'

结论 1、利用coefficient of determination,只能识别出我们的模型所训练的数据中存在的46%的变化; 2、考虑评估统计模型的另一种方法——绘制残差图;

#绘制残差图 def plot_residuals(df,predictions): plt.figure() (df["ENTRIESn_hourly"]-predictions).hist(bins=50) pylab.title("Residual plot") pylab.xlabel("Residuals") pylab.ylabel("Frequency") return plt plot_residuals(turnstile_data, pred)

为了对残差图的优劣进行评估,需引入“正态性检验”scipy.stats.normaltest(residuals)。

# 对残差结果进行“正态性检验” residuals = turnstile_data["ENTRIESn_hourly"]-pred (zscore, pvalue) = scipy.stats.normaltest(residuals) print("p-value of normaltest on residuals: %s" % pvalue) print("mean of residuals: %s" % residuals.mean()) >>> p-value of normaltest on residuals: 0.0 mean of residuals: -64.06875327870551

结论 尽管,当前的模型看起来非常合适,但残差图表明剩余误差中可能存在一些可以减少的结构。

07模型的优化改进

改进的模型方法: 一般来说,有两种方法可以提高统计模型的性能: (1)使我们的模型更复杂(make our model more complex); (2)喂给模型更多的数据(feed it more data)。 由于本项目的模型为线性回归模型,我们只是传递了原始数据集中的一小部分数据特征。 因此,接下来,我们可以使模型更复杂,并传递更多特征变量,来进行模型优化。

01 传递更多的特征变量,来优化模型

#对原始数据增加特征变量,进行同样的数据处理和分析 dummy_units = pd.get_dummies(turnstile_data['UNIT'],prefix='uint') features = turnstile_data[['rain', 'precipi', 'Hour', 'meantempi', 'mintempi', 'maxtempi', 'mindewpti', 'meandewpti', 'maxdewpti', 'minpressurei', 'meanpressurei', 'maxpressurei', 'meanwindspdi']].join(dummy_units) features, mu, sigma = normalize_features(features) #调用定义分类特征的缩放函数normalize_features features = np.array(features) # np.insert(arr,obj,values,axis),arr是一个数组,obj是元素插入的位置,values是需要插入的数值,axis是指示在哪一个轴上对应的插入位置进行插入 features = np.insert(features, 0, 1,axis=1) values = np.array(turnstile_data[['ENTRIESn_hourly']]).flatten() pred2 = predictions(features=np.array(features),values=values, alpha=0.1,num_interations=150) # 增加特征后的pred print("origial R^2: %.3f "% compute_r_squared(turnstile_data["ENTRIESn_hourly"],pred)) print("more existing features R^2: %.3f" %compute_r_squared(turnstile_data["ENTRIESn_hourly"],pred2)) >>> origial R^2: 0.465 more existing features R^2: 0.467

结论 1、上述结果表明:传递更多的特征变量,可以在一定程度上优化模型; 2、接下来考虑,通过使模型更复杂,来优化模型; 02 使模型更复杂,来优化模型 为进一步进行模型优化,可以使用特征的polynomial combinations(多项式组合) 来为我们的线性回归模型提供更好的数据拟合结果; 特征的多项式组合 1、使用itertools.combinations_with_replacement(df.columns, i)实现对数据特征的组合,调用关于特征的多项式组合函数时,增加关于特征的多项式组合函数的调用:add_polynomial_features(features, 2, add_sqrt=True); 2、特征的多项式组合的缺点是使用的特征数量急剧增加,并且训练和使用模型都需要消耗更长时间; 3、增加模型复杂性的缺点是,如果我们的模型已经足够复杂,继续增加模型复杂性将造成风险。此时,正确的做法是:我们需要喂给模型更多的数据; 4、为了收集和处理大量数据,我们可能不得不采用诸如MapReduce的并发模型,其中大量数据由许多计算机处理,这些计算机之间不能相互通信,而是写入共享文件系统; 5、判断模型是否足够复杂的方法:引入bias/variance(偏差/方差)。 (1)如果模型的bias较高,那么它就不适合data,且无法较好地拟合data,此时增加数据量已经无济于事,因为模型已经不是用于数据,正确的做法是增加模型的复杂度; (2)如果模型的variance较高,那么data将发生过拟合和模型复杂度过高,此时,正确的做法是增加data的数据量,即:提高data的复杂度,并降低模型过度拟合数据的可能性。 6、为了进行模型评估(即:确定模型究竟是bias较高,还是variance较高),我们可以通过 绘制学习曲线 (learning curves) 来确定。

# 定义关于特征的多项式组合函数 def add_polynomial_features(df, degree, add_sqrt): for i in range(2, degree +1 ): for combination in itertools.combinations_with_replacement(df.columns, i): # itertools.combinations_with_replacement(iterable, r) 允许重复元素的组合 name = "".join(combination) value = np.prod(df[list(combination)],axis=1) #np.prod()函数用来计算所有元素的乘积,对于有多个维度的数组可以指定轴,如axis=1指定计算每一行的乘积 df[name] = value if add_sqrt: for column in df.columns: df["%s_sqrt" % column] = np.sqrt(df[column]) #np.sqrt(x) : 计算数组各元素的平方根

引入关于特征的多项式组合函数后,对原始数据进行特征处理(同上,只是增加关于特征多项式函数的调用)

# 引入关于特征的多项式组合函数后,对原始数据进行特征处理(同上,只是增加关于特征多项式函数的调用) dummy_units = pd.get_dummies(turnstile_data["UNIT"],prefix="unit") features = turnstile_data[['rain', 'precipi', 'Hour', 'meantempi', 'mintempi', 'maxtempi', 'mindewpti', 'meandewpti', 'maxdewpti', 'minpressurei', 'meanpressurei', 'maxpressurei', 'meanwindspdi']] add_polynomial_features(features, 2, add_sqrt=True) # 调用关于特征的多项式函数 features = features.join(dummy_units) features, mu, sigma = normalize_features(features) features = np.array(features) features = np.insert(features,0,1,axis=1) values = np.array(turnstile_data[["ENTRIESn_hourly"]]).flatten() pred3 = predictions(features=np.array(features),values=values, alpha=0.025,num_interations=150) print("original R^2: %.3f" % compute_r_squared(turnstile_data['ENTRIESn_hourly'],pred)) print("more existing features R^2:%.3f"% compute_r_squared(turnstile_data['ENTRIESn_hourly'],pred2)) print("more existing features with polynomial combinations R^2: %.3f" % compute_r_squared(turnstile_data["ENTRIESn_hourly"],pred3)) >>> original R^2: 0.465 more existing features R^2:0.467 more existing features with polynomial combinations R^2: 0.472

绘制学习曲线 (learning curves) 1、数据集的划分: 在绘制学习曲线时,我们不是在所有可用的数据集上进行模型训练,而是将数据集分成三部分:训练集,交叉验证集和测试集。一种较好的默认拆分方法是——training约为60%,cross-validation约为20%,testing约为20%。 在本项目中,由于我们仅绘制学习曲线而不评估我们模型的普遍性,所以我们训练集划分为:training为60%,cross-validation为40%。 2、学习曲线的绘制: (1)绘制相对于training样本数量的?CV(?) 和 ?train(?)学习曲线。 (2)当提供更多训练样本时,需要重新训练?的新值并绘制关于training set (?train(?)) 和cross-validation set (?CV(?))的成本函数(cost function)学习曲线。 3、模型的评估: 通过学习曲线评估模型是high bia还是high variance的具体方法如下: (1)如果?CV(?)≈?train(?) ,随着样本数量的增加,bias将增大。说明该模型无法捕获数据的pattern,此时 应该增加模型的复杂度 ; (2)如果?CV(?)>>?train(?),则可能是所选模型太复杂并且训练数据发生过拟合造成的,此时 增加训练样本的数量有助于提高模型的性能。

利用df.reindex(np.random.permutation(df.index)) 定义对原始数据集进行重新洗牌的函数

# 定义对原始数据集进行重新洗牌的函数 def get_shuffled_df(df): m = len(turnstile_data) df = turnstile_data.copy() df = df.reindex(np.random.permutation(df.index)) #np.random.permutation,是对原来的数组进行重新洗牌(即随机打乱原来的元素顺序),返回一个新的打乱顺序的数组,并不改变原来的数组 return df np.random.seed(42) df = get_shuffled_df(turnstile_data)

对training数据集进行划分,60%为训练集,剩余40%的cross-validation集。

m = len(df) df_train = df[:int(0.6*m)] #截取60%的训练集 df_cv = df[int(0.6*m):] #截取剩余40%的cross-validation集 feature_names = ['rain', 'precipi', 'Hour', 'meantempi'] value_name = "ENTRIESn_hourly" # traing的数据处理 dummy_units = pd. get_dummies(df_train['UNIT'],prefix="unit") features_train = df_train[feature_names].join(dummy_units) features_train, mu, sigma = normalize_features(features_train) features_train = np.array(features_train) features_train = np.insert(features_train,0,1,axis=1) #第四个参数axis是指示在哪一个轴上对应的插入位置进行插入 #np.insert(arr,obj,values,axis),在对应的位置上插入对应的值 values_train = df_train[value_name] # cross-validation的数据处理 dummy_units = pd.get_dummies(df_cv['UNIT'],prefix="unit") features_cv = df_cv[feature_names].join(dummy_units) features_cv = (features_cv-mu) / sigma features_cv = np.array(features_cv) features_cv = np.insert(features_cv,0,1,axis=1) values_cv = df_cv[value_name]

绘制相对于training样本数量的?CV(?) 和 ?train(?)学习曲线。

#绘制学习曲线的相关函数 def get_learning_curves(features_train, values_train, features_cv,values_cv,num_points=10, alpha=0.1,num_iterations=150): cost_train = [] r_squared_train = [] cost_cv = [] r_squared_cv = [] m = len(features_train) number_of_samples = np.array(np.linspace(m/num_points, m-1, num_points),dtype=np.int) #生成等差数列 for i in number_of_samples: features_train_subset = features_train[:i] values_train_subset = values_train[:i] theta = np.zeros(features_train_subset.shape[1]) theta, _ = gradient_descent(features_train_subset,values_train_subset, theta,alpha, num_iterations) #调用梯度下降函数 cost_train_subset = compute_cost(features_train_subset,values_train_subset,theta) cost_train.append(cost_train_subset) r_squared_train.append(compute_r_squared(values_train_subset,features_train_subset.dot(theta))) cost_cv_subset = compute_cost(features_cv, values_cv,theta) cost_cv.append(cost_cv_subset) r_squared_cv.append(compute_r_squared(values_cv,features_cv.dot(theta))) return pd.DataFrame({'Number of samples': number_of_samples, 'Training error': cost_train, 'Testing error': cost_cv, 'R^2 training': r_squared_train, 'R^2 testing': r_squared_cv}) np.random.seed(42) costs = get_learning_curves(features_train, values_train,features_cv,values_cv) # 调用学习曲线函数

绘制学习曲线。

#绘制学习曲线 fig, (ax1, ax2) = pylab.subplots(nrows=2,ncols=1,figsize=(12,12)) set1 = brewer2mpl.get_map("Set1","qualitative",3).mpl_colors costs.plot(x="Number of samples", y=['Training error', 'Testing error'],ax=ax1,color=set1) ax1.set_title("Traditional learning curves") ax1.legend() ax1.set_xlabel("Number of training samples") ax1.set_ylabel("Value of cost function") costs.plot(x="Number of samples",y=["R^2 training", "R^2 testing"],ax=ax2,color=set1) ax2.set_title("Learning curves using R^2") ax2.legend() ax2.set_xlabel("Number of training samples") ax2.set_ylabel("R^2") pass

在这里插入图片描述 结论 1、“学习曲线”出现训练错误超出测试错误的情况,这可能是由于随机错误造成的; 2、如果要绘制更稳健的“学习曲线”,需要引入bootstrapping来评价训练集和测试集上成本函数的值,而不是使用单个样本; 3、观察替代传统“学习曲线”的使用“确定系数R^2”绘制的非常规“学习曲线”,表明:当前所用模型的bias较高; 4、测定的训练系数和测试系数几乎相等,并且基本不随样本数量发生变化,因此,我们不必通过增加训练样本的数量来改善学习算法的性能,反之,我们应该更专注于提升模型的复杂度,从而改善学习算法的性能,正如我们上面所做的那样,例如:添加多项式特征,或者,可以使用更高级的回归技术,例如:神经网络或支持向量回归(SVR); 5、当然,还存在用一种可能性是,我们当前可用的与天气有关的特征并不包含足够的信息以更好地预测MTA的乘客数量,但判断这是否属实较为困难。

08引入复杂模型——XGBoost from sklearn.model_selection import cross_val_score from xgboost import XGBRegressor params = [3,5,6,9] #手动调参,可以使用GridSearch进行自动调参 test_scores = [] for param in params: clf = XGBRegressor(max_depth=param) test_score = np.sqrt(-cross_val_score(clf,features_train,values_train,cv=3, scoring='neg_mean_squared_error')) test_scores.append(np.mean(test_score)) #绘制误差曲线 import matplotlib.pyplot as plt %matplotlib inline plt.plot(params, test_scores) plt.title("max_depth vs CV Error")


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭