编写Python代码,利用决策树方法进行最高天气预测 注意不可以使用sklearn训练模型 year,moth,day,week分别表示的具体的时间 temp_2:前天的最高温度值 temp_1:昨天的最高温度值 average:在历史中,每年这一天的平均最高温度值 actual:标签值,当天的真实最高温度 其中,原始数据中在week列中并不是一些数值特征,而是表示周几的字符串,需要进行数据预处理,使用编码方式:One-Hot Encoding,one-hot 编码类似于虚拟变量,是一种将分类变量转换为几个二进制列的方法。其中 1 代表某个输入属于该类别。数据集为temps.csv。使用创建三个python包第一个命名为"decision_tree_base.py"第二个名为"decision_tree_classifier.py"第三个命名为"random_forest_ classifier.py"最后使用graphviz画图
时间: 2024-03-10 14:44:44 浏览: 142
机器学习课设基于python实现决策树对天气降雪进行预测判断源码(带界面和数据)+项目使用说明.zip
以下是一个简单的决策树分类器的 Python 代码示例,基于 ID3 算法和信息增益作为分裂准则:
decision_tree_base.py:
```python
import numpy as np
class Node:
"""决策树节点类"""
def __init__(self, feature=None, threshold=None, value=None, left=None, right=None):
self.feature = feature # 当前节点分裂的特征
self.threshold = threshold # 当前节点分裂的阈值
self.value = value # 叶节点的预测值
self.left = left # 左子树
self.right = right # 右子树
class DecisionTree:
"""决策树分类器类"""
def __init__(self, max_depth=float('inf'), min_samples_split=2, criterion='entropy'):
self.max_depth = max_depth # 决策树的最大深度
self.min_samples_split = min_samples_split # 分裂所需的最小样本数
self.criterion = criterion # 分裂准则,默认为信息熵
self.tree = None # 决策树模型
def fit(self, X, y):
self.tree = self._build_tree(X, y, depth=0)
def predict(self, X):
y_pred = [self._predict_example(x, self.tree) for x in X]
return np.array(y_pred)
def _build_tree(self, X, y, depth):
"""递归构建决策树"""
n_samples, n_features = X.shape
# 如果样本数小于分裂所需的最小样本数,或者决策树深度达到最大深度,直接返回叶节点
if n_samples < self.min_samples_split or depth >= self.max_depth:
return Node(value=np.mean(y))
# 计算当前节点的分裂准则的值
if self.criterion == 'entropy':
gain_function = self._information_gain
elif self.criterion == 'gini':
gain_function = self._gini_impurity
gain, feature, threshold = max((gain_function(X[:, i], y), i, t)
for i in range(n_features) for t in np.unique(X[:, i]))
# 如果当前节点无法分裂,则返回叶节点
if gain == 0:
return Node(value=np.mean(y))
# 根据当前节点的最优特征和阈值进行分裂
left_idxs = X[:, feature] <= threshold
right_idxs = X[:, feature] > threshold
left = self._build_tree(X[left_idxs], y[left_idxs], depth+1)
right = self._build_tree(X[right_idxs], y[right_idxs], depth+1)
return Node(feature=feature, threshold=threshold, left=left, right=right)
def _predict_example(self, x, tree):
"""预测单个样本"""
if tree.value is not None:
return tree.value
if x[tree.feature] <= tree.threshold:
return self._predict_example(x, tree.left)
else:
return self._predict_example(x, tree.right)
def _information_gain(self, X_feature, y):
"""计算信息增益"""
entropy_parent = self._entropy(y)
n = len(X_feature)
thresholds = np.unique(X_feature)
entropies_children = [self._entropy(y[X_feature <= t]) * sum(X_feature <= t) / n
+ self._entropy(y[X_feature > t]) * sum(X_feature > t) / n
for t in thresholds]
weights_children = [sum(X_feature <= t) / n for t in thresholds]
entropy_children = sum(entropies_children)
return entropy_parent - entropy_children
def _gini_impurity(self, X_feature, y):
"""计算基尼不纯度"""
n = len(X_feature)
thresholds = np.unique(X_feature)
ginis_children = [self._gini_impurity(y[X_feature <= t]) * sum(X_feature <= t) / n
+ self._gini_impurity(y[X_feature > t]) * sum(X_feature > t) / n
for t in thresholds]
weights_children = [sum(X_feature <= t) / n for t in thresholds]
gini_children = sum(ginis_children)
return gini_children
def _entropy(self, y):
"""计算信息熵"""
_, counts = np.unique(y, return_counts=True)
probs = counts / len(y)
return -np.sum(probs * np.log2(probs + 1e-6))
```
decision_tree_classifier.py:
```python
import pandas as pd
from decision_tree_base import DecisionTree
class DecisionTreeClassifier(DecisionTree):
"""决策树分类器类"""
def __init__(self, max_depth=float('inf'), min_samples_split=2, criterion='entropy'):
super().__init__(max_depth, min_samples_split, criterion)
def fit(self, X, y):
y = pd.factorize(y)[0] # 将分类标签转换为数值
super().fit(X, y)
def predict(self, X):
y_pred = super().predict(X)
return pd.Series(y_pred).map({i: v for i, v in enumerate(np.unique(y_pred))}).values
```
random_forest_classifier.py:
```python
import numpy as np
from decision_tree_classifier import DecisionTreeClassifier
class RandomForestClassifier:
"""随机森林分类器类"""
def __init__(self, n_estimators=100, max_depth=float('inf'), min_samples_split=2,
criterion='entropy', max_features='sqrt'):
self.n_estimators = n_estimators # 决策树的数量
self.max_depth = max_depth # 决策树的最大深度
self.min_samples_split = min_samples_split # 分裂所需的最小样本数
self.criterion = criterion # 分裂准则,默认为信息熵
self.max_features = max_features # 每棵决策树使用的最大特征数
self.trees = [] # 决策树列表
def fit(self, X, y):
n_samples, n_features = X.shape
max_features = int(np.ceil(np.sqrt(n_features))) if self.max_features == 'sqrt' else self.max_features
for i in range(self.n_estimators):
tree = DecisionTreeClassifier(max_depth=self.max_depth, min_samples_split=self.min_samples_split,
criterion=self.criterion)
idxs = np.random.choice(n_samples, n_samples, replace=True) # 自助采样
X_sampled, y_sampled = X[idxs], y[idxs]
tree.fit(X_sampled[:, np.random.choice(n_features, max_features, replace=False)], y_sampled) # 随机选取特征
self.trees.append(tree)
def predict(self, X):
y_preds = np.array([tree.predict(X[:, tree.feature_importances_ > 0]) for tree in self.trees])
return np.apply_along_axis(lambda x: np.bincount(x).argmax(), axis=0, arr=y_preds)
```
关于如何使用 One-Hot Encoding 进行数据预处理,可以使用 pandas 库的 `get_dummies` 函数。例如,如果数据集中有一列名为 `week`,包含了一些字符串,我们可以将其转换为多个二进制列,每列代表一种字符串对应的编码。示例代码如下:
```python
import pandas as pd
# 读取数据集
df = pd.read_csv('temps.csv')
# 将字符串编码为多个二进制列
df_encoded = pd.get_dummies(df, columns=['week'])
```
最后,使用 graphviz 库画图可以通过以下代码实现:
```python
import graphviz
from sklearn.tree import export_graphviz
def plot_tree(tree):
"""绘制决策树"""
dot_data = export_graphviz(tree, out_file=None, feature_names=X.columns, class_names=y.unique(), filled=True)
graph = graphviz.Source(dot_data)
return graph
```
其中,`tree` 是一个决策树对象,`X` 是输入特征的 DataFrame,`y` 是标签的 Series。
阅读全文