《Python數(shù)據(jù)挖掘入門與實踐》第一章第五節(jié)(1.5)中關于分類問題提到了一種簡單實用的分類算法——OneR算法。
其實現(xiàn)方式多少有點麻煩,本人不才,用Pandas庫用對其代碼進行了優(yōu)化,這里介紹了兩者優(yōu)化的方式。
(什么是OneR算法?戳這里http://blog.csdn.net/baidu_25555389/article/details/73379036)
本次所有代碼的運行環(huán)境均為Anoconda的jupyter notebook。
方法一,在作者思路上進行優(yōu)化
作者的思路是首先創(chuàng)建一個函數(shù),給定這個函數(shù)數(shù)據(jù)集,特征類,特征值,即可計算出這個特征值所對應因變量類別出現(xiàn)的次數(shù),并進行錯誤率或者準確率計算。
這里用的數(shù)據(jù)是經(jīng)典的“鳶尾花”數(shù)據(jù),其數(shù)據(jù)可以直接再scikit-learn庫中進行導入。特征主要有四個:'萼片長度','萼片寬度', '花瓣長度', '花瓣寬度'。
因變量y有三個類別分別為'山鳶尾','變色鳶尾','維吉尼亞鳶尾'
每個特征值均為連續(xù)變量,首先將其以均值為分解點,將每個特征劃分為兩類(高低兩類)。
1、導入數(shù)據(jù)
from sklearn.datasets import load_iris
import pandas as pd
import numpy as np
# 導入數(shù)據(jù)
dataset = load_iris()
x = dataset.data
y = dataset.target
# 導入pd的dataframe
df = pd.DataFrame(x,columns=['x%s'% str(i+1) for i in range(4)])
df['y'] = pd.Series(y)
df.head()
df.describe().round(3)

2、將特征值離散化
# 以均值對每個特征進行區(qū)分,遍歷每個值與均值做個減法
df = df.assign(sl=lambda x : x.x1 - x.x1.mean())
df = df.assign(sw=lambda x : x.x2 - x.x2.mean())
df = df.assign(pl=lambda x : x.x3 - x.x3.mean())
df = df.assign(pw=lambda x : x.x4 - x.x4.mean())
# 將每個自變量的值與0進行比較
df2 = df.iloc[:,5:].round(3) > 0
df2['y'] = pd.Series(y)
# 將大于0的True設置為1,將小于0的Fales設置為0
dict_map = {
False:0,
True:1
}
# 遍歷每一列用map方法進行轉換
for i in range(4):
df2.iloc[:,i] = df2.iloc[:,i].map(dict_map)
df2.head()

其中sl,sw,pl,pw分別代表離散處理后的'萼片長度','萼片寬度', '花瓣長度', '花瓣寬度'。
3、將數(shù)據(jù)集劃分為訓練集和測試集
from sklearn.model_selection import train_test_split
X, y = df2.iloc[:,:4],df.iloc[:,4].values
X_train, X_test, y_train, y_test = train_test_split(X, y ,test_size = 0.25, random_state = 0)
4、定義類別統(tǒng)計函數(shù)
# 自定義一個函數(shù),統(tǒng)計具有給定特征值的個體在各個類別中出現(xiàn)的次數(shù),并以datafranme的形式返回。
def train_feature_value(X, y, feature_index, feature_val):
# 給index和columns定義基礎值
feature = {
0 : '萼片長',
1 : '萼片寬',
2 : '花瓣長',
3 : '花瓣寬',
}
values = {
0 : ' -- 低',
1 : ' -- 高',
}
# 設置初始dataframe
df_error = pd.DataFrame(np.zeros((1,3)),
index=[feature[feature_index]+values[feature_val]],
columns=['山鳶尾','變色鳶尾','維吉尼亞鳶尾'])
# 遍歷,尋找,增加
for sample, i in zip(X.iterrows(),y):
if sample[1][feature_index] == feature_val:
df_error.iloc[0,i] += 1
return df_error
4、遍歷所有特征并計算
frames = []
for i in range(4):
for j in range(2):
df_error = train_feature_value(X_train,y_train,i,j)
frames.append(df_error)
# 將所有的datafram合并
result = pd.concat(frames)
result

5、遍歷每個特征,并計算所對應每個類別的準確率
for i in range(len(result)):
result.iloc[i] = result.iloc[i]/result_sum[i]
result.round(3)

由此可以得到每個類別的鳶尾花所對應的主要特征,其中山鳶尾所對應的唯一特征是,花瓣長度值低;變色鳶尾所對應唯一特征為萼片寬度低;維吉尼亞鳶尾所對應的唯一特征為萼片長度高;

6、選取花瓣長度,來預測山鳶尾
X_test['y'] = X_test['pl']
true_counts = 0
for i , j in zip(X_test.iloc[:,4],y_test):
if i == j:
true_counts += 1
print('預測準確率為%.2f%%' % (true_counts/len(y_test)*100))
最終預測準確率為73.68%。雖然準確率并不高,但考慮到只用到了一個特征, 這個結果已經(jīng)很理想了。
方法二,用交叉表直接得到特征類別數(shù)量表
運用Pandas自帶的crosstab方法可以快速計算類別特征數(shù)量
X_train['y'] = y_train
train_data = X_train
feature = {
0 : '萼片長',
1 : '萼片寬',
2 : '花瓣長',
3 : '花瓣寬',
}
values = {
0 : ' -- 高',
1 : ' -- 低',
}
frames2 = []
for i in range(4):
df2=pd.crosstab(train_data.iloc[:,i],train_data.iloc[:,4])
frames2.append(df2)
df4 = pd.concat(frames2)
df4['index'] = result.index
df4.columns = ['山鳶尾','變色鳶尾','維吉尼亞鳶尾','index']
df4.set_index('index')

第二種方法比較簡單直接,計算出統(tǒng)計表以后再用前面代碼進行準確率計算,提取主要特征,進行預測即可,在此不作贅述。