zoukankan      html  css  js  c++  java
  • 机器学习实战-logistic回归分类

    基于LR的回归分类实例

    概念

    前提理解:

    机器学习的三个步骤:模型,损失函数(即样本误差),优化求解(通过损失函数,使得模型的样本误差最小或小于阈值,求出满足条件的参数,优化求解包括:最小二乘法,梯度下降)。

    链接1:简析python3深浅复制与赋值

    https://cloud.tencent.com/developer/news/53299

    Python3中赋值操作其实是对象的引用,相当于起了个别名,赋值关系,即整个内外层对象的引用,内外层都指向同一内存。

    链接2SGD详解

    https://www.cnblogs.com/NeilZhang/p/8454890.html

    实例说明

    基于LR的回归分类实例,特征抽取使用TF-IDF,模型优化采用SGD.

    模型:LR模型

    损失函数:均方误差

    优化求解:SGD,迭代50次

    输入:TF-IDF的词频

    输出:0,1

    数据集样例

    train目录:

    【train_neg.txt】

    不要 怕 恶庄 自寻 棺材 睡

    走 咯 拜拜

    大家 说 说 找操 科技 ( 兆 日 科技 ) 这波 能 跌 到 多少

    每 一次 反弹 都 是 逃命 的 机会 不要 抱 任何 幻想

    抛 ! 机构 连拉 股价 制造 概念 用 人性 贪婪 忽悠 小股民 在 高位 接货 333

    垃圾股

    18 71 , , 20000 股 跌 吧 黑庄

    兆 日 科技 跌停 控股 股东 拟 大幅 减持

    今天 是 老子 买入 你整 半年 时间 狗日 的 … … 27 3

    【train_pos.txt】

    兆 日 科技 抄 家伙 满仓 买进 干

    哇 日日 大涨 了 呀 呵呵 呵 吻 啊 日日 使劲

    前来 入住

    涨停 涨停 涨停 涨停 涨停 涨停 涨停 涨停 涨停 涨停 涨停 涨停 涨停

    今天 涨停

    兆 跌 科技 有望 了

    我 预测 这是 最后 一波 诱空 洗盘 该股 下跌 过程 中日 线 和 周线 的 kdj 均 未 创新 低 一旦 反弹

    19 65 老夫 已 满仓 买入 坐等 拉升 哈哈 !

    差不多 了 再 跌进 不了 深港 通 了 60 亿 底线 市值

    主力 拉高 再 出货 没 子弹 就 说

    老子 还要 持股 过节

    有 涨停 就 有 跌停 所以 很 正常 周一 拉红 是 肯定 的 星期二 的 操作 就要 多方面 考虑 了

    便宜货 我 先拣点

    test目录同train目录

    【stopwords.txt】

    你 等 我 吗 在 股价 股市 科技 股友 兆日 最后 今天 明天 公告 一个 还 已 发行价 做 月 到 还是 得 估计 谁 啊 可能 的 可以 来 。 。。 , ! 了 的 地 ? 就是 应该 明天 下午 上午 早上 晚上 你 等 我 吗 在 股价 股市 科技 股友 兆日 ——— 》), )÷(1- ", )、 =( : → ℃ & * 一一 ~~~~ ' . 『 .一 ./ -- 』 =″ 【 [*] }> [⑤]] [①D] c] ng昉 * // [ ] [②e] [②g] ={ } ,也 ' A [①⑥] [②B] [①a] [④a] [①③] [③h] ③] 1. -- [②b] '' ××× [①⑧] 0:2 =[ [⑤b] [②c] [④b] [②③] [③a] [④c] [①⑤] [①⑦] [①g] ∈[ [①⑨] [①④] [①c] [②f] [②⑧] [②①] [①C] [③c] [③g] [②⑤] [②②] 一. [①h] .数 [] [①B] 数/ [①i] [③e] [①①] [④d] [④e] [③b] [⑤a] [①A] [②⑧] [②⑦] [①d] [②j] 〕〔 ][ :// ′∈ [②④ [⑤e] 12% b] ... ................... …………………………………………………③ ZXFITL [③F] 」 [①o] ]∧′=[ ∪φ∈ ′| {- ②c } [③①] R.L. [①E] Ψ -[*]- ↑ .日 [②d] [② [②⑦] [②②] [③e] [①i] [①B] [①h] [①d] [①g] [①②] [②a] f] [⑩] a] [①e] [②h] [②⑥] [③d] [②⑩] e] 〉 】 元/吨 [②⑩] 2.3% 5:0 [①] :: [②] [③] [④] [⑤] [⑥] [⑦] [⑧] [⑨] …… —— ? 、 。 " " 《 》 ! , : ; ? . , . ' ? · ——— ── ? — < > ( ) 〔 〕 [ ] ( ) - + ~ × / / ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ Ⅲ В " ; # @ γ μ φ φ. × Δ ■ ▲ sub exp sup sub Lex # % & ' + +ξ ++ - -β < <± <Δ <λ <φ << = = =☆ =- > >λ _ ~± ~+ [⑤f] [⑤d] [②i] ≈ [②G] [①f] LI ㈧ [- ...... 〉 [③⑩] 第二 一番 一直 一个 一些 许多 种 有的是 也就是说 末##末 啊 阿 哎 哎呀 哎哟 唉 俺 俺们 按 按照 吧 吧哒 把 罢了 被 本 本着 比 比方 比如 鄙人 彼 彼此 边 别 别的 别说 并 并且 不比 不成 不单 不但 不独 不管 不光 不过 不仅 不拘 不论 不怕 不然 不如 不特 不惟 不问 不只 朝 朝着 趁 趁着 乘 冲 除 除此之外 除非 除了 此 此间 此外 从 从而 打 待 但 但是 当 当着 到 得 的 的话 等 等等 地 第 叮咚 对 对于 多 多少 而 而况 而且 而是 而外 而言 而已 尔后 反过来 反过来说 反之 非但 非徒 否则 嘎 嘎登 该 赶 个 各 各个 各位 各种 各自 给 根据 跟 故 故此 固然 关于 管 归 果然 果真 过 哈 哈哈 呵 和 何 何处 何况 何时 嘿 哼 哼唷 呼哧 乎 哗 还是 还有 换句话说 换言之 或 或是 或者 极了 及 及其 及至 即 即便 即或 即令 即若 即使 几 几时 己 既 既然 既是 继而 加之 假如 假若 假使 鉴于 将 较 较之 叫 接着 结果 借 紧接着 进而 尽 尽管 经 经过 就 就是 就是说 据 具体地说 具体说来 开始 开外 靠 咳 可 可见 可是 可以 况且 啦 来 来着 离 例如 哩 连 连同 两者 了 临 另 另外 另一方面 论 嘛 吗 慢说 漫说 冒 么 每 每当 们 莫若 某 某个 某些 拿 哪 哪边 哪儿 哪个 哪里 哪年 哪怕 哪天 哪些 哪样 那 那边 那儿 那个 那会儿 那里 那么 那么些 那么样 那时 那些 那样 乃 乃至 呢 能 你 你们 您 宁 宁可 宁肯 宁愿 哦 呕 啪达 旁人 呸 凭 凭借 其 其次 其二 其他 其它 其一 其余 其中 起 起见 起见 岂但 恰恰相反 前后 前者 且 然而 然后 然则 让 人家 任 任何 任凭 如 如此 如果 如何 如其 如若 如上所述 若 若非 若是 啥 上下 尚且 设若 设使 甚而 甚么 甚至 省得 时候 什么 什么样 使得 是 是的 首先 谁 谁知 顺 顺着 似的 虽 虽然 虽说 虽则 随 随着 所 所以 他 他们 他人 它 它们 她 她们 倘 倘或 倘然 倘若 倘使 腾 替 通过 同 同时 哇 万一 往 望 为 为何 为了 为什么 为着 喂 嗡嗡 我 我们 呜 呜呼 乌乎 无论 无宁 毋宁 嘻 吓 相对而言 像 向 向着 嘘 呀 焉 沿 沿着 要 要不 要不然 要不是 要么 要是 也 也罢 也好 一 一般 一旦 一方面 一来 一切 一样 一则 依 依照 矣 以 以便 以及 以免 以至 以至于 以致 抑或 因 因此 因而 因为 哟 用 由 由此可见 由于 有 有的 有关 有些 又 于 于是 于是乎 与 与此同时 与否 与其 越是 云云 哉 再说 再者 在 在下 咱 咱们 则 怎 怎么 怎么办 怎么样 怎样 咋 照 照着 者 这 这边 这儿 这个 这会儿 这就是说 这里 这么 这么点儿 这么些 这么样 这时 这些 这样 正如 吱 之 之类 之所以 之一 只是 只限 只要 只有 至 至于 诸位 着 着呢 自 自从 自个儿 自各儿 自己 自家 自身 综上所述 总的来看 总的来说 总的说来 总而言之 总之 纵 纵令 纵然 纵使 遵照 作为 兮 呃 呗 咚 咦 喏 啐 喔唷 嗬 嗯 嗳

    附代码

    #coding=utf-8
    '''
    基于LR的回归分类实例,特征抽取使用IF-IDF,模型优化采用SGD.
    
    模型:LR模型
    损失函数:均方误差
    优化求解:SGD,迭代50次
    
    输入:IF-IDF的词频
    输出:0,1
    '''
    import os
    import math
    import random
    class LR_Uni_Bi:
        def __init__(self, train_dir, test_dir, alpha=0.01):
            #初始化,设置文件目录及算法学习速率
            self.train_dir = train_dir
            self.test_dir = test_dir
            self.alpha = alpha
            #字典
            self.dic ={}
        def loadStopWords(self):
            for line in open('./stopwords.txt'):
                doc = line.split()
                # print(doc)
                #集合(set)是一个无序的不重复元素序列
                self.stopwords = set(doc)
                
            # print(self.stopwords)
    
        def buildUnigram(self,min1=0,sw1 =True):
    
            '''
            定义一元词袋模型
            '''
            #临时变量,存储unigram的次数,用于min-count过滤
            temp_dic = {}
            for fname in os.listdir(self.train_dir):
                for line in open(os.path.join(self.train_dir, fname)):
                    for token in line.split():
                        if token not in temp_dic:
                            temp_dic[token]=1
                        else:
                            temp_dic[token] +=1
    
            #临时变量,存储过滤后的词语
            temp_set = set()
            for word in temp_dic:
                if temp_dic[word] > min1:
                    temp_set.add(word)
    
            if sw1:
                self.loadStopWords()
                #两个集合求差集,对数据进行过滤
                temp_set -= self.stopwords
    
            count = 0
            for word in temp_set:
                self.dic[word] = count
                count += 1
            print('unigram',len(self.dic))
    
        def buildBigram(self,min2 = 5, sw2 =True):
            '''
            构造二元词袋模型,以词的个数为标准,而不是词的长度。 ('一段时间', '主力')
            '''
            #临时变量,用于存储bigram的次数,用于min-count过滤
            self.gram2 ={}
            for fname in os.listdir(self.train_dir):
                for line in open(os.path.join(self.train_dir,fname)):
                    doc = line.split()
                    # print(doc)
                    for i in range(len(doc) - 1):
                        t = tuple(doc[i:i+2])
                        if t not in self.gram2:
                            self.gram2[t] = 1
                        else:
                            self.gram2[t] += 1
            # print(self.gram2)
            #python中单引号和双引号组合使用,来避免使用转义字符
            print('original bigram', len(self.gram2))
            remove_set = set()
    
            for g in self.gram2:
                if self.gram2[g] <= min2:
                    remove_set.add(g)
                if sw2:
                    if g[0] in self.stopwords and g[1] in self.stopwords:
                        remove_set.add(g)
    
            for g in remove_set:
                del self.gram2[g]
            print('bigram min-count -%d %d'%(min2,len(self.gram2)))
            #经过一元词袋模型后,当前字典的纬度,表示有效的unigram的个数
            self.uni_count = len(self.dic)
            count = self.uni_count
            for g in self.gram2:
                self.dic[g] =count
                count += 1
            print('bigram',len(self.dic) - self.uni_count)
            # print(self.dic)
        def buildDic(self, min1 = 0, min2 = 0 , sw1 = True,sw2 = True):
            #构建一词模型和两词模型
            self.buildUnigram(min1=min1,sw1=sw1)
            self.buildBigram(min2=min2,sw2=sw2)
    
        def getlabel(self):
            '''
            提取训练数据的标签
            '''
            self.train_label = [ ]
            for fname in os.listdir(self.train_dir):
                if fname == 'train_neg.txt':
                    label = 0
                else:
                    label = 1
                for line in open(os.path.join(self.train_dir,fname)):
                    self.train_label.append(label)
            # print(self.train_label)
    
            self.test_label = []
            for fname in os.listdir(self.test_dir):
                if fname =='test_neg.txt':
                    label = 0
                else:
                    label = 1
                for line in open(os.path.join(self.test_dir,fname)):
                    self.test_label.append(label)
            # print(self.test_label)
    
        def setLog(self,log_dir):
            #设置日志数据的文件目录
            self.log_dir = log_dir
            #训练数据日志
            self.fw_train = open(self.log_dir + '/train_log.txt','w')
    
            #测试数据日志
            self.fw_test = open(self.log_dir + '/test_log.txt','w')
    
        def buildDocsTFIDF(self,dir):
            #文件词频
            idf={}
            docs = []
            #unigram对应的各个文档的有效长度
            docs_length1 = []
            #bigram对应的各个文件的有效长度
            docs_length2 = []
            for fname in os.listdir(dir):
                num = 0
                for line in open(os.path.join(dir,fname)):
                    # print(docs)
                    docs.append({})
                    # print(docs)
                    doc = line.split()
                    count1 = 0
                    count2 = 0
                    temp_set =set()
                    for word in doc:
                        if word in self.dic:
                            idx = self.dic[word]
                            # print(idx)
                            count1 += 1
                            temp_set.add(idx)
                            # print(temp_set)
    
                            if idx not in docs[-1]:
                                docs[-1][idx] = 1
                            else:
                                docs[-1][idx] += 1
                            # print(docs)
    
                    for i in range(len(doc) - 1):
                        t = tuple(doc[i:i+2])
                        if t in self.dic:
                            count2 +=1
                            idx = self.dic[t]
                            temp_set.add(idx)
    
                            if idx not in docs[-1]:
                                docs[-1][idx] = 1
                            else:
                                docs[-1][idx] += 1
                    #统计包含词w的文档数目
                    for idx in temp_set:
                        if idx not in idf:
                            idf[idx] = 1
                        else:
                            idf[idx] += 1
    
                    docs_length1.append(count1)
                    docs_length2.append(count2)
    
    
            #语料库中的文档总数
            N = len(docs)+0.0
            for idx in idf:
                idf[idx] = math.log(N / idf[idx])
    
    
    
            # print(docs)
            #计算词频-逆向文件频率
            for i in range(len(docs)):
    
                #赋值操作,相当于另起别名,实质是整个内外层对象的引用。详细参考python3的深浅拷贝和赋值
                doc = docs[i]
                # print(doc)
                # print(docs[i])
                for idx in doc:
                    if idx<self.uni_count:
                        doc[idx] = doc[idx] / (docs_length1[i] + 0.0)* idf[idx]
                    else:
                        doc[idx] = doc[idx] / (docs_length2[i] + 0.0)* idf[idx]
                # print(doc)
                # print(docs[i])
                # exit()
    
                    # print(docs)
                    # num += 1
                    # if num ==2:
                    #      exit()
            # for doc in docs:
            #     print(doc)
            #     exit()
            return docs
    
        def initTheta(self):
            '''
            随机初始化theta
            '''
            self.theta = []
            for i in range(len(self.dic)):
                self.theta.append(random.random())
    
        def sigmoid(self,x):
            '''
            sigmoid function
            '''
            return 1.0/(1+math.exp(-x))
    
        def SGD(self, iter, train_f, test_f):
            '''
            Stochastic Gradient Descent
            '''
            #随机初始化theta
            self.initTheta()
            #start SGD
            for j in range(iter):
                sample = random.sample(range(len(train_f)), len(train_f))
                for i in sample:
                    thetaX = 0
                    x = train_f[i]
                    for idx in x:
                        thetaX += self.theta[idx] * x[idx]
                    #LR回归求解预测值,Loggstic Regression
                    h = self.sigmoid(thetaX)
    
                    #损失函数的求导步骤求误差,用于迭代跟新thetaX
                    error = self.train_label[i] - h
    
                    #SGD更新迭代跟新参数thetaX
                    for idx in x:
                        self.theta[idx] = self.theta[idx]+ (self.alpha*error*x[idx])
    
                    print('iter %d' % j)
                    print('alpha',self.alpha)
    
            test_acc = self.test(train_f,test_f)
            print('test_acc',test_acc)
        def test(self,train_f, test_f):
            '''
            测试
            '''
            correct = 0
            for i in range(len(train_f)):
                x = train_f[i]
                thetaX = 0
                for idx in x:
                    thetaX += self.theta[idx] * x[idx]
                h = self.sigmoid(thetaX)
                #临时变量,暂存预测的文章的类型
                y = 0
                if h > 0.5:
                    y = 1
                #统计预测正确的数目
                if y == self.train_label[i]:
                    correct += 1
            #计算预测的准确值
            train_acc = correct /(len(train_f) + 0.0)
    
            print('6-1 training acc', train_acc)
            self.fw_train.write(str(train_acc))
            self.fw_train.write('
    ')
    
            correct = 0
            for i in range(len(test_f)):
                x = test_f[i]
                thetaX = 0
                for idx in x:
                    thetaX += self.theta[idx] * x[idx]
                h = self.sigmoid(thetaX)
                y = 0
                if h > 0.5:
                    y = 1
                if y == self.test_label[i]:
                    correct += 1
            test_acc = correct /(len(test_f) + 0.0)
            print('6-1 test acc', test_acc)
            self.fw_test.write(str(test_acc))
            self.fw_test.write('
    ')
    
            return test_acc
    
        def closeFw(self):
            self.fw_test.close()
            self.fw_train.close()
    
        def writeGramTable(self):
            '''
            输出保存词表及其权重
            '''
            self.fw_grams = open(self.log_dir + '/words.txt', 'w')
            gram_weight = {}
    
            for g in self.dic:
                #判断对象的变量类型
                if isinstance(g,tuple):
                    str = g[0]+' ' +g[1]
                else:
                    str =g
                gram_weight[str] = self.theta[self.dic[g]]
            sort = sorted(gram_weight.items(), key=lambda e: e[1], reverse=False)
            #按值排序
            for(gram, weight) in sort:
                self.fw_grams.write(gram)
                self.fw_grams.write(' ')
                self.fw_grams.write('%.3f' %weight)
                self.fw_grams.write('
    ')
            self.fw_grams.close()
    
    
        def writeResults(self, test_f):
            '''
            输出分类结果
            '''
            self.fw_res = open(self.log_dir+'results.txt','w')
            for i in range(len(test_f)):
                x = test_f[i]
                thetaX = 0
                for idx in x:
                    thetaX += self.theta[idx] * x[idx]
                h= self.sigmoid(thetaX)
    
                y = 0
                if h>0.5:
                    y = 1
                self.fw_res.write('%d' % y)
                self.fw_res.write(' ')
                self.fw_res.write('%d' % self.test_label[i])
                self.fw_res.write(' ')
    
                if y == self.test_label[i]:
                    self.fw_res.write('y')
                else:
                    self.fw_res.write('n')
                self.fw_res.write('
    ')
            self.fw_res.close()
    
        def truncateTest(self,threshold,test_f):
            '''
            截取一些小权重的词,进行测试
            '''
            correct = 0
            for i in range(len(test_f)):
                x = test_f[i]
                thetaX = 0
                for idx in x:
                    if abs(self.theta[idx]) >= threshold:
                        thetaX += self.theta[idx] * x[idx]
                h = self.sigmoid(thetaX)
                y = 0
                if h>0.5:
                    y = 1
                if y == self.test_label[i]:
                    correct += 1
            test_acc = correct / (len(self.test_docs) + 0.0)
            return test_acc
    
    
        def SGDwithTFIDF(self,iter):
            '''
            特征抽取
            用IFIDF做特征的stochastic Gradient Descent
            (HashingTF and IDF)词频-逆向文件频率,体现一个文档中词语对于语料库的重要程度。
            '''
            self.train_docs = self.buildDocsTFIDF(self.train_dir)
            # print(self.train_docs)
            print('train TFIDF',len(self.train_docs))
    
            self.test_docs = self.buildDocsTFIDF(self.test_dir)
            # print('test TFIDF',len(self.test_docs))
            # exit()
    
            #将TFIDF值进行SGD模型优化求解
            self.SGD(iter,self.train_docs,self.test_docs)
    
            #关闭文件流
            self.closeFw()
    
            #输出保存词表和权重
            self.writeGramTable()
    
            #输出分类结果
            self.writeResults(self.test_docs)
    
            '''
            截取一小段进行测试
            '''
            for i in range(600):
                threshold = i/600.0*40.0
                print('truncate threshold %f acc %f' %(threshold,self.truncateTest(threshold, self.test_docs)))
    
    
    
    if __name__ == '__main__':
    
        #数据初始化,设置输入路径
        lr = LR_Uni_Bi('./train', './test', alpha=0.5)
    
        #训练数据,特征变化,构造一元和二元语言模型
        lr.buildDic(min1=0,min2=0,sw1=True,sw2=True)
    
        #有监督训练,提取训练数据标签
        lr.getlabel()
    
        #设置输出路径
        lr.setLog('./out')
    
        #模型构建
        lr.SGDwithTFIDF(iter= 50)
  • 相关阅读:
    laravel MethodNotAllowedHttpException错误一个原因
    laravel查看执行sql的
    二维,多维数组排序array_multisort()函数的使用
    REMOTE_ADDR,HTTP_CLIENT_IP,HTTP_X_FORWARDED_FOR获取客户端IP
    学习正则笔记
    关于apidoc文档生成不了的一个原因
    laravel 表单验证 Exists 规则的基本使用方法
    laravel 500错误的一个解决办法
    关于laravel 用paginate()取值取不到的问题
    C语言寒假大作战02
  • 原文地址:https://www.cnblogs.com/smuxiaolei/p/10847353.html
Copyright © 2011-2022 走看看