基於感知機的人名-性別預測系統 —— Python實現
一. 感知機基礎知識:
如上圖所示,感知機模型是一個線性二分類模型,可以將線性可分的特徵向量對映為+1 / -1的二值分類結果。下面具體介紹此過程:
1. 模型結構:
設輸入與輸出:
χ ⊆ R n , γ ⊆ { + 1 , − 1 } ; \chi \subseteq \mathbb R^n,\gamma\subseteq \{+1,-1\}; χ⊆Rn,γ⊆{+1,−1};
x ∈ χ , y ∈ γ ; x\in \chi,y \in \gamma ; x∈χ,y∈γ;
則感知機模型表示為:
y = f ( x ) = s i g n ( w x + b ) , y = f(x)=sign(wx+b), y=f(x)=sign(wx+b),
其中 w ∈ R n , b ∈ R ; w\in\mathbb R^n,b\in\mathbb R; w∈Rn,b∈R;
s i g n ( x ) = { 1 , x ⩾ 0 − 1 , x < 0 sign(x) = \begin{cases} 1, & x \geqslant0 \\ -1, & x<0 \end{cases} sign(x)={1,−1,x⩾0x<0
2. 訓練資料:
此模型需要的訓練資料為 T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . . . . ( x N , y N ) } , T = \{(x_1,y_1),(x_2,y_2),. . . . . . (x_N,y_N)\}, T={(x1,y1),(x2,y2),......(xN,yN)},
其中 x i ∈ χ , y i ∈ γ ; x_i\in\chi,y_i\in\gamma; xi∈χ,yi∈γ;
3. 損失函式:
我們使用誤分類點到超平面的距離構造損失函式:
設 x 0 ∈ R n x_0\in\mathbb R^n x0∈Rn為誤分類點,
感知機定義的超平面為 S : w x + b = 0 , S:wx+b=0, S:wx+b=0,
則此誤分類點到超平面的距離為:
1 ∣ ∣ w ∣ ∣ ∣ w x 0 + b ∣ \dfrac{1}{||w||}|wx_0+b| ∣∣w∣∣1∣wx0+b∣,其中 ∣ ∣ w ∣ ∣ ||w|| ∣∣w∣∣為權重的 L 2 L_2 L2範數。
對於誤分類點 x i ∈ M , x_i \in M, xi∈M,有
− y i ( w x i + b ) > 0 , -y_i(wx_i+b)>0, −yi(wxi+b)>0,
忽略 l 2 l_2 l2範數,則損失函式定義為
L ( w , b ) = − ∑ x i ∈ M y i ( w x i + b ) , L(w,b)=-\sum_{x_i\in M}^{}y_i(wx_i+b), L(w,b)=−∑xi∈Myi(wxi+b),
我們的學習目標就是求得 w , b , w,b, w,b,有
m i n w , b L ( w , b ) 。 min_{w,b}L(w,b)。 minw,bL(w,b)。
4. 學習演算法:
感知機的學習採用梯度下降法,學習的目的是讓模型在訓練集上沒有誤分類點,具體的權重和偏執的更新為:
w : = w + α y i x i w := w+\alpha y_ix_i w:=w+αyixi
b : = b + α y i b := b + \alpha y_i b:=b+αyi
二. 專案實踐
1. 特徵函式:
當我們想要在一個資料集上採用感知機演算法來實現二分類時,我們首先需要考慮的是將資料轉化為特徵向量,這一過程的實現需要一系列的特徵函式,每一個特徵函式考量資料是否有相應的特徵,並將資料的該特徵轉化為數值。這一系列的特徵函式的作用結果就使得資料轉化為了特徵向量,也就是說N個特徵函式可以提取N個特徵,形成N維特徵向量。
對於線性不可分的資料集,例如異或關係產生的資料,感知機演算法是無效的。但在實際中,我們很難知道一個資料集是否是線性可分的,特別是往往我們無法直觀理解資料的特徵向量。為了解決感知機演算法只能處理線性可分的資料,最簡單的方法就是儘量提高特徵向量的維度,維度越高,特徵向量越可能是線性可分的。
具體到我們的專案中,資料集中包含120000個資料,擷取一部分如下:
1,閎家,1
2,玉瓔,0
3,於鄴,1
4,越英,0
5,蘊萱,0
6,子頎,0
7,靖曦,0
8,魯萊,1
9,永遠,1
10,紅孫,1
我們採用的方法是統計名字(除去姓氏)中所有出現的字元形成一個字元表,將此字元表作為特徵模板,對於某個名字,當其中出現了字元表中的某個字元時,我們將模板中的該位置標記為1,其它位置標記為0,經過這樣的處理後特徵模板轉化為了特徵向量。
我們在實踐過程中將100000個資料作為訓練集、20000個資料作為測試集,訓練集中統計得到的字符集包含5276個字元,也就是說我們的特徵向量的維度為5276。
同時,選擇此種構造特徵向量的方式也有其它好處:儲存特徵向量時,由於特徵向量是十分稀疏的多熱向量,所以我們只需儲存那些值為1的點即可,而通常值為1的點的數量不會超過2,這樣可以大大節省儲存空間與運算時間。
2. 核心程式碼介紹:
- 獲得字符集:
- 將資料集轉化為簡化的特徵向量以及標籤:
- 訓練:
在訓練中,我們需要關注的是權重以及偏執的初始值、世代與學習率這些超引數的選取,同時,特徵向量是在訓練過程中動態生成的,減少了儲存空間。
3. 模型評價:
當我們不進行訓練,只使用權重為0.01、偏置值為0.5的模型進行測試時,準確率為55%。
當世代為4、學習率為0.25時,模型預測的準確率接近80%。
對於這樣的結果,考量資料集本身的問題,會發現一些資料的標籤明顯有問題,同時資料中的名字大多是兩個字,對一個字的名字的預測準確率較低。實際上,對於生活中的常見名字,此模型的預測準確率還是比較高的。
4. 完整程式碼:
import json
import numpy as np
class MyModel(object):
def __init__(self):
self.orginal_path = r'train.txt'
self.data_path = r'clear_train.json'
self.test_data = r'clear_test.json'
self.slot = r'slot.json'
self.feature_vectors = r'feature_vectors.json'
self.label = r'label.json'
self.w = r'model_w.json'
self.b = r'model_b.json'
self.slotNum = 5276
def clear_orginal_data(self):
data = []
flag = 0
with open(self.orginal_path,'r',encoding='utf-8') as f_obj:
for line in f_obj:
if flag >= 100000:
break
now_data = line.strip().split(',')[1:]
if now_data[1] == '0':
now_data[1] = -1
else:
now_data[1] = 1
data.append(now_data)
flag += 1
print(len(data))
print(data[0])
print(data[len(data) - 1])
input()
with open(self.data_path,'w') as f_obj:
f_obj.write(json.dumps(data))
def get_slot(self):
with open(self.data_path,'r') as f_obj:
data = json.loads(f_obj.read())
slot = []
for i in range(len(data)):
for j in range(len(data[i][0])):
slot.append(data[i][0][j])
slot = list(set(slot))
print(len(slot))
with open(self.slot,'w') as f_obj:
f_obj.write(json.dumps(slot))
def get_feature_vectors_and_label(self):
with open(self.data_path,'r') as f_obj:
data = json.loads(f_obj.read())
with open(self.slot,'r') as f_obj:
slot = json.loads(f_obj.read())
feature_vectors = []
label = []
for i in range(len(data)):
label.append(data[i][1])
feature = []
for j in range(len(data[i][0])):
feature.append(slot.index(data[i][0][j]))
feature_vectors.append(feature)
print(len(label))
print(label[0:10])
print(len(feature_vectors))
print(feature_vectors[0:10])
input()
with open(self.label,'w') as f_obj:
f_obj.write(json.dumps(label))
with open(self.feature_vectors,'w') as f_obj:
f_obj.write(json.dumps(feature_vectors))
def sign(self,x):
if x >= 0:
return 1
else:
return -1
def perceptron(self,w,x,b):
w = np.array(w)
x = np.array(x)
return self.sign(np.dot(w,x) + b)
def train(self,epoch=4,alpha=0.25):
with open(self.label,'r') as f_obj:
label = json.loads(f_obj.read())
with open(self.feature_vectors,'r') as f_obj:
feature_vectors = json.loads(f_obj.read())
b = 0.5
w = np.ones(self.slotNum,float) * 0.001
for e in range(epoch):
for i in range(len(label)):
y_i = label[i]
x_i = np.zeros(self.slotNum,float)
for j in range(len(feature_vectors[i])):
x_i[feature_vectors[i][j]] = 1
if self.perceptron(w,x_i,b) * y_i <= 0:
w = w + alpha * y_i * x_i
b = b + alpha * y_i
with open(self.w,'w') as f_obj:
f_obj.write(json.dumps(list(w)))
with open(self.b,'w') as f_obj:
f_obj.write(json.dumps(b))
def pred(self,name):
with open(self.slot,'r') as f_obj:
slot = json.loads(f_obj.read())
with open(self.w,'r') as f_obj:
w = json.loads(f_obj.read())
with open(self.b,'r') as f_obj:
b = json.loads(f_obj.read())
x = np.zeros(self.slotNum,float)
for i in range(len(name)):
if i == 0:
continue
try:
x[slot.index(name[i])] = 1
except:
print('字型檔中無{}字'.format(name[i]))
result = self.perceptron(w,x,b)
if result == 1:
return '男'
else:
return '女'
def clear_test_data(self):
data = []
flag = 0
with open(self.orginal_path,'r',encoding='utf-8') as f_obj:
for line in f_obj:
if flag >= 100000:
now_data = line.strip().split(',')[1:]
if now_data[1] == '0':
now_data[1] = -1
else:
now_data[1] = 1
data.append(now_data)
flag += 1
print(len(data))
print(data[0:10])
input()
with open(self.test_data,'w') as f_obj:
f_obj.write(json.dumps(data))
def test(self):
with open(self.slot,'r') as f_obj:
slot = json.loads(f_obj.read())
with open(self.w,'r') as f_obj:
w = json.loads(f_obj.read())
with open(self.b,'r') as f_obj:
b = json.loads(f_obj.read())
with open(self.test_data,'r') as f_obj:
data = json.loads(f_obj.read())
feature_vectors = []
label = []
no = []
error = 0
for i in range(len(data)):
feature = []
flag = 0
for j in range(len(data[i][0])):
try:
feature.append(slot.index(data[i][0][j]))
except:
error += 1
flag = 1
break
if flag == 0:
feature_vectors.append(feature)
label.append(data[i][1])
all_simple_num = len(label)
success_num = 0
for i in range(len(label)):
x_i = np.zeros(self.slotNum,float)
for j in range(len(feature_vectors[i])):
x_i[feature_vectors[i][j]] = 1
if (label[i] == self.perceptron(w,x_i,b)):
success_num += 1
print(success_num / all_simple_num)
相關文章
- 基於結構化感知機的詞性標註與命名實體識別框架詞性標註框架
- 基於結構化平均感知機的分詞器Java實現分詞Java
- 基於Python的滲透測試資訊收集系統的設計和實現Python
- 基於Python實現的口罩佩戴檢測Python
- 基於前端技術實現的全面預算編制系統前端
- 【python3】基於隨機森林的氣溫預測Python隨機森林
- 機器學習 | 基於機器學習的推薦系統客戶購買可能性預測分析機器學習
- 【摸魚神器】基於python的BOSS識別系統Python
- 基於深度學習的人臉性別識別系統(含UI介面,Python程式碼)深度學習UIPython
- 基於MXNET框架的線性迴歸從零實現(房價預測為例)框架
- 基於 Kubernetes 實踐彈性的 CI/CD 系統
- 基於裝置監控運維管理平臺實現預測性維護運維
- Unity——基於ShaderLab實現光照系統Unity
- 基於mtcnn/facenet/tensorflow實現人臉識別登入系統CNN
- 基於Java+SpringBoot心理測評心理測試系統功能實現九JavaSpring Boot
- 基於Java+SpringBoot心理測評心理測試系統功能實現十JavaSpring Boot
- 基於SSH培訓機構管理系統的設計與實現
- 基於統計的預警:同環比預警實現深度剖析
- 感知機簡單實現
- 預處理(3):python實現用scikit-learn實現的線性判別分析(LDA)PythonLDA
- Python 基於 selenium 實現不同商城的商品價格差異分析系統Python
- 採用線性迴歸實現訓練和預測(Python)Python
- 基於Python的Xgboost模型實現Python模型
- 基於Python實現MapReducePython
- 機器學習實戰 | 性別預測模型的構建與優化機器學習模型優化
- 基於施工現場安全的安全帽識別系統
- 實現智慧機器預測性維護收益的三個步驟
- HanLP-基於HMM-Viterbi的人名識別原理介紹HanLPHMMViterbi
- 機器學習入門實戰——基於knn的airbnb房租預測機器學習KNNAI
- 基於ZooKeeper,Spring設計實現的引數系統Spring
- 基於Netty的Android系統IM簡單實現原理NettyAndroid
- 基於YOLOv4的目標檢測系統(附MATLAB程式碼+GUI實現)YOLOMatlabGUI
- 基於施耐德PLC的水位測控系統如何實現遠端監控上下載
- 實現基於內容的電影推薦系統—程式碼實現
- [python] 基於PyOD庫實現資料異常檢測Python
- 實現基於React的全域性提示元件ToastReact元件AST
- 統計學習方法c++實現之一 感知機
- 老人跌倒檢測識別預警系統