0%

数据划分

数据划分

留出法(Hold-Out)

定义与流程

就是有一个数据集$D$,要分出$S,T满足S\bigcup T=\emptyset,S\bigcap T=D$

S,T一个是训练集一个是测试集

就是把数据分成两个互不相交的部分,并保持数据分布大致一致

划分比例

  • 比例一般在$\frac{2}{3}到\frac{4}{5}$之间

  • 划分的时候保持数据分布大致一致,类似分层抽样

结果处理

  • 为了保证随机性,结果在多次划分中取平均值

优缺点

  • 优点:简单,快速
  • 缺点:容易出现局部极值

kNN、留出法、titanic

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
from pandas import *
from numpy import *
import matplotlib.pyplot as plt
def loadDataSet(filename1):
fr = read_csv(filename1)
return fr
def HoldOutSplit(dataSetO,P=0.7):
dataSet=[];testSet=[]
labelSet=[];testLabel=[]
n=dataSetO.shape[0]
S=0
for i in dataSetO['Survived']:
if(i==1.0):S+=1
N=n-S
S=P*S;N=P*N
SS=NN=0
for i in range(n):
p=random.random()
data=dataSetO.iloc[i]
if(p<=P):
if(data[0]==1.0)and(SS>=S):p=1.0-p
if (data[0] == 0.0) and (NN >= N): p = 1.0 - p
if(p<=P):
if(data[0]==1.0):SS+=1
else :NN+=1
dataSet.append(data[1:]),labelSet.append(data[0])
else:testSet.append(data[1:]),testLabel.append(data[0])
return array(dataSet),array(testSet),labelSet,testLabel
#def crossTestSplit()
def kNN(dataSet,testSet,labelSet,testLabel,K):
n=dataSet.shape[0]
error=0;z=testSet.shape[0]
for i in range(z):
Dvalue=dataSet-tile(testSet[i],(n,1))
Dvalue=Dvalue**2
sumValue=Dvalue.sum(axis=1)
sortValue=sumValue.argsort()
survive=0
for j in range(K):
if(labelSet[sortValue[j]]==1.0):survive+=1
survive=float(survive>K-survive)
if(survive!=testLabel[i]):error+=1
return (z-error)/z
def HoldOut():
z=0
dataSetO = loadDataSet('traingui.csv')
for i in range(10):
mxK = -inf
dataSet, testSet, labelSet, testLabel = HoldOutSplit(dataSetO)
for K in range(5, 25):
accrury = kNN(dataSet, testSet, labelSet, testLabel, K)
if (accrury > mxK):
mxK = accrury
z+=mxK
return 1.0*z/10.0
if __name__=='__main__':
print(HoldOut())

交叉验证法(Cross Validation,k折交叉验证)

定义与流程

把数据集分成k个互斥的集合,然后每次用一个作为测试集,其他k-1个作为训练集

划分与参数

  • 为了保证数据分布的一致性,从数据集中分层抽样得到这些集合
  • 交叉验证法评估结果的稳定性和保真性在很大的程度上取决与k的取值

结果处理

  • 返回k次结果的均值

优缺点

  • 优点:从有限的数据集尽可能的挖掘多的信息,从各种角度去学习,避免出现局部的极值
  • 缺点:当数据集比较大的时候,慢

kNN、交叉验证法、titanic

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
from pandas import *
from numpy import *
import matplotlib.pyplot as plt
def loadDataSet(filename1):
fr = read_csv(filename1)
return fr
def crossIndex(dataSetO):
n = dataSetO.shape[0]
dataIndex = [i for i in range(n)]
for i in range(n):
x = random.randint(1, n - 1)
dataIndex[i], dataIndex[x] = dataIndex[x], dataIndex[i]
return dataIndex
def crossTestSplit(dataSetO,dataIndex,head,Kc):
dataSet = [];testSet = []
labelSet = [];testLabel = []
n = dataSetO.shape[0];size=n//Kc
for i in range(n):
data = dataSetO.iloc[dataIndex[i]]
if(i>=head*size)and(i<(head+1)*size):testSet.append(data[1:]), testLabel.append(data[0])
else:dataSet.append(data[1:]),labelSet.append(data[0])
return array(dataSet), array(testSet), labelSet, testLabel
def kNN(dataSet,testSet,labelSet,testLabel,K):
n=dataSet.shape[0]
error=0;z=testSet.shape[0]
for i in range(z):
Dvalue=dataSet-tile(testSet[i],(n,1))
Dvalue=Dvalue**2
sumValue=Dvalue.sum(axis=1)
sortValue=sumValue.argsort()
survive=0
for j in range(K):
if(labelSet[sortValue[j]]==1.0):survive+=1
survive=float(survive>K-survive)
if(survive!=testLabel[i]):error+=1
return (z-error)/z
def crossTest():
dataSetO = loadDataSet('traingui.csv')
dataIndex=crossIndex(dataSetO)
Kc=10;z=0
for i in range(Kc):
mxK = -inf
dataSet, testSet, labelSet, testLabel =crossTestSplit(dataSetO,dataIndex,i,Kc)
for K in range(5, 25):
accrury = kNN(dataSet, testSet, labelSet, testLabel, K)
if (accrury > mxK):
mxK = accrury
z+=mxK
return 1.0 * z / 10.0
if __name__=='__main__':
print(crossTest())

由于打分层抽样还没想到怎么打比较简短(留出法的分层抽样我就打的很丑),所以暂时还没有分层抽样,只是随机了一下

自助法(BootStrapping)

定义与流程

思想来源

上面的两个方法用来训练的数据都不是全部数据,这样在实际评估的时候会造成偏差。所以我们想—-用我们所有的数据来训练模型—–>自助法

步骤

  • 1.在数据集D中随机一个样本,D的大小为n
  • 2.把这个样本拷贝D’中(注意是拷贝,就是D并没有改变)[注意:部分D的样本可能会被多次选取]
  • 3.将步骤2重复进行n次
  • 4.D’为训练集,D-D’为测试集

原理

统计一个样本x不会在D’中出现的概率,并取极限

$$
\lim _{n->∞}(1-{1\over n})^n={1\over e}≈0.368
$$
可见,一个样本不出现在D’中的概率大约为0.368,所以大约有0.368的样本没有出现在D’中

所以D-D’大约有0.368的数据

  • 综上:因为是直接在原数据中随机,最后得到的测试集的各项分布比例和训练集都一样
    • 这样就解决了不好划分(分层抽样)的问题
    • 还保证了训练集和测试集互斥

结果处理

  • 返回多次结果的均值

优缺点

  • 优点:
    • 在数据集较小、难以有效划分数据集和测试集的时候很有用
    • 在集成学习中,自助法能从初始数据集产生多个不同的训练集
    • 好打
  • 缺点:
    • 改变了初始数据集的分布,会引入估计误差。
    • 大数据集下表现没有上面的两种方法好

kNN、自助法、titanic

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
from pandas import *
from numpy import *
import matplotlib.pyplot as plt
def loadDataSet(filename1):
fr = read_csv(filename1)
return fr
def BSsplit(dataSetO):
n = dataSetO.shape[0]
dataSet = [];testSet = []
labelSet = [];testLabel = []
dataIndex=[]
for i in range(n):
x=random.randint(0,n-1)
dataIndex.append(x)
setIndex=set(dataIndex)
for i in range(n):
data = dataSetO.iloc[dataIndex[i]]
dataSet.append(data[1:]), labelSet.append(data[0])
data = dataSetO.iloc[i]
if(i not in setIndex):testSet.append(data[1:]),testLabel.append(data[0])
return array(dataSet), array(testSet), labelSet, testLabel
def kNN(dataSet,testSet,labelSet,testLabel,K):
n=dataSet.shape[0]
error=0;z=testSet.shape[0]
for i in range(z):
Dvalue=dataSet-tile(testSet[i],(n,1))
Dvalue=Dvalue**2
sumValue=Dvalue.sum(axis=1)
sortValue=sumValue.argsort()
survive=0
for j in range(K):
if(labelSet[sortValue[j]]==1.0):survive+=1
survive=float(survive>K-survive)
if(survive!=testLabel[i]):error+=1
return (z-error)/z
def bootStrappingTest():
z = 0
dataSetO = loadDataSet('traingui.csv')
for i in range(10):
mxK = -inf
dataSet, testSet, labelSet, testLabel = BSsplit(dataSetO)
for K in range(5, 25):
accrury = kNN(dataSet, testSet, labelSet, testLabel, K)
if (accrury > mxK):
mxK = accrury
z += mxK
return 1.0 * z / 10.0
if __name__=='__main__':
print(bootStrappingTest())

留一法

定义

相当于n折交叉验证

就是每一用一个做测试集,其他做训练集

结果处理

  • 返回n次结果的均值

优缺点

  • 优点:好打,交叉验证的优点+++
  • 缺点:慢

kNN、留一法、titanic

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
from pandas import *
from numpy import *
import matplotlib.pyplot as plt
def loadDataSet(filename1):
fr = read_csv(filename1)
return fr
def leaveOneSplit(dataSetO,test):
n = dataSetO.shape[0]
dataSet = [];testSet = []
labelSet = [];testLabel = []
for i in range(n):
data = dataSetO.iloc[i]
if(test!=i):dataSet.append(data[1:]), labelSet.append(data[0])
else:testSet.append(data[1:]), testLabel.append(data[0])
return array(dataSet), array(testSet), labelSet, testLabel
def kNN(dataSet,testSet,labelSet,testLabel,K):
n=dataSet.shape[0]
error=0;z=testSet.shape[0]
for i in range(z):
Dvalue=dataSet-tile(testSet[i],(n,1))
Dvalue=Dvalue**2
sumValue=Dvalue.sum(axis=1)
sortValue=sumValue.argsort()
survive=0
for j in range(K):
if(labelSet[sortValue[j]]==1.0):survive+=1
survive=float(survive>K-survive)
if(survive!=testLabel[i]):error+=1
return (z-error)/z
def leaveOneTest():
z = 0
dataSetO = loadDataSet('traingui.csv')
for i in range(dataSetO.shape[0]):
mxK = -inf
dataSet, testSet, labelSet, testLabel = leaveOneSplit(dataSetO,i)
#for K in range(5, 25):
K=20
accrury = kNN(dataSet, testSet, labelSet, testLabel, K)
if (accrury > mxK):
mxK = accrury
z += accrury
return 1.0 * z / dataSetO.shape[0]
if __name__=='__main__':
print(leaveOneTest())