資料探勘學習(四)——常見案例總結
1、K-meaning演算法實戰
主要是通過均值來聚類的一個方法。
步驟為:
1)隨機選擇k個點作為聚類中心;
2)計算各個點到這k個點的距離,將距離相近的點聚集在一起,行程k個類;
3)將對應的點聚到與他最近的聚類中心;
4)分成k個聚類之後,重新計算聚類中心;
5)比較當前聚類中心與前一次聚類中心,如果是同一個點,則聚類收斂,得到聚類結果;如果為不同的點,則重複第二到五步。
#!/usr/bin/env python
# _*_ UTF-8 _*_
import numpy as npy
import pandas as pda
import matplotlib.pylab as pyl
# 通過程式實現錄取學生的聚類;
dataf = pda.read_csv(fname)
x = dataf.iloc[:, 1:4].as_matrix()
from sklearn.cluster import Birch
from sklearn.cluster import KMeans
# 呼叫kmeans方法,指定聚4類。
kms = KMeans(n_clusters=4)
y = kms.fit_predict(x)
# 一個y代表一個點,數字表示屬於第幾類。
print(y)
print(x)
# x代表學生
s = npy.arange(
pyl.plot(s, y, "o")
pyl.show()
# 通過聚類實現商品的聚類:
# 淘寶商品的聚類:
import matplotlib.pylab as pyl
import pymysql
conn = pymysql.connect(host="localhost",
user="root",
password="123456",
db="livan",
port=3306,
sql="select price, comments from goods"
dataf2 = pda.read_sql(sql, conn)
x = dataf2.iloc[:,:].as_matrix()
from sklearn.cluster import Birch
from sklearn.cluster import KMeans
# 呼叫kmeans方法,指定聚3類。
kms = KMeans(n_clusters=3)
y = kms.fit_predict(x)
print(y)
for i in range(0, len(y)):
if(y[i]==0):
pyl.plot(dataf2.iloc[i:i+1, 0:1].as_matrix(),
dataf2.iloc[i:i+1, 1:2].as_matrix(),
"*r")
elif(y[i]==1):
pyl.plot(dataf2.iloc[i:i+1, 0:1].as_matrix(),
dataf2.iloc[i:i+1, 1:2].as_matrix(),
"sy")
elif(y[i]==2):
pyl.plot(dataf2.iloc[i:i+1, 0:1].as_matrix(),
dataf2.iloc[i:i+1, 1:2].as_matrix(),
"pk")
pyl.show()
2、決策樹:
#!/usr/bin/env python
# _*_ UTF-8 _*_
import pandas as pda
# 資訊熵:信源的不確定度。
fname = "F:/python_workspace/file/lessons.csv"
dataf = pda.read_csv(fname)
# 提取某行列,然後轉換成矩陣[行,列]
x = dataf.iloc[:, 1:5].as_matrix()
y = dataf.iloc[:, 5].as_matrix()
# x為二維陣列,可以對其進行遍歷,遇到是、多等欄位變為1
# 遇到否、少等欄位變為0;
for i in range(0, len(x)):
for j in range(0, len(x[i])):
thisdata = x[i][j]
if(thisdata =="是" or thisdata=="多" or thisdata=="高"):
x[i][j] = int(1)
else:
x[i][j] = -1
for i in range(0, len(y)):
thisdata = y[i]
if(thisdata=="高"):
y[i] = 1
else:
y[i] = -1
# 容易錯的地方:
# 正確的做法為:轉化好格式,將xy轉化為資料框,然後再轉化為陣列並制定格式。
xf = pda.DataFrame(x)
yf = pda.DataFrame(y)
x2 = xf.as_matrix().astype(int)
y2 = yf.as_matrix().astype(int)
# 建立決策樹:
from sklearn.tree import DecisionTreeClassifier as DTC
# 資訊熵的模式entropy
dtc = DTC(criterion="entropy")
dtc.fit(x2, y2)
# 直接預測銷量高低:
import numpy as npy
x3 = npy.array([[1, -1, -1, 1], [1, 1, 1, 1], [-1, 1, -1, 1]])
rst = dtc.predict(x3)
print(rst)
# 視覺化決策樹:
from sklearn.tree import export_graphviz
from sklearn.externals.six import StringIO
with open("F:/python_workspace/file/decision_tree/dtc.dot", "w") as file:
# 引數為:模式、特徵值(實戰、課時數、是否促銷、是否提供配套資料)
export_graphviz(dtc, feature_names=["combat", "num", "promotion", "datum"], out_file=file)
# 此時已經生成決策樹,但是dot的檔案打不開,此時需要使用graph的軟體開啟。
Dot的使用方法:
可以得到決策樹:
決策樹往左看——負能量;往右看——正能量;
Entropy是資訊熵,value是銷量高地的統計情況【14,15】:即14是銷量低的,15是銷量高的。決策樹會通過一層層的使用特徵值,來劃分資料。
3、邏輯迴歸:求解邏輯迴歸引數的傳統方法是梯度下降,構造為凸函式的代價函式後,每次沿著偏導方向(下降速度最快方向)邁進一小部分,直至N次迭代後到達最低點。
#!/usr/bin/env python
# _*_ UTF-8 _*_
import pandas as pda
fname = "F:/python_workspace/file/logic/luqu.csv"
dataf = pda.read_csv(fname)
# [行,列]
x = dataf.iloc[:, 1:4].as_matrix()
y = dataf.iloc[:, 0:1].as_matrix()
from sklearn.linear_model import LogisticRegression as LR
from sklearn.linear_model import RandomizedLogisticRegression as RLR
# 建立一個邏輯迴歸模型
r1 = RLR()
# 訓練模型
r1.fit(x, y)
# 特徵值篩選,獲取有效特徵。
r1.get_support()
# print(dataf.columns[r1.get_support()])
# 將可用的特徵值引數轉換成陣列,用來預測y值。
t = dataf[dataf.columns[r1.get_support()]].as_matrix()
r2 = LR()
# 建立xy之間的關係並進行訓練。
r2.fit(t, y)
print("訓練結束")
print("模型正確率為:"+str(r2.score(x, y)))
4、貝葉斯分類器:
思路為:
1、給定一個訓練集、一個對應的標籤集,訓練集中的每一個數據點x(對應有多個維度(a1,a2,a3,a4))對應有一個標籤A,即該訓練集已經做好分類。
2、對給定的標籤集進行計算,各個標籤A在標籤集中佔的比例即為訓練集中某一類A出現的出現概率。
3、在訓練集中,某一類別中的資料有多個維度(a1,a2,a3,a4),各個維度值在這一類別A中的比例可以計算得出。
4、然後再使用貝葉斯公式計算新出現的資料的概率。#!/usr/bin/env python
# _*_ UTF-8 _*_
import numpy as npy
# 貝葉斯分類:
class Bayes:
def __init__(self):
# -1表示測試方法沒有做,表示沒有進行訓練。
self.length = -1
# 分類的類別標籤
self.labelcount = dict()
self.vectorcount = dict()
# 訓練函式:(dataSet:list 訓練集指定為list型別)
def fit(self, dataSet:list, labels:list):
if(len(dataSet)!=len(labels)):
raise ValueError("您輸入的測試陣列跟類別陣列長度不一致~")
self.length = len(dataSet[0]) # 測試資料特徵值的長度。
# 所有類別的資料
labelsnum = len(labels)
# 不重複的類別的數量
norepeatlabel = set(labels)
# 以此遍歷各個類別
for item in norepeatlabel:
# 計算當前類別佔總類別的比例:
# thislabel為當前類別
thislabel = item
# 當前類別在總類別中的比例;
labelcount[thislabel]= labels.count(thislabel)/labelsnum
for vector, label in zip(dataSet, labels):
if(label not in vectorcount):
self.vectorcount[label]= []
self.vectorcount[label].append(vector)
print("訓練結束~")
return self
# 測試資料:
def btest(self, TestData, labelsSet):
if(self, length==-1):
raise ValueError("您還沒有進行訓練,請先訓練~~")
# 計算testdata分別為各個類別的概率:
lbDict = dict()
for thislb in labelsSet:
p = 1
# 當前類別佔總類別的比例:
alllabel = self.labelcount[thislb]
# 當前類別中的所有向量:
allvector = self.vectorcount[thislb]
# 當前類別一共有多少個向量:
vnum = len(allvector)
# 陣列轉置
allvector =npy.array(allvector).T
for index in range(0, len(TestData)):
vector = list(allvector[index])
p* = vector.count(TestData[index])/vnum
lbDict[thislb] = p*alllabel
thislabel = sorted(lbDict, key=lambda x:lbDict[x], reverse=True)[0]
return thislabel
5、KNN手寫體數字識別:
此處使用畫圖工具,建立一個含手寫體數字的圖片檔案,然後找一些訓練資料:
1)訓練資料:
0、1、2、3、4、5、6、7、8、9,共十種手寫體資料,用來訓練程式,此處使用trainDigits;
2)測試資料:
即將之前的圖片轉換成的txt檔案作為測試檔案,此處使用testDigits;
3)圖片處理:
在進行二維碼或者圖片數字識別時,需要將圖片轉換成txt的二進位制檔案,行程一個檔案流。
KNN演算法的主要思路為:
1)計算輸入點與訓練集中點的位置(歐式距離演算法);
2)對計算出來的資料按照從小到大排序,最前面的為輸入點到訓練集中點的最短距離;
3)取出前k個距離值,並對距離值進行分組;
4)標記各組資料的多少,最多的標籤值即為輸入點的所在類別。
#!/usr/bin/env python
# _*_ UTF-8 _*_
from PIL import Image
from numpy import *
import operator
from os import listdir
# # 圖片處理
# # 先將所有圖片轉換為固定寬高,比如:32*32,然後再轉換成文字。
# im = Image.open("F:/python_workspace/file/hand_write/hand_write.png")
# # 另存為圖片:
# #im.save("F:/python_workspace/file/hand_write/hand_write.jpg")
# fh =open("F:/python_workspace/file/hand_write/hand_write.txt","a")
# # 獲取圖片的長寬高: 0:寬;1:高;
# width = im.size[0]
# height = im.size[1]
# # 獲取畫素(寬為1,高為9的畫素):
# # (255, 255, 255):白色
# # (0,0,0):黑色
# for i in range(0, width):
# for j in range(0, height):
# cl = im.getpixel((i, j))
# clall = cl[0]+cl[1]+cl[2]
# if(clall == 0):
# # 黑色;
# fh.write("1")
# else:
# fh.write("0")
# fh.write("\n")
# fh.close()
# 運算knn函式:
def knn(k, testdata, traindata, labels):
traindatasize = traindata.shape[0]
dif = tile(testdata, (traindatasize, 1))-traindata
sqdif = dif**2
sumsqdif =sqdif.sum(axis=1)
distance = sumsqdif**0.5
sortdistance =distance.argsort()
count = {}
for i in range(0, k):
vote = labels[sortdistance[i]]
count[vote] = count.get(vote, 0)+1
sortcount = sorted(count.items(), key=operator.itemgetter(1), reverse=True)
return sortcount[0][0]
# 手寫體數字的識別:
# 1.載入資料
def datatoarray(fname):
arr = []
fh = open(fname)
for i in range(0, 32):
thisline = fh.readline()
for j in range(0, 32):
arr.append(int(thisline[j]))
return arr
# arr1 = datatoarray("F:/python_workspace/file/hand_write/trainingDigits/0_10.txt")
# print(arr1)
# 建立一個函式取檔案的字首:
def seplabel(fname):
filestr = fname.split(".")[0]
label = int(filestr.split("_")[0])
return label
# 2.建立訓練資料:
def traindata():
labels = []
# 載入當前目錄下的所有檔名:
trainfile =listdir("F:/python_workspace/file/hand_write/trainingDigits")
num = len(trainfile)
# 長度為1024,即為1024列,每一行儲存一個檔案。
# 用一個數組儲存所有訓練資料,行:檔案總數;列:1024
# 用zeros建立一個數組:
trainarr =zeros((num, 1024))
for i in range(0, num):
thisfname = trainfile[i]
# 返回的是訓練數字labels(0--9)
thislabel =seplabel(thisfname)
labels.append(thislabel)
# 將所有檔案的訓練集資料內容載入到trainarr中。
trainarr[i, :] =datatoarray("F:/python_workspace/file/hand_write/trainingDigits/"+thisfname)
return trainarr, labels
# 3.用測試資料呼叫knn演算法測試,看是否能夠準確識別:
def datatest():
trainarr, labels =traindata()
testlist = listdir("F:/python_workspace/file/hand_write/testDigits")
tnum = len(testlist)
for i in range(0, tnum):
thistestfile = testlist[i]
testarr = datatoarray("F:/python_workspace/file/hand_write/testDigits/"+thistestfile)
rknn = knn(3, testarr, trainarr, labels)
print(rknn)
datatest()
# 4.抽某一個測試檔案出來進行試驗:
trainarr, labels = traindata()
thistestfile = "6_6.txt"
testarr = datatoarray("F:/python_workspace/file/hand_write/testDigits/"+thistestfile)
rknn = knn(3, testarr, trainarr, labels)
print(rknn)
6、貝葉斯手寫體數字識別:
#!/usr/bin/env python
# _*_ UTF-8 _*_
import numpy as npy
from numpy import *
from os import listdir
# 貝葉斯演算法的應用:
class Bayes:
def __init__(self):
# -1表示測試方法沒有做,表示沒有進行訓練。
self.length = -1
# 分類的類別標籤
self.labelcount = dict()
self.vectorcount = dict()
# 訓練函式:(dataSet:list 訓練集指定為list型別)
def fit(self, dataSet:list, labels:list):
if(len(dataSet)!=len(labels)):
raise ValueError("您輸入的測試陣列跟類別陣列長度不一致~")
self.length = len(dataSet[0]) # 測試資料特徵值的長度。
# 所有類別的資料
labelsnum = len(labels)
# 不重複的類別的數量
norepeatlabel = set(labels)
# 以此遍歷各個類別
for item in norepeatlabel:
# 計算當前類別佔總類別的比例:
# thislabel為當前類別
thislabel = item
# 當前類別在總類別中的比例;
self.labelcount[thislabel]= labels.count(thislabel)/labelsnum
for vector, label in zip(dataSet, labels):
if(label not in self.vectorcount):
self.vectorcount[label]= []
self.vectorcount[label].append(vector)
print("訓練結束~")
return self
# 測試資料:
def btest(self, TestData, labelsSet):
if(self.length==-1):
raise ValueError("您還沒有進行訓練,請先訓練~~")
# 計算testdata分別為各個類別的概率:
lbDict = dict()
for thislb in labelsSet:
p = 1
# 當前類別佔總類別的比例:
alllabel = self.labelcount[thislb]
# 當前類別中的所有向量:
allvector = self.vectorcount[thislb]
# 當前類別一共有多少個向量:
vnum = len(allvector)
# 陣列轉置
allvector =npy.array(allvector).T
for index in range(0, len(TestData)):
vector = list(allvector[index])
p = vector.count(TestData[index])/vnum
lbDict[thislb] = p*alllabel
thislabel = sorted(lbDict, key=lambda x:lbDict[x], reverse=True)[0]
return thislabel
# 手寫體數字的識別:
# 1.載入資料
def datatoarray(fname):
arr = []
fh = open(fname)
for i in range(0, 32):
thisline = fh.readline()
for j in range(0, 32):
arr.append(int(thisline[j]))
return arr
# 建立一個函式取檔案的字首:
def seplabel(fname):
filestr = fname.split(".")[0]
label = int(filestr.split("_")[0])
return label
# 2.建立訓練資料:
def traindata():
labels = []
# 載入當前目錄下的所有檔名:
trainfile =listdir("F:/python_workspace/file/hand_write/trainingDigits")
num = len(trainfile)
# 長度為1024,即為1024列,每一行儲存一個檔案。
# 用一個數組儲存所有訓練資料,行:檔案總數;列:1024
# 用zeros建立一個數組