日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python数据分析案例28——西雅图交通事故预测(不平衡样本处理)

發布時間:2024/5/14 python 59 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python数据分析案例28——西雅图交通事故预测(不平衡样本处理) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本次案例適合機器學習數據科學方向的同學。


?引言(廢話集)

交通事故是一個嚴重的公共安全問題,在全球范圍內每年都有成千上萬的人死于交通事故。隨著交通運輸的發展和城市化進程的加速,交通事故已成為制約城市發展和人民幸福的主要因素之一。因此,通過分析交通事故的原因和嚴重程度,以及開發有效的預測模型,可以有效預防交通事故的發生,并減少交通事故對人類社會的危害。

本研究的目標是通過機器學習模型預測交通事故的嚴重程度,以保護城市居民免受交通事故的嚴重傷害并防止交通碰撞。為了實現這一目標,我們將分析影響交通事故嚴重程度的各種因素,并建立一個準確、可靠的預測模型。

目前,人們通常依靠經驗和統計數據來評估交通事故的嚴重程度。但是,這種方法的缺點是可能存在主觀性和局限性,無法準確預測交通事故的發生和嚴重程度。相比之下,機器學習模型可以自動學習和優化模型,以最大程度地準確預測交通事故的嚴重程度。本研究旨在比較當前解決方案和我們提出的解決方案之間的優缺點,以證明機器學習模型在交通事故預測方面的優勢。

最后,我們將通過分析西雅圖市10年內的交通事故數據來提供支持我們研究的證據,我們的響應變量y是SEVERITYCODE(事故嚴重程度代碼)。因為在一個交通事故中,事故嚴重程度是我們最關心的問題,也是我們希望能夠預測的目標變量。其他列則可能作為預測變量x,幫助我們預測事故嚴重程度。本研究將為西雅圖交通政府制定更有效的交通事故預防措施和政策提供科學依據。


導入包

#導入數據分析常用包 import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns %matplotlib inline plt.rcParams['axes.unicode_minus'] = False #負號

數據探索

# 讀取數據 data=pd.read_csv('Collisions.csv',na_values='Unknown') #查看數據前三行 data.head(3)

#自動解析數據類型 data=data.infer_objects() #查看數據信息 data.info()

?

?#變量含義
'''OBJECTID:事故對象的標識符
INCKEY:內部事故唯一鍵
COLDETKEY:采集數據的標識符
REPORTNO:事故報告號
STATUS:事故處理狀態
ADDRTYPE:地址類型
INTKEY:十字路口標識符
LOCATION:事故位置
EXCEPTRSNCODE:例外原因代碼
EXCEPTRSNDESC:例外原因描述
SEVERITYCODE:事故嚴重程度代碼
SEVERITYDESC:事故嚴重程度描述
COLLISIONTYPE:碰撞類型
PERSONCOUNT:涉及的人數
PEDCOUNT:行人數量
PEDCYLCOUNT:自行車數量
VEHCOUNT:涉及的車輛數量
INJURIES:受傷人數
SERIOUSINJURIES:嚴重受傷人數
FATALITIES:死亡人數
INCDATE:事故發生日期
INCDTTM:事故發生日期和時間
JUNCTIONTYPE:交叉口類型
SDOT_COLCODE:SDOT收集的事故代碼
SDOT_COLDESC:SDOT收集的事故描述
INATTENTIONIND:不注意標記
UNDERINFL:受到駕駛員的影響
WEATHER:天氣狀況
ROADCOND:道路條件
LIGHTCOND:光線條件
PEDROWNOTGRNT:行人未被授予權利
SDOTCOLNUM:SDOT收集的事故編號
SPEEDING:超速行駛
ST_COLCODE:州事故代碼
ST_COLDESC:州事故描述
SEGLANEKEY:分段車道關鍵字
CROSSWALKKEY:人行橫道關鍵字
HITPARKEDCAR:是否碰撞停放的車輛'''

#觀察缺失值 import missingno as msno msno.matrix(data)


數據預處理?

特征預處理

'''OBJECTID,INCKEY,COLDETKEY,REPORTNO''' #這四個變量是取值唯一的編號型變量,對于模型沒有幫助,刪除 data.drop(columns=['OBJECTID','INCKEY','COLDETKEY','REPORTNO'],inplace=True)

#若是有一行全為空值就刪除?

data.dropna(how='all',inplace=True)

#取值唯一的變量刪除 ?(如果有一列的值全部一樣,也就是取值唯一的特征變量就可以刪除了,因為每個樣本沒啥區別,對模型就沒啥用)?

for col in data.columns:if len(data[col].value_counts())==1:print(col)data.drop(col,axis=1,inplace=True)

?#缺失到一定比例就刪除,缺失量達到一定程度就給他刪了,缺失太多不如不要這個特征。我這里的比例是20%?

miss_ratio=0.2 for col in data.columns:if data[col].isnull().sum()>data.shape[0]*miss_ratio:print(col)data.drop(col,axis=1,inplace=True)

總共38個變量,現在已經刪除了11個了

然后需要對數據進一步細化處理,要把數據分為數值型和其他類型來看。

首先查看數值型數據


數值型變量預處理

#查看數值型數據, pd.set_option('display.max_columns', 20) data.select_dtypes(exclude=['object']).head()

?

做機器學習當然需要特征越分散越好,因為這樣就可以在X上更加有區分度,從而更好的分類。

所以那些數據分布很集中的變量可以扔掉。

可以用方差,但是由于數據的口徑大小不一致,方差不好對比,

這里我們采用異眾比例來衡量數據的分散程度,若異眾比例低于0.02就刪除

#計算異眾比例 variation_ratio_s=0.02 for col in data.select_dtypes(exclude=['object']).columns:df_count=data[col].value_counts()kind=df_count.index[0]variation_ratio=1-(df_count.iloc[0]/len(data[col]))if variation_ratio<variation_ratio_s:print(f'{col} 最多的取值為{kind},異眾比例為{round(variation_ratio,4)},太小了,沒區分度需要刪掉')#data.drop(col,axis=1,inplace=True)

我們發現SERIOUSINJURIES,FATALITIES,SEGLANEKEY ,CROSSWALKKEY 四個變量的異眾比例是很小的,大部分取值都是0。

但是SERIOUSINJURIES 嚴重受傷程度 和FATALITIES 死亡數量都是對于交通嚴重程度很多有的變量,我們選擇保留他們。

而SEGLANEKEY和CROSSWALKKEY 是路段ID和人行橫道ID,對于預測作用應該不大,選擇刪除。

##刪除 SEGLANEKEY和CROSSWALKKEY data.drop(columns=['SEGLANEKEY','CROSSWALKKEY'],inplace=True)

object型變量預處理

查看非數值變量前三行?

data.select_dtypes(include=['object']).head(3)

'LOCATION','SDOT_COLDESC','ST_COLCODE','ST_COLDESC', #這四個變量都是針對這個事件的具體描述,有的是文本類型,做不了特征變量,刪除 'SEVERITYDESC','STATUS','SDOT_COLCODE' #這幾個變量對于交通嚴重程度沒有解釋作用,也刪除 data.drop(columns=['LOCATION','SDOT_COLDESC','ST_COLCODE','ST_COLDESC','SEVERITYDESC','STATUS','SDOT_COLCODE'],inplace=True)


填充缺失值

1.刪除缺失值:對于一些缺失值的行比較少的變量可以直接刪除缺失值的行樣本。

可以看出我們的響應變量SEVERITYCODE存在缺失值,而且只有一個缺失值,刪掉這個缺失值不會對數據整體造成太大的影響,

而且缺失值可能會對后續的建模和分析產生干擾和誤差,因此在這種情況下,我們可以直接刪除存在缺失值的行。

2.其他變量填充缺失值:

(1)對于類別變量(如ADDRTYPE, COLLISIONTYPE, JUNCTIONTYPE, UNDERINFL, WEATHER, ROADCOND, LIGHTCOND)可以使用眾數進行填充。

# 刪除缺失值 data.dropna(subset=['SEVERITYCODE'], inplace=True)# 類別變量填充眾數 data['ADDRTYPE'].fillna(data['ADDRTYPE'].mode()[0], inplace=True) data['COLLISIONTYPE'].fillna(data['COLLISIONTYPE'].mode()[0], inplace=True) data['JUNCTIONTYPE'].fillna(data['JUNCTIONTYPE'].mode()[0], inplace=True) data['UNDERINFL'].fillna(data['UNDERINFL'].mode()[0], inplace=True) data['WEATHER'].fillna(data['WEATHER'].mode()[0], inplace=True) data['ROADCOND'].fillna(data['ROADCOND'].mode()[0], inplace=True) data['LIGHTCOND'].fillna(data['LIGHTCOND'].mode()[0], inplace=True)

特征工程

兩個時間變量進行轉化,變為時間的格式

data['INCDTTM'] = pd.to_datetime(data['INCDTTM']) data['INCDATE'] = pd.to_datetime(data['INCDATE'])

?INCDTTM變量包含小時,更為詳細,對INCDTTM這個變量里面提取時間特征就行,我們提取這個事故發生的年,月,小時。因為日可能沒有明顯的含義,而月份代表季節性,小時代表每天的交通事故發生的可能性最大的時刻,所以選擇年,月,小時三個作為新特征

data['year']=data['INCDTTM'].dt.year data['month']=data['INCDTTM'].dt.year data['hour']=data['INCDTTM'].dt.hour

構建了新特征后,原來的特征不要的就刪除

data.drop(columns=['INCDTTM','INCDATE'],inplace=True)

UNDERINFL中有重復含義變量,需要進行處理

#將0變為N,1變為Y data['UNDERINFL']=data['UNDERINFL'].map({'N':'N','0':'N','Y':'Y','1':'Y'})

#查看處理完的數據信息
?

print(data.shape) data.info()

沒有缺失值了。

#首先對訓練集取出y y=data['SEVERITYCODE'] data.drop(['SEVERITYCODE'],axis=1,inplace=True)

?##查看分類變量的每個變量分為幾類

for col in data.select_dtypes(include=['object']).columns:print(f"{col}變量有{len(data[col].unique())}類")


數據探索?

?數值型變量畫圖

#查看特征變量的箱線圖分布 columns = data.select_dtypes(exclude=['object']).columns.tolist() # 列表頭 dis_cols = 4 #一行幾個 dis_rows = len(columns) plt.figure(figsize=(4 * dis_cols, 4 * dis_rows),dpi=128) for i in range(len(columns)):plt.subplot(dis_rows,dis_cols,i+1)sns.boxplot(data=data[columns[i]], orient="v",width=0.5)plt.xlabel(columns[i],fontsize = 20) plt.tight_layout() #plt.savefig('特征變量箱線圖',formate='png',dpi=500) plt.show()

#畫密度圖,訓練集和測試集對比 dis_cols = 4 #一行幾個 dis_rows = len(columns) plt.figure(figsize=(4 * dis_cols, 4 * dis_rows),dpi=128)for i in range(len(columns)):ax = plt.subplot(dis_rows, dis_cols, i+1)ax = sns.kdeplot(data[columns[i]], color="Red" ,fill=True)ax.set_xlabel(columns[i],fontsize = 20)ax.set_ylabel("Frequency",fontsize = 18) plt.tight_layout() #plt.savefig('訓練測試特征變量核密度圖',formate='png',dpi=500) plt.show()

?


分類型變量畫圖

#查看特征變量的箱線圖分布 columns = data.select_dtypes(include=['object']).columns.tolist() # 列表頭 dis_cols = 3 #一行幾個 dis_rows = len(columns) plt.figure(figsize=(5 * dis_cols, 5 * dis_rows),dpi=128) for i in range(len(columns)):plt.subplot(dis_rows,dis_cols,i+1)sns.barplot(x=data[columns[i]].value_counts().index, y=data[columns[i]].value_counts().values)#sns.barplot(data=data[columns[i]].value_counts(), orient="v",width=0.5)plt.xlabel(columns[i],fontsize = 15)plt.xticks(rotation=45) plt.tight_layout() #plt.savefig('特征變量箱線圖',formate='png',dpi=500) plt.show()

相關性分析

#畫出數值型變量之間的相關性 corr = plt.subplots(figsize = (18,16),dpi=128) corr= sns.heatmap(data.corr(method='spearman'),annot=True,square=True)

?


?分類變量進行獨立熱編碼

#很多x都是文本型分類變量,所以要進行的獨立熱編碼處理

data=pd.get_dummies(data) data.shape


查看響應變量的分布?

y.value_counts()

可視化?

# 查看y的分布 #分類問題 plt.figure(figsize=(8,3),dpi=128) plt.subplot(1,2,1) y.value_counts().plot.bar(title='Response variable histogram graph') plt.subplot(1,2,2) y.value_counts().plot.pie(title='Response Variable Pie Chart') #plt.savefig('響應變量.png') plt.tight_layout() plt.show()

?

?##響應變量數據分布存在極度的不平衡情況,我們將0,1,2,2b四組情況映射為0,? 3(表示交通事故很嚴重)映射為1,表示是一個二分類問題

y=y.map({'0':0,'1':0,'2':0,'2b':0,'3':1}) y.value_counts()


下面對y進行類別平衡處理

在處理極度不平衡的分類樣本時,可以考慮以下幾種方法: 欠采樣(Undersampling):從多數類別中隨機選擇一部分樣本,使得多數類別的樣本數量與少數類別的樣本數量相近。這種方法的優點是簡單快捷,但可能會丟失一些有用信息。

過采樣(Oversampling):從少數類別中隨機復制一些樣本,使得少數類別的樣本數量與多數類別的樣本數量相近。這種方法的優點是可以充分利用數據集,但可能會導致過擬合。

SMOTE(Synthetic Minority Over-sampling Technique)算法:是一種常用的過采樣方法,它通過對少數類別樣本進行插值生成新的樣本來擴充數據集。這種方法可以有效地避免過擬合問題。

混合采樣(Mixed Sampling):結合欠采樣和過采樣的優點,既可以減少數據量,又可以充分利用數據集。可以先進行欠采樣,然后再對欠采樣后的數據進行過采樣。

我們首先對樣本少的進行上采樣

from imblearn.over_sampling import RandomOverSampler os=RandomOverSampler(sampling_strategy=0.0025) X_train_ns,y_train_ns=os.fit_resample(data,y) print("The number of classes before fit {}".format(y.value_counts().to_dict())) print("The number of classes after fit {}".format(y_train_ns.value_counts().to_dict()))

?

將y為1的樣本增加到599個

再對樣本多的進行下采樣,比例為0.2,即0類數量8成,1類數量2成。雖然也不平衡,但是比剛剛那個好多了。。也能訓練了。

from imblearn.under_sampling import RandomUnderSampler rus = RandomUnderSampler(sampling_strategy=0.2) X_resampled, y_resampled = rus.fit_resample(X_train_ns, y_train_ns) X_train_ns2,y_train_ns2=rus.fit_resample(X_train_ns,y_train_ns) print("The number of classes before fit {}".format(y_train_ns.value_counts().to_dict())) print("The number of classes after fit {}".format(y_train_ns2.value_counts().to_dict()))

?查看現在的數據形狀

print(X_train_ns2.shape,y_train_ns2.shape)

一共3594個樣本,其中0類有2995條,1類有599條,x特征變量的個數有57個?


算法實現

#劃分訓練集和測試集,查看他們的形狀 from sklearn.model_selection import train_test_split X_train,X_test,y_train,y_test=train_test_split(X_train_ns2,y_train_ns2,stratify=y_train_ns2,test_size=0.2,random_state=0) print(X_train.shape,X_test.shape,y_train.shape,y_test.shape)

?

#數據標準化 from sklearn.preprocessing import StandardScaler scaler = StandardScaler() scaler.fit(X_train) X_train_s = scaler.transform(X_train) X_test_s = scaler.transform(X_test) print('訓練數據形狀:') print(X_train_s.shape,y_train.shape) print('測試數據形狀:') print(X_test_s.shape,y_test.shape)

上述代碼是先劃分訓練集和測試集,測試集的比例為20%,隨機數種子為0。然后進行數據的標準化, 打印查看訓練集數據,測試集數據的形狀。 可以看到我們有訓練集4598,測試集1150,特征變量有74個。


#采用五種模型,對比驗證集精度?

from sklearn.linear_model import LogisticRegression from sklearn.neighbors import KNeighborsClassifier from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.svm import SVC

#邏輯回歸 model1 = LogisticRegression(C=1e10,max_iter=10000)#K近鄰 model2 = KNeighborsClassifier(n_neighbors=10)#決策樹 model3 = DecisionTreeClassifier(random_state=77)#隨機森林 model4= RandomForestClassifier(n_estimators=1000, max_features='sqrt',random_state=10)#支持向量機 model5 = SVC(kernel="rbf", random_state=77)model_list=[model1,model2,model3,model4,model5] model_name=['Logistic Regression', 'K-Nearest Neighbors', 'Decision Tree', 'Random Forest','Support Vector Machine']

評價標準

本文是一個分類問題,采用四個分類問題常用而且可靠的評價指標,準確率、精確度、召回率和F1值對模型進行全面的評價。四個指標的計算公式如下

計算所有評價指標,定義評估函數

from sklearn.metrics import confusion_matrix from sklearn.metrics import classification_report from sklearn.metrics import cohen_kappa_score from sklearn.model_selection import KFold def evaluation(y_test, y_predict):accuracy=classification_report(y_test, y_predict,output_dict=True)['accuracy']s=classification_report(y_test, y_predict,output_dict=True)['weighted avg']precision=s['precision']recall=s['recall']f1_score=s['f1-score']#kappa=cohen_kappa_score(y_test, y_predict)return accuracy,precision,recall,f1_score #, kappa def evaluation2(lis):array=np.array(lis)return array.mean() , array.std() df_eval=pd.DataFrame(columns=['Accuracy','Precision','Recall','F1_score']) for i in range(5):model_C=model_list[i]name=model_name[i]print(f'{name}模型擬合完成')model_C.fit(X_train_s, y_train)pred=model_C.predict(X_test_s)s=classification_report(y_test, pred)s=evaluation(y_test,pred)df_eval.loc[name,:]=list(s)

df_eval

?

bar_width = 0.4 colors=['c', 'b', 'g', 'tomato', 'm', 'y', 'lime', 'k','orange','pink','grey','tan'] fig, ax = plt.subplots(2,2,figsize=(10,8),dpi=128) for i,col in enumerate(df_eval.columns):n=int(str('22')+str(i+1))plt.subplot(n)df_col=df_eval[col]m =np.arange(len(df_col))plt.bar(x=m,height=df_col.to_numpy(),width=bar_width,color=colors)#plt.xlabel('Methods',fontsize=12)names=df_col.indexplt.xticks(range(len(df_col)),names,fontsize=10)plt.xticks(rotation=40)plt.ylabel(col,fontsize=14)plt.tight_layout() #plt.savefig('柱狀圖.jpg',dpi=512) plt.show()

?

?可以看到上面隨機森林模型效果最好


下面對隨機森林模型進一步進行超參數搜索

#利用K折交叉驗證搜索最優超參數 from sklearn.model_selection import KFold, StratifiedKFold from sklearn.model_selection import GridSearchCV,RandomizedSearchCV

管道流,網格化搜索?

from sklearn.pipeline import Pipeline steps = [('standardize', StandardScaler()), ('model',RandomForestClassifier(max_features='sqrt',random_state=10) ) ]RF_pipe = Pipeline( steps = steps )param_distributions = {'model__max_depth': range(2, 9),'model__n_estimators': [250,500,750,1000,1500,2000]}model= GridSearchCV( RF_pipe, param_distributions, n_jobs = 6, cv = KFold(n_splits=3, shuffle=True, random_state=0) )

查看這個管道里面的參數

RF_pipe.get_params()['model'].get_params().keys()

擬合模型?

model.fit(X_train,y_train)

?

#查看模型最好的參數和準確率 print(f" best param: {model.best_params_},accuary:{model.best_score_}" )

#將最好的參數賦值給模型 model = model.best_estimator_ pred=model.predict(X_test_s) s=evaluation(y_test,pred) print(f'Acc: {s[0]}, Prec: {s[1]}, Recall: {s[2]}, F1:{s[3]}')

?

#準確率、精確度、召回率和F1值

RF_s=evaluation(model.predict(data),y) RF_s

?


?結論

模型的比較等等,在這個分類問題上,隨機森林效果最好,其次是支持向量機和邏輯回歸

本案例的局限性在于y取值為1的數據樣本量太少,上采樣多了可能會導致模型過擬合等等

?變量重要性

#使用所有數據訓練 model=RandomForestClassifier(max_depth= 8,n_estimators=2000,max_features='sqrt',random_state=10) #使用前面的最優參數 model.fit(np.array(data),y) pred=model.predict(np.array(data)) s=evaluation(y,pred) print(f'Acc: {s[0]}, Prec: {s[1]}, Recall: {s[2]}, F1:{s[3]}')

n=10 sorted_index = model.feature_importances_.argsort()[::-1][:n] mfs=model.feature_importances_[sorted_index][:n] plt.figure(figsize=(5,4),dpi=128) sns.barplot(y=np.array(range(len(mfs))),x=mfs,orient='h') plt.yticks(np.arange(data.shape[1])[:n], data.columns[sorted_index][:n]) plt.xlabel('Feature Importance') plt.ylabel('Feature') plt.title('LGBM') plt.show()

?

可以看到,PEDCOUNT,COLLISIONTYPE_Pedesttain等變量對于響應變量y的影響程度高,說明這個幾個變量對交通事故有顯著性影響

應該控制這幾個變量,來減少交通事故的嚴重程度

總結

以上是生活随笔為你收集整理的Python数据分析案例28——西雅图交通事故预测(不平衡样本处理)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。