# 模型验è¯(ModelValidation) 模型验è¯å°±æ˜¯å½“选择了模型和超å‚æ•°åŽï¼Œé€šè¿‡å¯¹è®ç»ƒæ•°æ®è¿›è¡Œå¦ä¹ ,对比模型对已知数æ®çš„预测值和实际值的差è·ã€‚ 然åŽæ ¹æ®ä¸åŒçš„å·®è·ï¼Œè¿›è¡Œè°ƒæ•´ï¼Œé€‰æ‹©ã€‚ ## é”™è¯¯çš„æ¨¡åž‹éªŒè¯ æ¨¡åž‹éªŒè¯éœ€è¦å¯¹æ•°æ®é›†è¿›è¡Œé€‰æ‹©åˆ†ç±»ï¼Œå¦‚果使用è®ç»ƒé›†è¿›è¡ŒéªŒè¯æˆ–者错误的数æ®é›†åˆ†ç±»ï¼Œåˆ™å¯èƒ½å¯¼è‡´é”™è¯¯ç»“论。 上é¢çš„鸢尾花例å就说典型的错误结论,一般很少出现验è¯ç»“果完全æ£ç¡®çš„情况,事出å常必有妖,å°å¿ƒï¼ï¼ï¼ 通过检查代ç 我们å‘现,上é¢é¸¢å°¾èŠ±å‡ºçŽ°ç™¾åˆ†ç™¾æ£ç¡®çš„情况主è¦é—®é¢˜æ˜¯ï¼Œæˆ‘们è®ç»ƒæ¨¡åž‹ç”¨çš„æ•°æ®å’Œæµ‹è¯•æ¨¡åž‹ç”¨çš„æ•°æ® æ˜¯åŒä¸€æ‰¹æ•°æ®ï¼Œç»ƒä¹ 题居然和考试题是一套,怪ä¸å¾—äººäººéƒ½æ‰“æ»¡åˆ†ï¼Œè¿™æ ·æ˜¯ä¸è¡Œçš„。 ## 模型验è¯çš„æ£ç¡®æ–¹æ³•ï¼šç•™å‡ºé›†(HoldOut) 为了解决上é¢è€ƒè¯•é¢˜å’Œç»ƒä¹ 题åŒä¸€å¥—的问题,å³ä¸ºäº†æ›´å®¢è§‚的评估å¦ç”Ÿçš„æˆç»©ï¼Œæœ€ç®€å•çš„办法就是考试题ä¸èƒ½ä½¿å¹³æ—¶çš„è®ç»ƒé¢˜ï¼Œæˆ‘们在 评估结果的时候,使用的数æ®é›†ä¸èƒ½æ˜¯è®ç»ƒçš„æ•°æ®é›†ï¼Œè¿™æ ·å°±éœ€è¦åœ¨å¯»æ¥å¼€å§‹å¯¹æ€»æ•°æ®é›†è¿›è¡Œåˆ†ç±»ï¼Œä¸€éƒ¨åˆ†ç”¨æ¥è®ç»ƒï¼Œ 一部分用æ¥éªŒè¯ã€‚ 用æ¥è€ƒè¯•çš„题需è¦ä»Žç»ƒä¹ 题ä¸é¢„先留出æ¥ï¼Œæˆ‘们把这类数æ®é›†å«åšç•™å‡ºé›†ã€‚ æ•°æ®é›†å¯ä»¥æ‰‹åŠ¨åˆ†å‡ºï¼Œä½†æ‰‹åŠ¨åˆ†å˜åœ¨ç€è®¸å¤šé—®é¢˜ï¼Œå¸¸è§çš„比如分出的数æ®ä¸ç§‘å¦ä¸å®¢è§‚,我们一般使用sklearn给我们æ供的分类工具。 Sklear也为我们æ供了相应的工具,用æ¥åˆ†ç±»æ•°æ®é›†ï¼š `train_test_split` ```python # 导入数æ®é›†åˆ†ç±»å·¥å…· # sklearn 0.2 y以上版本移入model_selectionåŒ…ä¸ # from sklearn.cross_validation import train_test_split from sklearn.model_selection import train_test_split #è®ç»ƒé›†å’Œæµ‹è¯•é›†å„å 50% X1, X2, y1, y2 = train_test_split(X, y, random_state=0, train_size=0.5) #使用一部分用æ¥è®ç»ƒ model.fit(X1, y1) # 使用å¦ä¸€éƒ¨åˆ†æµ‹è¯• y2_model = model.predict(X2) #对留出集的预测åŽçš„结果和原æ¥çœŸå®žå€¼è¿›è¡Œå¯¹æ¯” rst = accuracy_score(y2, y2_model) print("模型准确率:{}ï¼…".format(rst * 100)) ``` 模型准确率:90.66666666666666ï¼… ## 交å‰éªŒè¯ 如果使用留出集测试,得出的结果是值得信赖的,但也有一个缺点,模型失去了一部分è®ç»ƒçš„计划, å³æˆ‘们把原æ¥ç”¨æ¥è®ç»ƒçš„æ•°æ®æ‹¿æ¥æµ‹è¯•äº†ï¼Œè¿™å¯èƒ½å¯¼è‡´ç»“果并ä¸æ˜¯æœ€ä¼˜ç»“果,特别是对è®ç»ƒé›†è§„模比较å°çš„时候, 甚至å¯èƒ½ä¼šå¯¼è‡´é”™è¯¯ç»“果。 解决这一问题的方法是交å‰éªŒè¯ï¼Œä¹Ÿå°±æ˜¯ä¸€ç»„æ‹Ÿåˆï¼Œè®©æ•°æ®çš„æ¯ä¸ªå集å³æ˜¯è®ç»ƒé›†åˆæ˜¯éªŒè¯é›†åˆ,方法如下: - 计算总共分为两轮 - 第一轮X1为è®ç»ƒé›†ï¼ŒX2是测试集 - 第二轮X2为è®ç»ƒé›†ï¼ŒX1是测试集 è¿™æ ·è™½ç„¶å¤šäº†ä¸€è½®å·¥ä½œï¼Œä½†ä½¿æ¨¡åž‹å¾—åˆ°äº†å……åˆ†è®ç»ƒã€‚ ```python #这里用两轮验è¯ï¼Œè½®æµç”¨ä¸€èˆ¬æ•°æ®ä½œä¸ºç•™å‡ºé›† y2_model = model.fit(X1, y1).predict(X2) y1_model = model.fit(X2, y2).predict(X1) rst1 = accuracy_score(y1, y1_model) rst2 = accuracy_score(y2, y2_model) print("模型1准确率:{}ï¼…".format(rst1 * 100)) print("模型2准确率:{}ï¼…".format(rst2 * 100)) ``` 模型1准确率:96.0ï¼… 模型2准确率:90.66666666666666ï¼… 以上交å‰éªŒè¯å…±è¿›è¡Œäº†ä¸¤è½®ï¼Œæœ€ç»ˆç»“æžœå¯ä»¥æŠŠä¸¤æ¬¡ç»“åˆè®¡ç®—,比如求平å‡å€¼ï¼Œç§°ä¸ºä¸¤è½®äº¤å‰éªŒè¯ã€‚ 对两轮交å‰éªŒè¯çš„概念å¯ä»¥æ‰©å±•ï¼Œæ¯”如五轮交å‰éªŒè¯ï¼Œå³æ¯æ¬¡é€‰å– 20% ä½œä¸ºç•™å‡ºé›†ï¼Œè¿™æ ·å¯ä»¥è¿›è¡Œäº”轮。 或者å¯ä»¥ç†è§£æˆåˆ†æˆäº”ç‰ä»½ï¼Œæ¯æ¬¡ä¸€ä»½(20%)用æ¥ä½œä¸ºç•™å‡ºé›†ï¼Œå…¶ä½™å››ä»½ä½œä¸ºè®ç»ƒé›†ã€‚ ```python # sklearn 0.2 以åŽç‰ˆæœ¬ç§»å…¥model_selection包 # from sklearn.cross_validation import cross_val_score from sklearn.model_selection import cross_val_score # sklearn.model_selection.cross_val_score(estimator, X, y=None, # scoring=None, cv=None, # n_jobs=1, verbose=0, # fit_params=None, # pre_dispatch=‘2*n_jobs’) # estimator:数æ®å¯¹è±¡ # Xï¼šæ•°æ® # yï¼šé¢„æµ‹æ•°æ® # soring:调用的方法 # cv:交å‰éªŒè¯ç”Ÿæˆå™¨æˆ–å¯è¿ä»£çš„次数 # n_jobs:åŒæ—¶å·¥ä½œçš„cpu个数(-1代表全部) # verbose:详细程度 # fit_paramsï¼šä¼ é€’ç»™ä¼°è®¡å™¨çš„æ‹Ÿåˆæ–¹æ³•çš„å‚æ•° # pre_dispatch:控制并行执行期间调度的作业数é‡ã€‚å‡å°‘这个数é‡å¯¹äºŽé¿å…在CPUå‘é€æ›´å¤šä½œä¸šæ—¶CPU内å˜æ¶ˆè€—的扩大是有用的。该å‚æ•°å¯ä»¥æ˜¯ï¼š # - 没有,在这ç§æƒ…况下,所有的工作立å³åˆ›å»ºå¹¶äº§ç”Ÿã€‚将其用于轻é‡çº§å’Œå¿«é€Ÿè¿è¡Œçš„作业,以é¿å…由于按需产生作业而导致延迟 # - 一个intï¼Œç»™å‡ºæ‰€äº§ç”Ÿçš„æ€»å·¥ä½œçš„ç¡®åˆ‡æ•°é‡ # - 一个å—符串,给出一个表达å¼ä½œä¸ºn_jobs的函数,如'2 * n_jobs' rst = cross_val_score(model, X, y, cv=5) print("模型准确率:{}".format(rst * 100)) ``` 模型准确率:[ 96.66666667 96.66666667 93.33333333 93.33333333 100. ] è¿™ç§æŠŠæ•°æ®åˆ†æˆï¼®ä»½ï¼Œä¸€ä»½ä½œä¸ºç•™å‡ºé›†ï¼Œå…¶ä»–用æ¥è®ç»ƒçš„交å‰éªŒè¯ç±»åž‹å«LOO(LeaveOneOut)交å‰éªŒè¯ã€‚ æžç«¯æƒ…况下我们å¯ä»¥æŠŠæ•´ä¸ªæ•°æ®é›†æ¯ä¸ªæ•°æ®ä½œä¸ºä¸€ä¸ªé›†åˆï¼Œæ¯æ¬¡æ‹¿å‡ºä¸€ä¸ªæ•°æ®ä½œä¸ºç•™å‡ºé›†ã€‚ ```python from sklearn.model_selection import LeaveOneOut, cross_val_score scores = cross_val_score(model, X, y, cv=LeaveOneOut()) print("验è¯åˆ†æ•°æ€»å…±ï¼š{}".format(scores)) #æ¯æ¬¡ç»“果求å‡å€¼ä½œä¸ºæœ€ç»ˆç»“æžœ print("\n最终验è¯ç»“果:{}".format(scores.mean())) ``` 验è¯åˆ†æ•°æ€»å…±ï¼š[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] 最终验è¯ç»“果:0.96