python機(jī)器學(xué)習(xí)——十次交叉驗(yàn)證訓(xùn)練的數(shù)據(jù)準(zhǔn)備算法

攝于 2017年4月21日 臺(tái)灣墾丁船帆石海灘

前言

這兩天本來(lái)打算開(kāi)始寫樸素貝葉斯分類器的算法的兜叨,由于上一篇博文python實(shí)現(xiàn)貝葉斯推斷——垃圾郵件分類在實(shí)現(xiàn)時(shí),在數(shù)據(jù)劃分訓(xùn)練集和測(cè)試集的時(shí)候遇到兩個(gè)問(wèn)題猴鲫,第一是數(shù)據(jù)量太少懂缕,只有50條數(shù)據(jù),解決方法就是擴(kuò)大數(shù)據(jù)量咯坛增。第二個(gè),也是今天寫這篇博文的目的薄腻,就是在訓(xùn)練的時(shí)候轿偎,我先把數(shù)據(jù)文件進(jìn)行隨機(jī)亂序,然后抽取了亂序后前10個(gè)數(shù)據(jù)文件被廓,這個(gè)目的實(shí)際上就是為了隨機(jī)從中抽取10個(gè)數(shù)據(jù)文件作為測(cè)試集,剩下的40個(gè)數(shù)據(jù)文件作為訓(xùn)練集萝玷。這種方法在機(jī)器學(xué)習(xí)的數(shù)據(jù)準(zhǔn)備過(guò)程中是非常常見(jiàn)的嫁乘。但是,為了能夠更好的測(cè)試模型球碉,盡可能的排除外在因素的干擾蜓斧,消除偏好,同時(shí)獲得最好的精度睁冬,所以這里則引入交叉驗(yàn)證(Cross-Validation)挎春,而交叉驗(yàn)證的次數(shù)一般取10次,所以一般也叫十次交叉驗(yàn)證豆拨。從stackoverflow上找到一張圖直奋,一看即明,原圖網(wǎng)站施禾。

算法思路

如果數(shù)據(jù)量為10的倍數(shù)脚线,則分離數(shù)據(jù)是非常方便的,即直接均分十份弥搞,依次輪流存入test和train兩個(gè)文件夾中邮绿。
但是如果不是10的倍數(shù)呢渠旁?
思路如下:
1.獲取數(shù)據(jù)數(shù)量,余除10船逮,獲得余數(shù)顾腊,例如現(xiàn)在有24個(gè)數(shù)據(jù)文件,24%10=4
2.根據(jù)余數(shù)拆分?jǐn)?shù)據(jù)挖胃,即將數(shù)據(jù)拆分成20和4兩份杂靶。
3.將拆分?jǐn)?shù)據(jù)后能夠整除10的一份均分十份,即將數(shù)據(jù)量為20的數(shù)據(jù)量均分為十份冠骄,每份包含2個(gè)數(shù)據(jù)文件伪煤。
4.將余數(shù)拆分成一份一個(gè)數(shù)據(jù),然后遍歷每一份凛辣,依次一份分開(kāi)加入到第3步已經(jīng)均分好的數(shù)據(jù)中抱既,直到余數(shù)部分的數(shù)據(jù)使用完。
沒(méi)看懂扁誓?
甩圖:

2.png

這樣做的目的是盡可能達(dá)到數(shù)據(jù)均分的效果防泵,讓實(shí)驗(yàn)效果更加。

算法實(shí)現(xiàn)

前期準(zhǔn)備

數(shù)據(jù)來(lái)源

700條neg電影數(shù)據(jù)+700條pos電影數(shù)據(jù)蝗敢,共1400條數(shù)據(jù)捷泞。下一篇博客樸素貝葉斯分類器將會(huì)用到這批數(shù)據(jù)。完整數(shù)據(jù)可以在下方的github獲得寿谴。

python包

1.fwalker
2.bfile
3.numpy
4.shutil
5.os
fwalker和bfile是不是很陌生锁右?哈哈這是我自己寫的包,傳送門:python3文本讀取與寫入常用代碼讶泰、python中import自己寫的.py
當(dāng)一些代碼(如寫入寫出文本咏瑟,創(chuàng)建文件夾、統(tǒng)計(jì)詞頻)經(jīng)常需要被使用到時(shí)痪署,可以考慮下我這種方法码泞,非常方便,可以大大縮短編寫算法的周期和減少代碼量狼犯。

代碼實(shí)現(xiàn)

既然我們需要進(jìn)行十次交叉驗(yàn)證余寥,因此數(shù)據(jù)需要復(fù)制十份,則需要10個(gè)文件夾來(lái)進(jìn)行存放悯森,每個(gè)文件夾下又包含test和train數(shù)據(jù)宋舷。



代碼(寫一行代碼打一行注釋,良心啊~)

# -*- coding: utf-8 -*-
# @Date    : 2017-05-11 21:24:50
# @Author  : Alan Lau (rlalan@outlook.com)
# @Version : Python3.5

from fwalker import fun
from bfile import buildfile as bf
from random import shuffle
import numpy as np
import shutil
import os


def buildfile(output_path):
    for i in range(1, 10+1):
        # 循環(huán)新建編號(hào)1-10的文件夾瓢姻,用于存放train和test文件夾
        file_num = bf('%s\\%d' % (output_path, i))
        # 在每個(gè)編號(hào)文件夾下新建train文件夾肥缔,用于存放90%的訓(xùn)練數(shù)據(jù)
        train_file = bf('%s\\train' % file_num)
        # 在每個(gè)編號(hào)文件夾下新建test文件夾,用于存放10%的訓(xùn)練數(shù)據(jù)
        test_file = bf('%s\\test' % file_num)
    print('Data storage has been bulit!')
    return output_path


def split_ten(files):
    file_len = len(files)  # 獲取文件總數(shù)
    shuffle(files)  # 隨機(jī)打亂文件路徑列表的順序,即使python的隨機(jī)是偽隨機(jī)
    data_storage = []  # 初始化一個(gè)列表续膳,用來(lái)接收分劃分好的文件路徑
    remainder = file_len % 10  # 判斷文件數(shù)量能否直接被10整除
    if remainder == 0:  # 如果可以整除改艇,直接將數(shù)據(jù)切成10組
        np_files = np.array(files)  # 將文件路徑列表轉(zhuǎn)換成numpy
        data_storage = np_files.reshape(10, -1)  # 利用numpy的reshape來(lái)將文件路徑切分為10組
        # 比如說(shuō)現(xiàn)在有20個(gè)文件路徑
        # reshape()后得到的結(jié)果為2、2坟岔、2谒兄、2、2社付、2承疲、2、2鸥咖、2燕鸽、2,即共十份啼辣、每份包含2個(gè)文件路徑啊研。
        return data_storage
    else:  # 否則,則先切開(kāi)余數(shù)部分的文件
        np_files = np.array(files[:-1*remainder])  # 切開(kāi)余數(shù)部分的文件鸥拧,使文件數(shù)量保證能夠被10整除
        data_storage_ten = np_files.reshape(10, -1)  # 同樣利用上面的方法使用numpy切分10組文件
        # 獲取余數(shù)部分的文件列表党远,遍歷列表,盡可能的將多余的文件分散在10組文件中富弦,而不是直接加入到一個(gè)文件中
        remainder_files = (
            np.array(files[-1*remainder:])).reshape(remainder, -1)  # 使用reshape切分問(wèn)一份一組
        for i in range(0, len(remainder_files)):
            ech_dst = data_storage_ten[i]
            ech_rf = remainder_files[i]
            # 將取出來(lái)的余數(shù)內(nèi)的路徑分別加入到已經(jīng)均分好的10份的前remainder個(gè)數(shù)據(jù)當(dāng)中沟娱,比如說(shuō)現(xiàn)在有24份文件,
            # 將24拆份拆分成一個(gè)能被10整除的數(shù)和一個(gè)余數(shù)腕柜,即這里拆分成20和4济似,我們首先將拆出來(lái)的20份文件均分10份,
            # 即每份有2個(gè)文件路徑盏缤,然后砰蠢,再將剩下后面的4個(gè)文件路徑,盡可能的放入到剛剛均分好的10份數(shù)據(jù)中蛾找。
            # 因此最終拆分的結(jié)果共有十份,每份數(shù)量分別為:3赵誓、3打毛、3、3俩功、2幻枉、2、2诡蜓、2熬甫、2、2蔓罚。
            data_storage.append(np.concatenate((ech_dst, ech_rf)))
        for j in range(remainder, len(data_storage_ten)):
            # 將將剩下的沒(méi)有被余數(shù)部分加入的份加入到data_storage中
            data_storage.append(data_storage_ten[j])
        return np.array(data_storage)


def group_data(data_storage, output_path):
    for i in range(0, len(data_storage)):
        ech_path = '%s\\%d' % (output_path, i+1)  # 構(gòu)造每一份需要寫入的路徑
        ech_train_path = '%s\\train' % ech_path
        ech_test_path = '%s\\test' % ech_path
        test_paths = data_storage[i]
        move_file(test_paths, ech_test_path)
        train_paths = np.concatenate(([data_storage[:i], data_storage[i+1:]]))
        # 將剩下的訓(xùn)練部分加入到train_paths中椿肩,并且降維
        train_paths = np.concatenate((train_paths))  # 再次降維瞻颂,使其變成1維
        move_file(train_paths, ech_train_path)
        num = i+1
        print('No.%d is over!' % num)


def move_file(old_paths, new_path):
    for old_path in old_paths:
        shutil.copy2(old_path, new_path)
        flag_name = '_'.join(old_path.split('\\')[-2:])
        old_name = '%s\\%s' % (new_path, old_path.split('\\')[-1])
        new_name = '%s\\%s' % (new_path, flag_name)
        os.rename(old_name, new_name)


def main():
    file_path = r'..\data\data_of_movie'
    # file_path = r'..\data\test'
    output_path = r'..\data\tenTimesTraining'
    files = fun(file_path)
    output_path = buildfile(output_path)
    data_storage = split_ten(files)
    group_data(data_storage, output_path)


if __name__ == '__main__':
    main()

至于實(shí)驗(yàn)的結(jié)果,就是把1400條數(shù)據(jù)隨打亂郑象,輪流存入10個(gè)文件夾中贡这,并且其中的10%輪流作為測(cè)試集存入test文件中,剩下的90%則存入了train厂榛。
由于數(shù)據(jù)量大盖矫,我這里截取一小部分?jǐn)?shù)據(jù)展示。



對(duì)比沒(méi)有劃分?jǐn)?shù)據(jù)前的數(shù)據(jù)名稱會(huì)發(fā)現(xiàn)击奶,我這里還把類別的標(biāo)簽加到了每條數(shù)據(jù)的名稱中辈双。

這個(gè)算法可以使用到大多數(shù)的機(jī)器學(xué)習(xí)需要?jiǎng)澐值臄?shù)據(jù)當(dāng)中,前提只需要將不同分類的數(shù)據(jù)存在以分類命名的文件夾下即可柜砾。為了方便識(shí)別湃望,算法會(huì)提取文件夾的名稱作為標(biāo)簽名重命名每條數(shù)據(jù)。重命名格式為:標(biāo)簽_xxx.txt

所有數(shù)據(jù)以及完整代碼GITHUB

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末局义,一起剝皮案震驚了整個(gè)濱河市喜爷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌萄唇,老刑警劉巖檩帐,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異另萤,居然都是意外死亡湃密,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門四敞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)泛源,“玉大人,你說(shuō)我怎么就攤上這事忿危〈锕浚” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵铺厨,是天一觀的道長(zhǎng)缎玫。 經(jīng)常有香客問(wèn)我,道長(zhǎng)解滓,這世上最難降的妖魔是什么赃磨? 我笑而不...
    開(kāi)封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮洼裤,結(jié)果婚禮上邻辉,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好值骇,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布莹菱。 她就那樣靜靜地躺著,像睡著了一般雷客。 火紅的嫁衣襯著肌膚如雪芒珠。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天搅裙,我揣著相機(jī)與錄音皱卓,去河邊找鬼。 笑死部逮,一個(gè)胖子當(dāng)著我的面吹牛娜汁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播兄朋,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼掐禁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了颅和?” 一聲冷哼從身側(cè)響起傅事,我...
    開(kāi)封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎峡扩,沒(méi)想到半個(gè)月后蹭越,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡教届,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年响鹃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片案训。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡买置,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出强霎,到底是詐尸還是另有隱情忿项,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布城舞,位于F島的核電站轩触,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏椿争。R本人自食惡果不足惜怕膛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一熟嫩、第九天 我趴在偏房一處隱蔽的房頂上張望秦踪。 院中可真熱鬧,春花似錦、人聲如沸椅邓。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)景馁。三九已至板壮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間合住,已是汗流浹背绰精。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留透葛,地道東北人笨使。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像僚害,于是被迫代替她去往敵國(guó)和親硫椰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容