我正在解决加州理工学院机器学习课程(http://work.caltech.edu/homework/hw1.pdf)的作业1.为解决问题7-10,我们需要实施PLA.这是我在python中的实现:
import sys,math,random
w=[] # stores the weights
data=[] # stores the vector X(x1,x2,...)
output=[] # stores the output(y)
# returns 1 if dot product is more than 0
def sign_dot_product(x):
global w
dot=sum([w[i]*x[i] for i in xrange(len(w))])
if(dot>0):
return 1
else :
return -1
# checks if a point is misclassified
def is_misclassified(rand_p):
return (True if sign_dot_product(data[rand_p])!=output[rand_p] else False)
# loads data in the following format:
# x1 x2 ... y
# In the present case for d=2
# x1 x2 y
def load_data():
f=open("data.dat","r")
global w
for line in f:
data_tmp=([1]+[float(x) for x in line.split(" ")])
data.append(data_tmp[0:-1])
output.append(data_tmp[-1])
def train():
global w
w=[ random.uniform(-1,1) for i in xrange(len(data[0]))] # initializes w with random weights
iter=1
while True:
rand_p=random.randint(0,len(output)-1) # randomly picks a point
check=[0]*len(output) # check is a list. The ith location is 1 if the ith point is correctly classified
while not is_misclassified(rand_p):
check[rand_p]=1
rand_p=random.randint(0,len(output)-1)
if sum(check)==len(output):
print "All points successfully satisfied in ",iter-1," iterations"
print iter-1,w,data[rand_p]
return iter-1
sign=output[rand_p]
w=[w[i]+sign*data[rand_p][i] for i in xrange(len(w))] # changing weights
if iter>1000000:
print "greater than 1000"
print w
return 10000000
iter+=1
load_data()
def simulate():
#tot_iter=train()
tot_iter=sum([train() for x in xrange(100)])
print float(tot_iter)/100
simulate()
根据问题7的答案的问题,当训练集的大小但是我的实现平均需要50000次迭代时,感知器应该花费大约15次迭代来收敛.训练数据是随机生成的,但我正在生成简单线条的数据,如x = 4,y = 2,等等.这是我得到错误答案还是有其他错误的原因.我的训练数据样本(使用y = 2可分离):
1 2.1 1
231 100 1
-232 1.9 -1
23 232 1
12 -23 -1
10000 1.9 -1
-1000 2.4 1
100 -100 -1
45 73 1
-34 1.5 -1
它的格式为x1 x2输出(y)
解决方法:
很明显,您正在努力学习Python和分类算法.
但是,由于您的代码存在一些样式效率低下的问题,因此很难为您提供帮助,并且这可能会导致部分问题成为您与教授之间的沟通错误.
例如,教授是否希望您在“在线模式”或“离线模式”下使用Perceptron?在“在线模式”中,您应该按顺序移动数据点,不应该重新访问任何点.从赋值的猜想来看它应该只需要15次迭代来收敛,我很好奇这是否意味着前15个数据点按顺序排列会导致分类器线性地分离你的数据集.
通过替换随机抽样,你可能会让自己花费更长的时间(虽然,根据数据样本的分布和大小,这是不可能的,因为你可能会大致认为任何15分都可以做到和第一个15).
另一个问题是,在您检测到正确分类的点(非is_misclassified评估为True的情况)后,如果您再见到一个错误分类的新随机点,那么您的代码将进入外部while循环的较大部分,并且然后回到顶部,它将覆盖全0的校验向量.
这意味着你的代码检测到它已正确分类所有点的唯一方法是它评估它们的特定随机序列(在内部while循环中)恰好是一个全1的字符串,除了它的神奇能力任何特定的0,在通过数组时,它正确分类.
我不能完全正式化为什么我认为这将使程序花费更长的时间,但似乎你的代码需要更严格的融合形式,它需要在一个单片传递方式上一次学习所有内容在已经更新了一堆之后的训练阶段.
一个简单的方法来检查我对此的直觉是否很糟糕将是将while行循环中的行check = [0] * len(输出)全部移动到一起并且仅初始化它一次.
一些使代码更易于管理的一般建议:
>不要使用全局变量.相反,让你的函数加载和准备数据返回的东西.
>例如,有几个地方你说
return(如果sign_dot_product(data [rand_p]),则返回true!= output [rand_p] else False)
这种事情可以简化为
return sign_dot_product(data [rand_p])!= output [rand_p]
这更容易阅读,并以更直接的方式传达您要检查的标准.
>我怀疑效率起着重要作用,因为这似乎是一种教学练习,但是有很多方法可以重构你对列表理解的使用,这可能是有益的.如果可能,只需使用具有本机数组类型的NumPy.目睹如何用列表操作表达这些操作中的某些操作是可悲的.即使你的教授不希望你用NumPy实施,因为他或他正试图教你纯粹的基础知识,我说要忽略它们并去学习NumPy.它将帮助您在Python中使用这些类型的操作获得工作,实习和实践技能,而不仅仅是与本机数据类型进行斗争,以执行它们不是为其设计的(阵列计算).