引用说明:
写在最前
在开始看这个篇目之前,建议先去了解一下机器学习的一些基础。
这是陌诺开展的第三个项目,这个项目扎根人工智能基础,从机器学习讲起,从零开始实现机器学习的相关内容。
配置要求
一、最新版的Numahk库
二、每一篇章结尾有专门的依赖库,例如KNN需要Counter类,包含在命名为collections.ahk的文件中
正式开始
一、机器学习实现基础
我们将输入向量称作x,输出向量称作y,训练实例t形式为<x,y>,训练集则是所有t的集合。
机器学习就是实现输入未知结果的向量xi,根据训练集来预测结果yi。
二、K最近邻算法基础
在讲K最近邻算法之前,我们必须先了解最近邻算法是什么。
最近邻算法思路:
1.计算xi与训练集训练实例的“距离”
2.然后找到与xi“距离”最近的训练实例tc=<xc,yc>
3.最后返回这训练集对应的yc作为xi的预测结果
K最近邻算法思路:
在最近邻基础上进行优化,寻找到最近的k个邻点。
返回多预测结果中可能性最大的那个。
***注意:k的数量不是一成不变的,需要根据训练集的数据特点进行合理选取,这也是KNN最大的难点。
代码实战
; 注意更改这里的引用地址。
#Include "../numahk.ahk"
#Include "../collections.ahk"
class KNN
{
__New(XTrain, YTrain, nNeighbors := 5, p := 2)
{
this.XTrain := XTrain
this.YTrain := YTrain
this.nNeighbors := nNeighbors
this.p := p
}
predict(X)
{
; 预测
; 测试集全遍历
knnlist := List()
for i in xrange(len(this.XTrain))
{
; 注意:这里是计算最近邻的核心计算公式,可以通过改变this.p的值以更改距离计算公式。
dist := numahk.linalg.norm(numahk.Subtract(X.Copy(), this.XTrain[i]), "ord=" this.p)
knnlist.append(List(round(dist, 2), this.YTrain[i]))
}
for i in xrange(len(knnlist))
{
for j in range(i + 1, len(knnlist))
{
if knnlist[i][0] > knnlist[j][0]
swap(i, j, knnlist)
}
}
minKnnlist := knnlist[0 ":" this.nNeighbors]
; 统计
knn := List()
for k in minKnnlist
knn.append(k[-1])
count_pairs := Counter(knn)
max_count := 0
max_value := 0
for i, Valuei in count_pairs.Content
{
max_count := (Valuei > max_value) ? i : max_count
max_value := (Valuei > max_value) ? Valuei : max_value
}
return max_count
}
score(X_test, y_test)
{
right_count := 0
n := 10
for value in zip(X_test, y_test)
{
X := value[0]
y := value[1]
label := this.predict(X)
if label == y
right_count += 1
}
return right_count / len(X_test)
}
}
测试代码
XTrain := numahk.array([[3,104],[2,100],[1,81],[101,10],[99,5],[98,2]])
Ytrain := numahk.array([0,0,0,1,1,1])
; 注意:如果要算的是Score的话,这里的xtest的数组一定是要两层。
xtest := numahk.array([[101,20]])
ytest := numahk.array([1])
; 这里的第三个参数是k的值,默认值为5;还有可选的第四个参数,默认值为2
clf := KNN(XTrain, YTrain, 3)
resultScore := clf.score(xtest, ytest)
; 这里如果只是想预测值的话可以用result := clf.predict(xtest)
; 并且xtest的数组只能是一层。即[101,20]。
MsgBox(resultScore)
依赖库
collections.ahk
Class Counter
{
__New(Object := "Null")
{
Map_Element := Map()
if Object == "Null"
Object := Array()
if Type(Object) == "Integer" || Type(Object) == "Float" || Type(Object) == "String"
{
Object := String(Object)
Lst_Object := StrSplit(Object, "")
Loop Lst_Object.Length
{
Key := Lst_Object[A_Index]
if Map_Element.Has(Key)
Map_Element[Key]++
else
Map_Element[Key] := 1
}
}
else if Type(Object) == "Array"
{
For i in Object
{
Key := ToString(i)
if Map_Element.Has(Key)
Map_Element[Key]++
else
Map_Element[Key] := 1
}
}
else if Type(Object) == "List"
{
For i in Object
{
Key := ToString(i)
if Map_Element.Has(Key)
Map_Element[Key]++
else
Map_Element[Key] := 1
}
}
else if Type(Object) == "Numpy.NDArray"
{
For i in Object.array
{
Key := ToString(i)
if Map_Element.Has(Key)
Map_Element[Key]++
else
Map_Element[Key] := 1
}
}
else if Type(Object) == "Map" || Type(Object) == "Dict"
{
For i, Value in Object
{
if isNumber(Value)
Map_Element[i] := Value
}
}
else if Type(Object) == "Object"
{
For i, Value in Object.OwnProps()
{
if isNumber(Value)
Map_Element[i] := Value
}
}
else
Throw ValueError("Illegal Input")
this.Content := Map_Element
}
And(Object)
{
Map_Object := Counter(Object).Content
And_Map := Map()
For i, Value in Map_Object
{
Key := i
if this.Content.Has(Key)
And_Map[Key] := Min(Value, this.Content[Key])
}
this.Content := And_Map
Return this
}
Del(Key)
{
if this.Content.Has(Key)
this.Content.Delete(Key)
Return this
}
Elements()
{
Return this.Content
}
Keys()
{
Lst_Keys := Array()
For i, Value in this.Content
Lst_Keys.Push(i)
Return Lst_Keys
}
Most_Common(Number)
{
if Number > this.Content.Count
Number := this.Content.Count
Lst_Return := Array()
Lst_Map := List.SortMap(this.Content)
Loop Number
Lst_Return.Push(Lst_Map[A_Index])
Return Lst_Return
}
Or(Object)
{
Map_Object := Counter(Object).Content
For i, Value in Map_Object
{
Key := i
if this.Content.Has(Key)
this.Content[Key] := Max(Value, this.Content[Key])
else
this.Content[Key] := Value
}
For i, Value in this.Content
{
if Value < 0
this.Content.Delete(i)
}
Return this
}
Sub(Object)
{
Map_Object := Counter(Object).Content
For i, Value in Map_Object
{
Key := i
if this.Content.Has(Key)
{
this.Content[Key] -= Value
if this.Content[Key] <= 0
this.Content.Delete(Key)
}
}
Return this
}
Subtract(Object)
{
Map_Object := Counter(Object).Content
For i, Value in Map_Object
{
Key := i
if this.Content.Has(Key)
this.Content[Key] -= Value
else
this.Content[Key] := -Value
}
Return this
}
Update(Object)
{
Map_Object := Counter(Object).Content
For i, Value in Map_Object
{
Key := i
if this.Content.Has(Key)
this.Content[Key] += Value
else
this.Content[Key] := Value
}
Return this
}
Values()
{
Lst_Values := Array()
For i, Value in this.Content
Lst_Values.Push(Value)
Return Lst_Values
}
}