SoftMax

原理:

LR实际上是针对二分类问题的,但是SoftMax其实就是LR推广到多分类的形式。 在逻辑回归中:

$P(y=1|x)=\frac{e^{-\thetaTx}}{1+e^{-\thetaTx}}$ $P(y=0|X)=\frac{1}{1+e^{-\thetaTx}}$

那么loss function就是:

$L(\theta)=\sum_{i=1}^n{yi}log\frac{e^{-\thetaTx}}{1+e^{-\thetaTx}}+(1-yi)log\frac{1}{1+e^{-\thetaTx}}$

推广到多分类问题:

$P(y=k|x)=\frac{e^{-\theta_kTx}}{\sum_kKe^{-\theta_kTx}}$

那么loss function就变成了:

$L(\theta)=\sum_{i=1}^n{I{yi=k}}log\frac{e^{-\theta_kTx}}{1+e^{-\theta_kTx}}$

$I{yi = k}$表示当yi = k时为1,其他为0.

同样可以采用梯度下降的方式求解。

实现demo

SKlean中关于逻辑回归的多分类问题,可以选择muti参数,它是有多个二分类器组合实现的。SKlean没有实现softmax的回归分类算法。在Theano包中有SoftMax函数,用与计算公式3中的值,可以自己实现基于SoftMax的分类算法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# encoding:utf-8
"""
@version:1
@author:Chenlini
@file:softmax.py
@time:2017/6/15 11:22
"""

# coding:utf8


from theano import *
from sklearn.datasets import *
from pandas import *
from sklearn.model_selection import *
from numpy import *


class SoftMax:
    def __init__(self, Iter=1, learnrate=0.01, alpha=0.1):

        self.Iter = Iter
        self.learnrate = learnrate
        self.alpha = alpha

    def training(self, X, Y, typenum, batch_size=500):
        ##featuresnum是X的纬度,batchesnum是分区的数目
        featuresnum = X.shape[1]
        batchesnum = int(X.shape[0] / batch_size)
        ###因为在softMax中theta和x都是全局变量,所以这里应该声明为全局变量
        X = theano.shared(np.asarray(X, dtype=float))
        ###保证Y是整型的
        Y = theano.tensor.cast(theano.shared(np.asarray(Y)), 'int32')
        #x是一个矩阵,y是一个向量
        x = theano.tensor.matrix('x')
        y = theano.tensor.ivector('y')
        ##表示index是整型标量
        index = theano.tensor.lscalar()
        theta = theano.shared(value=0.001 * zeros((featuresnum, typenum),
                                                     dtype=theano.config.floatX),
                              name='theta', borrow=True)
        ###hx就是计算softmax()的值
        hx = theano.tensor.nnet.softmax(theano.tensor.dot(x, theta))
        ##这个就是loss
        cost = -theano.tensor.mean(theano.tensor.log(hx)[theano.tensor.arange(y.shape[0]), y]) + 0.5 * self.alpha * theano.tensor.sum(theta ** 2)
        #grad可以自动计算倒数
        g_theta = theano.tensor.grad(cost, theta)
        ##这里就是用一个结构保存更新的值
        updates = [(theta, theta - self.learnrate * g_theta)]
        #批量更新
        train_model = theano.function(
            inputs=[index], outputs=cost, updates=updates, givens={
                x: X[index * batch_size: (index + 1) * batch_size],
                y: Y[index * batch_size: (index + 1) * batch_size]
            }, allow_input_downcast=True
        )

        lastcostJ = np.inf
        stop = False
        epoch = 0
        costj = []
        ###总体的循环执行,当达到最大循环次数或者cost不再下降的时候结束
        while (epoch < self.Iter) and (not stop):
            epoch = epoch + 1
            for minibatch_index in range(batchesnum):
                costj.append(train_model(minibatch_index))
            if np.mean(costj) >= lastcostJ:
                print("costJ is increasing !!!")
                stop = True
            else:
                lastcostJ = np.mean(costj)
                print(('epoch %i, minibatch %i/%i,averange cost is %f') %
                      (epoch, minibatch_index + 1, batchesnum, lastcostJ))
        self.theta = theta
        return self.theta.get_value()



    def testing(self, X, Y, batch_size=500):

        batchesnum = int(X.shape[0] / batch_size)
        X = theano.shared(np.asarray(X, dtype=float))
        Y = theano.tensor.cast(theano.shared(np.asarray(Y)), 'int32')

        x = theano.tensor.matrix('x')
        y = theano.tensor.ivector('y')

        index = theano.tensor.lscalar()
        hx = theano.tensor.nnet.softmax(theano.tensor.dot(x, self.theta))
        ###求最后的类别结果和误差
        predict = theano.tensor.argmax(hx, axis=1)

        errors = theano.tensor.mean(theano.tensor.neq(predict, y))

        test_model = theano.function(
            inputs=[index], outputs=errors, givens={
                x: X[index * batch_size: (index + 1) * batch_size],
                y: Y[index * batch_size: (index + 1) * batch_size]
            }, allow_input_downcast=True
        )
        test_losses = []
        for minibatch_index in range(batchesnum):
            test_losses.append(test_model(minibatch_index))
        test_score = np.mean(test_losses)
        print(('minibatch %i/%i, test error of model %f %%') %
              (minibatch_index + 1, batchesnum, test_score * 100.))

    


if __name__ == '__main__':

    X, y = make_classification(n_samples=80000)
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5)
    Testsoftmax = SoftMax()
    ###typenum=len(set(y)
    Testsoftmax.training(X_train, y_train, typenum=len(set(y)))
    Testsoftmax.testing(X_test, y_test)


基本代码参考: http://www.cnblogs.com/qw12/p/5962430.html

GBDT+LR融合

原理

工业界LR模型用的比较多的原因就是它非常容易可以并行化,处理起大规模的数据来比较容易。但是LR的学习能力有限,必须要经历大量的特征选择,特征组合等工作。因此找到合适的方法简化特征工程是非常重要的。facebook在KDD上发表了一篇文章,讲的就是GBDT+LR,为我们提供了一些思路,论文中的基本原理很简单,搞清楚下面这幅图就行了:

  1. 使用GBDT训练数据,得到如下2棵树,第一棵树3个叶子结点,第二棵树2个叶子结点,总共5个叶子结点。因此最后用于LR的特征向量就是5维的[0,0,0,0,0]。

  2. 训练数据共有n个样本,那么对于其中一个样本x,查看x最终会出现在哪些树的结点上面。比如x出现在树1的第1个结点以及树2的第2个结点,那么特征向量就是[1,0,0,0,1] 得到的特征向量可以选择和原本的特征一起带入逻辑回归中,也可以单独作为特征进行学习。

demo

sklearn分别实现了GBDT和LR的算法,所以做一个小例子测试融合算法是否会比原始的算法好。重点介绍方法,结果不确定,因为参数没有调到最优。

1
2
3
4
5
6
import numpy as np
from sklearn import ensemble
from sklearn import  datasets
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_hastie_10_2
from sklearn.ensemble import GradientBoostingClassifier
注意:Boosting的方法也分分类树和回归树,这里选择的是分类树,因为make_hastie_10_2这个数据集是一个二分类的数据集

单纯使用GradientBoostingClassifier

1
2
3
4
5
X, y = make_hastie_10_2(random_state=0)
X_train, X_test = X[:2000], X[2000:]
y_train, y_test = y[:2000], y[2000:]
clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0,    max_depth=1, random_state=0).fit(X_train, y_train)
sum(clf.predict(X_test)==y_test)

最后一行是统计分类正确的数目,这里的结果是9130

单纯使用LogisticRegression

1
2
3
4
5
6
7
paramsLr={ 'multi_class':'multinomial',
          'penalty':'l2','solver':'sag', 'tol':0.0001
          }
lr1 = LogisticRegression(C=1.0,solver='sag', max_iter=100,penalty='l2',
                             multi_class='multinomial',tol=0.0001)
lr1.fit(X_train, y_train)
sum(lr1.predict(X_test)==y_test)

最后一行是统计分类正确的数目,这里的结果是5149

GBDT+LR融合

基于原理中介绍到的思想,需要将GBDT运行的结果转化为LR能够接受的数据结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def PreLR_GBDT(clf,Features):
    result=clf.apply(Features)[:,:,0]
    classT=np.zeros(result.shape[1]+1)
    for num in range(0,result.shape[1]):
        classT[num+1]=max(result[:,num])

    classT=classT.cumsum()
    classT=classT.astype(np.int32)

    M=np.zeros((result.shape[0],classT[-1]))

    for num in range(0, result.shape[0]):
        for num2 in range(0, result.shape[1]):
            M[num, classT[num2] + result[num][num2] - 1] = 1

    return M

有了上面的函数之后就可以再建立LR的模型了:

1
2
3
4
5
6
7
8
X_train_LR_GBDT=np.append(X_train,PreLR_GBDT(clf, X_train),axis=1)
X_test_LR_GBDT=np.append(X_test,PreLR_GBDT(clf, X_test),axis=1)

lr_GBDT = LogisticRegression(solver='sag', max_iter=100,penalty='l2',
                             multi_class='multinomial',tol=0.0001)
lr_GBDT.fit(X_train_LR_GBDT, y_train)

sum(lr_GBDT.predict(X_test_LR_GBDT)==y_test)

最后一行是统计分类正确的数目,这里的结果是9140,这里采用的是GBDT训练过后的feature和原始组合的方式,当然和可以不组合,直接用新的feature进行训练。

以上展示的是如何把GBDT与LR融合到一起,每个模型都没有进行调参,因此结果参考意义不大。

java基础知识–抽象类和接口的区别

1. 抽象类

抽象类就是为了实现面向对象设计的,因此必然是为了能够被继承。

1)抽象方法默认为public。可以是protected,但是不能是private。

2)抽象类不能直接创建一个对象;

3)子类必须实现父类所有的抽象方法。否则的话必须定义该子类也是抽象类。

4)抽象类中也可以有不是abstract的成员方法和数据成员。

1
2
3
abstract class Class1 {
    abstract void method();
}

2.接口

接口同样是为了实现面向对象而设计的。但是接口中的数据成员都是默认为public static final的,但是一般不会定义数据成员,而所有的成员函数都是public abstract的。

1
2
3
interface interface1{
    void method();
}

两者区别

  1. 抽象类可以多种类型的数据成员以及成员函数,因此抽象类可以定义一些默认的行为。接口只能有abstract的函数以及public static final的数据成员。
  2. 一个类只能继承自一个对象,但是可以实现多个接口。
  3. 设计理念:其实abstract class表示的是"is-a"关系,interface表示的是"like-a"关系。 要明确设计理念,该类的本质是什么,实现了哪些方法。可以查找AlarmDoor的例子。
  4. 注意接口的数据成员必须赋予初始值,使得实现的类无法改变该值。抽象类中的数据成员默认为friendly类型。

参考资料: http://www.cnblogs.com/beanmoon/archive/2012/12/06/2805221.html

r

Mac R语言访问SQLServer远程数据库-----ODBC

描述:想用R来访问数据库,但是远程数据库是SQL Server的,没有Mac版的客户端,因此建议去下载navicat for SQL Server .找一下破解版。

1.下载ODBC

brew brew install unixodbc

2.配置数据源

找到odbc.ini文件,一般在usr/local/etc里面。

第一种方式:直接配置

[ODBC Data Sources]
TESTdsn=Test DSN1
[TESTdsn]
Driver          = /usr/local/lib/libtdsodbc.so
Description     = Test DSN1
Trace           = No
Server          = 地址    
Database        = 数据库名
Port            = 1433
TDS_Version     = 7.0
client charset  = UTF-8 

第二种方法:用freetds

brew install freetds --with-unixodbc

配置freetds的数据源 /usr/local/etc/freetds.conf

[testdsn]                     # SQL Server数据源名称,可以任意取有意义的名称
  host=192.168.10.22   # 数据库主机
 port=1344                   #数据库监听端口
 tds version=8.0 #默认7.0

配置odbcinst.ini和odbc.ini odbcinst.ini:

[FREETDS]
Description=freetds driver
Driver=/usr/local/freetds/lib/libtdsodbc.so  #指定TDS驱动路径

odbc.ini:


[testdsn]  # 数据源名称
Driver=FREETDS # 指向odbcinst.ini的驱动配置
Description=MSSQL Server
Servername=testdsn # 数据源名称
Database=sqlscada    #数据库名称
cpp

堆和栈的区别

在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量 的存储区。里面的变量通常是局部变量、函数参数等。
堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。

    int* p=new int[5];//在栈内存中存放了一个指向一块堆内存的指针p。

1、管理方式不同;
2、空间大小不同;
3、能否产生碎片不同;
4、生长方向不同; 5、分配方式不同;
6、分配效率不同;

管理方式:

对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆 来说,释放工作由程序员控制,容易产生memory leak。

空间大小:

一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角 度来看堆内存几乎是没有什么限制的。但是对于栈来讲,一般都是有一定的空间 大小的

碎片问题:

对于堆来讲,频繁的new/delete势必会造成内存空间的不连续, 对于栈来讲,遵循先进后出的规则,是一块连续的内存空间。堆用链表来存储空闲空间,是不连续的。

生长方向:

对于堆来讲,是向高地址拓展的数据结构;对于栈来讲,是向低地址拓展的数据结构。

分配方式:

堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配 由alloca,new函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由 编译器进行释放,无需我们手工实现。

分配效率:

栈是机器系统提供的数据结构,堆则是C/C++函数库提供的,堆的效率比栈要低得多。

Java并行编程(1)实现多线程的方法

简单基础知识:

java的并发编程一定要考虑四个方面的内容。

  1. 共享性:当多个线程共享一份数据的时候就会有数据的安全问题。

  2. 互斥性:最基本的就是需要保证数据在同一时间只被一个线程锁修改。

  3. 原子性:类似于数据库的一致性,在数据修改到一半的时候,又被其他的操作修改。

  4. 可见性:比如线程1对数据进行了修改,但是还没有同步到最终版本,因此线程2对这次就该就是不可见的,会出现问题。

  5. 有序性:编译器会对代码做重排序的操作,这种排序有可能遵照原始线程的代码顺序,也可能是无序的优化,会有线程不安全的问题。

Read on →

正则表达式

1.一般符号

符号 意思
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字 等价于 ‘[^A-Za-z0-9_]’
\s 匹配空格
\d 匹配数字
\b 匹配单词边界,比如要匹配I am lily中的am,可以使用\bam\b
\A 匹配字符串的开始
\Z 匹配字符串的结束
^ 匹配字符串的开始,多行时匹配每一行的开头
$ 匹配字符串的结束,多行时匹配每一行的结束
[] 匹配括号内的包含的字符,比如[a-z]
| 匹配左右两边的表达式,优先匹配左边的,如果|不在括号中,作用域就是整个正则表达式。
Read on →

python字符串连接

python有若干种字符连接方式,找找资料总结如下:

  1. ‘+’号方法

     str1='aaa'
     str2='bbb'
     print(str1 + str2)
     'aaabbb'
    
  2. ‘,’号方法,会有空格。

     str1='aaa'
     str2='bbb'
     print(str1 , str2)
     'aaa bbb'
    
  3. 空格连接

     str1='aaa'
     str2='bbb'
     print(str1 str2)
     'aaabbb'
    
  4. ‘%’连接

     str1='aaa'
     str2='bbb'
     print("%s,%s"%(str1,str2))
     'aaa,bbb'
    
  5. join

     str=['aaa','bbb','ccc']
     t=','
     print(t.join(str))
     'aaa,bbb,ccc'
    
  6. ‘*'连接

     a = 'abc'
     a * 3 = 'abcabcabc'
    

汉诺塔问题

递归问题 n个盘子,三个柱子。一个柱子为起始柱子,一个为终点柱子,一个为中间柱子。 步骤:

1.将n-1个盘子移到中间柱子。

2.将第n个盘子移到终点柱子。

问题就变成了将n-1个盘子移到终点柱子的问题,重复。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    #include<iostream>
    using namespace std;
    int i;
    void move(int n,char from,char to){
           printf("step %d: the number %d from %c to %c ",i++,n,from,to);
    }
    void Hanio(int n,char start,char end,char mid){
           if(n==1)move(n,start,end);
           else{
                Hanio(n-1,start,mid,end);
                move(n,start,end);
                Hanio(n-1,mid,end,start);
               }
    }
    int main(){
           int n;  
        while(cin<<n){  
        i = 1;   //全局变量赋初始值  
        Hanio(n,'1','2','3');  
        printf("最后总的步数为%d\n",i-1);  
     }  
    return 0; 
    }