2018年1月19日 星期五

Maker玩轉Machine Learning (室內定位運用KNN演算法 Part 1)

最近看了一些論文,發現室內定位愈來愈多人開始用Machine Learning來做

不看還好,一看驚為天人!  決定花點時間學習一下

家中財政部長問我為什麼每次寫文章都這麼鄉民口吻

為何不像週刊專欄或是科技新聞那樣專業?

決定這次換個方式寫,但寫的程度太差,部長大人應該開心不起來 XD

-----------------分隔線在此---------------------

Machine Learning眾人以ML簡之

Big Data、Machine Learning、Deep Learning集市以AI著稱

機器訓練得宜,則學術深博,常言道,得AI者,得天下

今 吾以knn首试,knn為何? wiki曰明於此

例參github而來,python語句

假令 今有四點如圖



a1a2Ab1b2B,此時入c如下


於眼焉能辨cB

若君興於圖,參碼之

from matplotlib import pyplot as plt
import numpy as np

a1 = np.array([1, 1])
a2 = np.array([5, 1])
b1 = np.array([1, 5])
b2 = np.array([5, 5])
b3 = np.array([3, 5])
c = np.array([3, 4])

X1, Y1 = a1
X2, Y2 = a2
X3, Y3 = b1
X4, Y4 = b2
X5, Y5 = b3
X6, Y6 = c

plt.title('show data')
plt.scatter(X1, Y1, color="blue", label="a1")
plt.scatter(X2, Y2, color="blue", label="a2")
plt.scatter(X3, Y3, color="red", label="b1")
plt.scatter(X4, Y4, color="red", label="b2")
plt.scatter(X5, Y5, color="red", label="b3")
plt.scatter(X6, Y6, color="red", label="c")
plt.legend(loc='upper left')

plt.annotate(r'a1(1,1)', xy=(X1, Y1), xycoords='data', xytext=(+10, +30), textcoords='offset points', fontsize=16, arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))
plt.annotate(r'a2(5,1)', xy=(X2, Y2), xycoords='data', xytext=(+10, +30), textcoords='offset points', fontsize=16, arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))
plt.annotate(r'b1(1,5)', xy=(X3, Y3), xycoords='data', xytext=(+10, +30), textcoords='offset points', fontsize=16, arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))
plt.annotate(r'b2(5,5)', xy=(X4, Y4), xycoords='data', xytext=(+10, +30), textcoords='offset points', fontsize=16, arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))
plt.annotate(r'b3(3,5)', xy=(X5, Y5), xycoords='data', xytext=(+10, +30), textcoords='offset points', fontsize=16, arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))
plt.annotate(r'c(3,4)', xy=(X6, Y6), xycoords='data', xytext=(+10, +30), textcoords='offset points', fontsize=16, arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))
plt.show()


Knn碼,例1于此

k3(3),為取3點極近xy數組

from matplotlib import pyplot as plt
import numpy as np
import math

def Euclidean(vec1, vec2): #Euclidean間距算法
    npvec1, npvec2 = np.array(vec1), np.array(vec2)
    return math.sqrt(((npvec1-npvec2)**2).sum())

def Cosine(vec1, vec2): #Cosine間距算法
    npvec1, npvec2 = np.array(vec1), np.array(vec2)
    return npvec1.dot(npvec2)/(math.sqrt((npvec1**2).sum()) * math.sqrt((npvec2**2).sum()))

def create_trainset():

    trainset_tf = dict()
    trainset_tf[u'X1, Y1'] = np.array([1, 1])
    trainset_tf[u'X2, Y2'] = np.array([5, 1])
    trainset_tf[u'X3, Y3'] = np.array([1, 5])
    trainset_tf[u'X4, Y4'] = np.array([5, 5])
    trainset_tf[u'X5, Y5'] = np.array([3, 5])

    trainset_class = dict()
    trainset_class[u'X1, Y1'] = 'A'
    trainset_class[u'X2, Y2'] = 'A'
    trainset_class[u'X3, Y3'] = 'B'
    trainset_class[u'X4, Y4'] = 'B'
    trainset_class[u'X5, Y5'] = 'B'

    return trainset_tf, trainset_class

def knn_classify(input_tf, trainset_tf, trainset_class, k):

    xy = np.array([0, 0])
   
    tf_distance = dict()

    print '(1) 各點之遙' #python3用法 --> print ("(1) 各點之遙")
    for place in trainset_tf.keys():
        tf_distance[place] = Euclidean(trainset_tf.get(place), input_tf)
        print '\tTF(%s) = %f' % (place, tf_distance.get(place))

    class_count = dict()
    print '(2) K個鄰為類, k = %d' % k
    for i, place in enumerate(sorted(tf_distance, key=tf_distance.get, reverse=False)):
        current_class = trainset_class.get(place)
        print '\tTF(%s) = %f, class = %s' % (place, tf_distance.get(place), current_class)
        class_count[current_class] = class_count.get(current_class, 0) + 1
        xy = xy + trainset_tf[place]
        if (i + 1) >= k:
            break
           
    print '(3) K鄰均等之xy -->' #3
    finalx=float(xy[0])/k
    finaly=float(xy[1])/k
    print '\tx = %f' % finalx, ', y = %f'% finaly
   
    print '(4) K個鄰累計,最高者任其終類'
    input_class = ''
    for i, c in enumerate(sorted(class_count, key=class_count.get, reverse=True)):
        if i == 0:
            input_class = c
        print '\t%s, %d' % (c, class_count.get(c))
    print '(5) 結果 = %s' % input_class

input_tf = np.array([3, 4])
trainset_tf, trainset_class = create_trainset()
knn_classify(input_tf, trainset_tf, trainset_class, k=3)

結果

見結果,x3y5

吾於碼中,設input_tf = np.array([3, 4]),表x3y4

y於實測與預測相差1,頗為接近! 心喜! 信心大增!

故例2,吾設實測集合於下

def create_trainset():

    trainset_tf = dict()
    trainset_tf[u'T1, U1, V1, W1, X1, Y1, Z1'] = np.array([-55, -65, -65, -75, -85, 1, 1])
    trainset_tf[u'T2, U2, V2, W2, X2, Y2, Z2'] = np.array([-65, -55, -85, -75, -65, 5, 1])
    trainset_tf[u'T3, U3, V3, W3, X3, Y3, Z3'] = np.array([-65, -85, -55, -60, -65, 1, 5])
    trainset_tf[u'T4, U4, V4, W4, X4, Y4, Z4'] = np.array([-75, -75, -60, -55, -60, 5, 5])
    trainset_tf[u'T5, U5, V5, W5, X5, Y5, Z5'] = np.array([-85, -65, -65, -59, -55, 3, 5])
   #這太難寫了! 放棄! 直接寫白話文 XD
   #以[-55, -65, -65, -75, -85, 1, 1]為例
   #-55表示手環在第一個接收器的位置,-85離最遠
   #於空間內置放5個接收器,手環於5個地點發射,故5個接收器的強度都不同
   #5個負數代表5個接收器收到的RSSI,後面2個值(1,1)代表xy
#如果您有參加過我們的工作坊就知道Linkit 7697一秒可以送出多筆資料
   #但這只是模擬數據,實做是要用洗資料的方式
#而這個資料集是代表實測出來的建模,要給機器去學習比對,找出使用者目前位置

    trainset_class = dict()
    trainset_class[u'T1, U1, V1, W1, X1, Y1, Z1'] = 'A'
    trainset_class[u'T2, U2, V2, W2, X2, Y2, Z2'] = 'A'
    trainset_class[u'T3, U3, V3, W3, X3, Y3, Z3'] = 'B'
    trainset_class[u'T4, U4, V4, W4, X4, Y4, Z4'] = 'B'
    trainset_class[u'T5, U5, V5, W5, X5, Y5, Z5'] = 'B'

    return trainset_tf, trainset_class

此時,夫子戴手環入室,input_tf表夫子之室內數據

負數為各Linkit 7697所得RSSI,設xy數為零零,將由ML算之,設集如下

input_tf = np.array([-72, -72, -63, -53, -63, 0, 0])

MLx3, y5,倒果為因,同上例1之xy得數

故窺Machine Learning之強大,何況Deep Learning?

如下為例2之碼

from matplotlib import pyplot as plt
import numpy as np
import math

def Euclidean(vec1, vec2): #Euclidean間距算法
    npvec1, npvec2 = np.array(vec1), np.array(vec2)
    return math.sqrt(((npvec1-npvec2)**2).sum())

def Cosine(vec1, vec2): #Cosine間距算法
    npvec1, npvec2 = np.array(vec1), np.array(vec2)
    return npvec1.dot(npvec2)/(math.sqrt((npvec1**2).sum()) * math.sqrt((npvec2**2).sum()))

def create_trainset():

    trainset_tf = dict()
    trainset_tf[u'T1, U1, V1, W1, X1, Y1, Z1'] = np.array([-55, -65, -65, -75, -85, 1, 1])
    trainset_tf[u'T2, U2, V2, W2, X2, Y2, Z2'] = np.array([-65, -55, -85, -75, -65, 5, 1])
    trainset_tf[u'T3, U3, V3, W3, X3, Y3, Z3'] = np.array([-65, -85, -55, -60, -65, 1, 5])
    trainset_tf[u'T4, U4, V4, W4, X4, Y4, Z4'] = np.array([-75, -75, -60, -55, -60, 5, 5])
    trainset_tf[u'T5, U5, V5, W5, X5, Y5, Z5'] = np.array([-85, -65, -65, -59, -55, 3, 5])
   

    trainset_class = dict()
    trainset_class[u'T1, U1, V1, W1, X1, Y1, Z1'] = 'A'
    trainset_class[u'T2, U2, V2, W2, X2, Y2, Z2'] = 'A'
    trainset_class[u'T3, U3, V3, W3, X3, Y3, Z3'] = 'B'
    trainset_class[u'T4, U4, V4, W4, X4, Y4, Z4'] = 'B'
    trainset_class[u'T5, U5, V5, W5, X5, Y5, Z5'] = 'B'

    return trainset_tf, trainset_class

def knn_classify(input_tf, trainset_tf, trainset_class, k):

    xy = np.array([0, 0])
   
    tf_distance = dict()

    print '(1) 各點之遙'
    for place in trainset_tf.keys():
        tf_distance[place] = Euclidean(trainset_tf.get(place), input_tf)
        print '\tTF(%s) = %f' % (place, tf_distance.get(place))

    class_count = dict()
    print '(2) K個鄰為類 k = %d' % k
    for i, place in enumerate(sorted(tf_distance, key=tf_distance.get, reverse=False)):
        current_class = trainset_class.get(place)
        print '\tTF(%s) = %f, class = %s' % (place, tf_distance.get(place), current_class)
        class_count[current_class] = class_count.get(current_class, 0) + 1
        xy = [(xy[0] + trainset_tf[place][5]),(xy[1] + trainset_tf[place][6])]
        if (i + 1) >= k:
            break
           
    print '(3) K鄰均等之xy -->'
    finalx=float(xy[0])/k
    finaly=float(xy[1])/k
    print '\tx = %f' % finalx, ', y = %f'% finaly
   
    print '(4) K個鄰累計,最高者任其終類'
    input_class = ''
    for i, c in enumerate(sorted(class_count, key=class_count.get, reverse=True)): #擇小排序之
        if i == 0:
            input_class = c
        print '\t%s, %d' % (c, class_count.get(c))
    print '(5) 結果 = %s' % input_class

input_tf = np.array([-72, -72, -63, -53, -63, 0, 0])
trainset_tf, trainset_class = create_trainset()
knn_classify(input_tf, trainset_tf, trainset_class, k=3)


結果


若君難以窺得內文所然,正常!


吾於古文茫然,乃正港台北俗


此為現實定位模擬數值,將有實測之文

ML系列文將以不同風貌展現


2018/2/3於府城AI Robot解說此篇緣由

 


欲入吾流?
 


沒有留言:

張貼留言

動手做系列 - 康達效應 (Coanda Effect)

康達效應 (Coanda Effect) 是指流體流過具有彎度的凸表面時,會被表面吸附的現象,具體實驗過程請看以下影片 台灣的學生比較怕錯,因為錯了可能會被釘在牆上 之前還看過老師霸凌學生的新聞,老師霸凌比同儕霸凌還可...