使用Python在Weka中选择特征
Weka是一个用于数据挖掘任务的机器学习算法的集合。Weka上的大部分操作都是在图形用户界面上进行的。然而,这限制了用户的编程经验和对幕后操作的理解。
这就是本文的灵感所在,它通过实际编写Python代码来说明Weka中的特征选择。
什么是特征选择
特征选择是一种减少提供给机器学习模型的输入数量的方法,以便只使用相关的输入。该技术的应用是为了提高机器学习模型的准确性。
特征选择的类型
有三种特征选择技术;包装器、过滤器和嵌入式方法。包装器特征选择方法用输入特征的不同子集创建几个模型。然后,它根据选择前预设的性能矩阵来选择性能最好的模型。
筛选特征选择法取每个输入变量和目标输出之间的关系值。然后,每个关系的分数被用来选择哪些属性要包括在数据集中。
嵌入方法利用了包装器和过滤器方法的优点。此外,它还仔细选择了对特定训练迭代结果有贡献的最关键属性。
特征选择的好处?
特征选择的应用是为了改善机器学习过程,加快预测的速度。由于它只选择必要的变量,因此利用数据集中所有属性的时间被降到了最低。它也消除了多余的和不相关的特征,这些特征会花费更多的时间。
前提条件
要继续学习本教程,你应该具备以下条件。
- Python 3
- Python Weka Wrapper
- 打开JDK 8
为特征选择建立一个环境
首先使用下面的命令创建一个虚拟环境。
virtualenv venv
接下来,用下面的命令激活创建的虚拟环境。
source venv/bin/activate
为了设置开发环境,你需要安装以下软件包。
cycler==0.11.0
fonttools==4.30.0
joblib==1.1.0
kiwisolver==1.4.0
numpy==1.22.3
packaging==21.3
Pillow==9.0.1
pyparsing==3.0.7
python-dateutil==2.8.2
six==1.16.0
tomli==2.0.1
weka==1.0.6
安装它们的最简单方法是在创建虚拟环境的根目录下创建一个requirements.txt 文件,然后执行下面的命令。
pip install -r requirements.txt
在这个步骤中,创建一个名为feature-selection.py 的文件,然后导入所需的库,如下图所示。在我们继续进行时,我们将看到每个库是如何使用的。
import traceback
from itertools import combinations
from math import ceil, log2
import weka.core.jvm as jvm
from weka.classifiers import Classifier, Evaluation
from weka.core.classes import Random
from weka.core.converters import Loader
from weka.filters import Filter
读取数据集
我们将从读取数据集开始。我们将使用糖尿病疾病数据集,你可以通过这个链接找到它。
要加载数据集,请使用下面的代码片段。
def load_dataset():
loader = Loader("weka.core.converters.ArffLoader")
dataset = loader.load_file("diabetes.arff", class_index="last")
return dataset
选择属性
这一步将首先设置一个我们将在程序中使用的分类器算法的列表。然后,这些算法将被用来评估模型的准确性,并确定哪些特征能给出最准确的分类。
def select_attributes(dataset):
classifier_algorithms = [
("IBk KNN", Classifier(classname="weka.classifiers.lazy.IBk")),
("Naive Bayes", Classifier(classname="weka.classifiers.bayes.NaiveBayes")),
("J48 Decision Tree", Classifier(classname="weka.classifiers.trees.J48")),
]
接下来,我们需要指定要处理的列数。列的数量是由数据集中的属性总数减去一个,即分类结果得到的。
number_of_columns = dataset.num_attributes - 1
接下来,我们确定数据集中所有可能的列组合。我们这样做是因为我们试图找到所有可能的属性组合,然后从那里找到性能最好的组合。
column_combinations = []
for r in range(1, number_of_columns + 1):
column_combinations.extend(list(combinations(range(number_of_columns), r)))
接下来,我们通过使用下面的代码片断删除较少的必要属性,从输入数据集中获得一个过滤的数据集。
results = {classifier[0]: [] for classifier in classifier_algorithms}
for selected_columns in column_combinations:
columns_to_remove = set(range(number_of_columns)) - set(selected_columns)
remove = Filter(
classname="weka.filters.unsupervised.attribute.Remove",
options=["-R", ",".join(map(lambda x: str(x + 1), columns_to_remove))],
)
remove.inputformat(dataset)
filtered = remove.filter(dataset)
for classifier_name, classifier in classifier_algorithms:
classifier.build_classifier(filtered)
evaluation = Evaluation(filtered)
evaluation.crossvalidate_model(classifier, filtered, 5, Random(42))
results[classifier_name].append(
(filtered.attribute_names()[:-1], evaluation.percent_correct)
)
接下来,我们为前面所述的算法列表中的每个算法返回分类器结果。
for classifier, result in results.items():
results[classifier] = sorted(result, key=lambda x: x[1], reverse=True)
return results
关于主函数的工作
主函数是所有其他函数被调用执行的地方。这里的第一件事是调用read data函数来读取我们打算使用的数据集。
def main():
dataset = load_dataset()
接下来,我们存储所有的列名,不包括分类类列。
columns = dataset.attribute_names()[:-1]
然后我们调用select_attributes 函数来执行属性选择。
results = select_attributes(dataset)
在下一步,我们将打印每一列及其对模型预测的表现,以帮助我们知道什么属性对模型的预测贡献了多少百分比。
columns_performance = dict.fromkeys(columns, 0)
for classifier_name, result in results.items():
print(classifier_name)
to_n_attributes = 5
print_results("Best", result[:to_n_attributes])
for selected_columns, accuracy in result:
number_selected = len(selected_columns)
for column in columns:
if column in selected_columns:
columns_performance[column] += accuracy / number_selected
columns_performance = dict(sorted(columns_performance.items(), key=lambda item: item[1], reverse=True))
# Printing the attribute importance
print("\nAttribute Importance in the Dataset")
for column, performance in columns_performance.items():
print(f"\t{column}: {performance}")
最后,添加下面的代码片断来打印最终结果。
def print_results(result_type, result):
print(f"\t{result_type}")
for columns, accuracy in result:
print(f"\t\t{columns}: {accuracy:.4f}%")
驱动程序代码
我们需要指定调用JVM的主要函数,因为Weka库需要JVM来运行。创建下面的函数,它将在需要执行时启动JVM,并在完成后停止它。
if __name__ == "__main__":
try:
jvm.start()
main()
except Exception as e:
print(traceback.format_exc())
finally:
jvm.stop()
测试代码
当我们运行我们的代码时,它会给出每个分类算法的输出和选定的最佳属性。它还会打印出基本属性,也就是所选属性。
Columns: ['preg', 'plas', 'pres', 'skin', 'insu', 'mass', 'pedi', 'age']
IBk KNN
Best
['preg', 'plas', 'insu', 'mass']: 72.3958%
['preg', 'plas', 'pres', 'insu']: 72.0052%
['preg', 'plas', 'pres', 'insu', 'mass', 'pedi', 'age']: 71.7448%
['plas', 'insu', 'age']: 71.3542%
['preg', 'plas', 'insu', 'age']: 70.9635%
Naive Bayes
Best
['plas', 'mass', 'pedi', 'age']: 77.3438%
['preg', 'plas', 'pres', 'mass', 'pedi']: 77.0833%
['preg', 'plas', 'pres', 'insu', 'mass', 'pedi']: 76.9531%
['preg', 'plas', 'pres', 'skin', 'mass', 'pedi']: 76.6927%
['preg', 'plas', 'pres', 'pedi']: 76.5625%
J48 Decision Tree
Best
['plas', 'pres', 'mass', 'pedi', 'age']: 75.6510%
['plas', 'pres', 'mass', 'age']: 75.5208%
['plas', 'pres', 'skin', 'mass', 'age']: 75.5208%
['preg', 'plas', 'pres', 'skin']: 75.3906%
['plas', 'pres', 'skin', 'mass', 'pedi', 'age']: 75.3906%
Attribute importance (heuristic):
plas: 6919.9380
mass: 6600.2365
preg: 6579.5027
insu: 6556.4481
age: 6552.0908
总结
在本教程中,我们使用Weka包装库来演示如何使用Python编程语言进行特征选择。首先,我们加载了数据,并使用三种算法来确定对糖尿病数据集进行分类时最关键的特征。然后,我们展示了由我们的程序选择的基本特征。