数据挖掘大作业

1.数据处理

在数据预处理阶段,删除无关特征和处理缺失值是非常重要的一步,以确保模型的性能。以下是一些常见的方法和实用示例:

删除无关特征

  1. 特征选择: 基于相关性分析和特征重要性评估来删除无关特征。

    • 相关性分析: 可以使用皮尔逊相关系数、协方差矩阵等方法来检查特征与目标变量之间的相关性。通常选择与目标变量相关性较高的特征。
    import pandas as pd
    
    # 假设 df 是你的数据框
    correlation_matrix = df.corr()
    relevant_features = correlation_matrix['target'].abs().sort_values(ascending=False)
    # 选择相关性高于某个阈值的特征
    selected_features = relevant_features[relevant_features > 0.3].index.tolist()
    df_selected = df[selected_features]
  2. 模型的重要性评估: 使用模型(如随机森林、Lasso回归等)来评估特征的重要性,选择重要特征。

    from sklearn.ensemble import RandomForestClassifier
    
    model = RandomForestClassifier()
    model.fit(X_train, y_train)
    feature_importance = model.feature_importances_
    features = X_train.columns
    important_features = [features[i] for i in range(len(feature_importance)) if feature_importance[i] > 0.1]

处理缺失值

  1. 删除缺失值:

    • 如果缺失值占很小比例,可以直接删除包含缺失值的行。
    df.dropna(inplace=True)
  2. 填充缺失值:

    • 使用均值、中位数、众数等统计量填充缺失值,适用于数值型特征。
    df.fillna(df.mean(), inplace=True)  # 用均值填充
    # 或者使用中位数
    df.fillna(df.median(), inplace=True)  # 用中位数填充
    • 对于分类特征,可以使用众数进行填充。
    df['category_feature'].fillna(df['category_feature'].mode()[0], inplace=True)
  3. 插值法:

    • 对于时间序列数据,可以使用插值法填充缺失值。
    df['value'].interpolate(method='linear', inplace=True)
  4. 使用机器学习模型进行缺失值填充:

    • 训练一个模型使用其余已知特征来预测缺失值。这种方法通常更复杂,但在某些情况下可能会更有效。

示例代码

下面是一个综合示例:

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier

# 假设导入了数据
df = pd.read_csv('data.csv')

# 删除无关特征
df.drop(columns=['unnecessary_feature1', 'unnecessary_feature2'], inplace=True)

# 处理缺失值
# 对于数值型特征,使用均值填充
df.fillna(df.mean(), inplace=True)
# 对于分类特征,使用众数填充
df['category_feature'].fillna(df['category_feature'].mode()[0], inplace=True)

# 特征选择
X = df.drop(columns=['target'])  # 预测变量
y = df['target']  # 目标

# 进一步选择特征(假设已经分离出了X_train和y_train)
model = RandomForestClassifier()
model.fit(X, y)
feature_importance = model.feature_importances_
features = X.columns
important_features = [features[i] for i in range(len(feature_importance)) if feature_importance[i] > 0.1]
X_selected = X[important_features]  # 选择重要特征

# 接下来就可以进行模型训练和评估了

2.可视化

可视化特征对结果的影响是理解模型和数据的重要步骤。以下是一些常用的方法和示例,帮助你可视化特征与目标变量之间的关系。

散点图 (Scatter Plot)

对于数值型特征,可以使用散点图来展示特征与目标之间的关系。

import pandas as pd
import matplotlib.pyplot as plt

# 假设 df 是你的数据框,'feature' 是特征名,'target' 是目标变量
plt.figure(figsize=(10, 6))
plt.scatter(df['feature'], df['target'], alpha=0.5)
plt.title('Scatter plot of Feature vs Target')
plt.xlabel('Feature')
plt.ylabel('Target')
plt.grid()
plt.show()

箱线图 (Box Plot)

箱线图能够显示特征的分布情况和离群值,适用于分类目标变量的情况。

import seaborn as sns

# 假设 'feature' 是特征名,'target' 是目标变量
plt.figure(figsize=(10, 6))
sns.boxplot(x='target', y='feature', data=df)
plt.title('Box plot of Feature by Target Class')
plt.show()

小提琴图 (Violin Plot)

小提琴图类似于箱线图,但提供了更丰富的信息,包括数据的分布形状。

plt.figure(figsize=(10, 6))
sns.violinplot(x='target', y='feature', data=df)
plt.title('Violin plot of Feature by Target Class')
plt.show()

特征重要性图 (Feature Importance Plot)

对于基于树的模型(如随机森林)可以绘制特征重要性图,以显示各个特征对预测的影响。

from sklearn.ensemble import RandomForestClassifier

# 假设你有 X 和 y
model = RandomForestClassifier()
model.fit(X, y)

feature_importances = model.feature_importances_
features = X.columns

plt.figure(figsize=(12, 8))
plt.barh(features, feature_importances, color='skyblue')
plt.title('Feature Importance from Random Forest')
plt.xlabel('Importance')
plt.ylabel('Features')
plt.show()

相关性热图 (Correlation Heatmap)

热图可以显示所有特征与目标变量之间的相关性,便于整体查看。

plt.figure(figsize=(12, 8))
correlation_matrix = df.corr()
sns.heatmap(correlation_matrix, annot=True, fmt=".2f", cmap='coolwarm')
plt.title('Correlation Heatmap')
plt.show()

工具使用

使用像 SHAPLIME 这样的库可以帮助可视化特征对个别预测结果的影响。

SHAP (SHapley Additive exPlanations)
import shap

# 训练模型
model = RandomForestClassifier()
model.fit(X, y)

# 创建SHAP解释器
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X)

# 可视化
shap.summary_plot(shap_values, X)
LIME (Local Interpretable Model-agnostic Explanations)
from lime import lime_tabular

# 训练LIME解释器
explainer = lime_tabular.LimeTabularExplainer(X.values, feature_names=X.columns.tolist(), class_names=['target'])
i = 0  # 选择要解释的样本
exp = explainer.explain_instance(X.values[i], model.predict_proba)
exp.show_in_notebook()

3. 特征选择

去掉一些不重要的特征后重新训练模型是完全可行的,并且通常是推荐的做法。这个过程被称为特征选择(Feature Selection)。特征选择有以下几个好处:

  1. 减少过拟合:减少特征的数量可以降低模型过拟合的风险,特别是在特征数量多于训练样本的情况下。

  2. 提高模型性能:移除不重要的特征可以减少模型训练和预测时的噪声干扰,从而可能提高模型的泛化能力。

  3. 减少计算成本:较少的特征意味着模型训练和预测时需要的计算资源和时间更少。

  4. 提高可解释性:特征选择可以帮助你理解哪些特征对模型的预测结果有实质性的影响,从而提高模型的可解释性。

以下是进行特征选择并重新训练模型的步骤:

  1. 训练随机森林模型:使用全部特征训练一个随机森林模型。

  2. 评估特征重要性:使用模型的feature_importances_属性来评估每个特征的重要性。

  3. 选择特征:根据特征重要性分数,选择一个阈值来决定哪些特征是重要的,哪些可以被移除。

  4. 创建新的特征集:使用被选为重要的特征创建一个新的特征集。

  5. 重新训练模型:使用新的特征集重新训练模型。

  6. 评估模型性能:评估新模型的性能,确保移除特征后模型性能没有显著下降。

  7. 迭代优化:如果需要,可以迭代这个过程,进一步调整特征选择的阈值,或者尝试不同的特征选择方法。

以下是一个简单的代码示例,展示了如何根据特征重要性重新训练模型:

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split

# 假设df是你的DataFrame,其中包含了你的数据
X = df.iloc[:, :-1]  # 特征
y = df.iloc[:, -1]   # 标签

# 将数据集分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

# 训练随机森林模型
forest = RandomForestClassifier(n_estimators=100, random_state=0)
forest.fit(X_train, y_train)

# 获取特征重要性
importances = forest.feature_importances_

# 将特征重要性从高到低排序
indices = np.argsort(importances)[::-1]

# 设置阈值,选择重要性较高的特征
threshold = 0.05  # 这个阈值可以根据实际情况调整
selected_features = X_train.columns[importances > threshold]

# 使用选择的特征创建新的特征集
X_train_selected = X_train[selected_features]
X_test_selected = X_test[selected_features]

# 使用新的特征集重新训练模型
forest_selected = RandomForestClassifier(n_estimators=100, random_state=0)
forest_selected.fit(X_train_selected, y_train)

# 评估新模型的性能
# 可以使用交叉验证、准确率、F1分数等指标来评估模型性能

在实际应用中,你可能需要根据模型的性能和业务需求来调整特征选择的策略和阈值。

4. 最终代码(ipynb)

# %% [markdown]
# #### Random Forest 随机森林算法预测房车保险
# 
# ##### 一、数据预处理
# 

# %%
# join()方法
# 该方法用于将序列中的元素以指定的字符连接成一个新的字符串。
# 语法:str.join(sequence)

fruit = ['apple', 'banana', 'orange']
result = '-'.join(fruit)
print(result)

# %% [markdown]
# - 从 `dictionary.txt` 中读取特征信息,并保存到 csv 文件的头部
# - 将原始数据变成 csv 格式,并保存到本地
# 

# %%
def get_header():
    header = []
    header_file = open("./tic/dictionary.txt", "r", encoding="utf-8")
    # 读取第4行到第90行作为header
    for line in header_file.readlines()[3:89]:
        header.append(line.strip())
    header_file.close()
    return header

def save_data_as_csv(header):
    ticdata = open("./tic/ticdata2000.txt", "r", encoding="utf-8")
    pridict = open("./tic/ticeval2000.txt", "r", encoding="utf-8")
    
    pridict_csv = open("./tic/ticeval2000.csv", "w", encoding="utf-8")
    ticdata_csv = open("./tic/ticdata2000.csv", "w", encoding="utf-8")
    ticdata_csv.write(",".join(header) + "\n")
    for line in ticdata:
        line = line.strip().replace("\t", ",") + "\n"
        ticdata_csv.write(line)
    ticdata_csv.close()
    ticdata.close()

    for line in pridict:
        line = line.strip().replace("\t", ",") + "\n"
        pridict_csv.write(line)
    pridict_csv.close()
    pridict.close()

save_data_as_csv(get_header())
print(get_header())

# %% [markdown]
# - `查看数据集`
# 

# %%
import pandas as pd
import numpy as np
turing_data = pd.read_csv('./tic/ticdata2000.csv')
turing_data.head() # 输出数据集的前几行
# print(turing_data.shape) # 输出数据集的大小

# %%
print(turing_data.columns) # 输出数据集的列名

# %%
print(turing_data.info()) # 输出数据集的基本信息

# %%
print(turing_data.describe()) # 输出数据集的描述性统计

# %%
print(turing_data.isnull().sum()) # 输出数据集的缺失值统计

# %%
"""
在数据预处理阶段,删除无关特征和处理缺失值是非常重要的一步,以确保模型的性能。以下是一些常见的方法和实用示例:

**删除无关特征**

1. 特征选择: 基于相关性分析和特征重要性评估来删除无关特征。
   - 相关性分析: 可以使用皮尔逊相关系数、协方差矩阵等方法来检查特征与目标变量之间的相关性。通常选择与目标变量相关性较高的特征。

```python
import pandas as pd

# 假设 df 是你的数据框
correlation_matrix = df.corr()
relevant_features = correlation_matrix['target'].abs().sort_values(ascending=False)
# 选择相关性高于某个阈值的特征
selected_features = relevant_features[relevant_features > 0.3].index.tolist()
df_selected = df[selected_features]
```

2. 模型的重要性评估: 使用模型(如随机森林、Lasso 回归等)来评估特征的重要性,选择重要特征。

```python
from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier()
model.fit(X_train, y_train)
feature_importance = model.feature_importances_
features = X_train.columns
important_features = [features[i] for i in range(len(feature_importance)) if feature_importance[i] > 0.1]
```

**处理缺失值**

1. 删除缺失值:
   - 如果缺失值占很小比例,可以直接删除包含缺失值的行。

```python
df.dropna(inplace=True)
```

2. 填充缺失值:
   - 使用均值、中位数、众数等统计量填充缺失值,适用于数值型特征。

```python
df.fillna(df.mean(), inplace=True)  # 用均值填充
# 或者使用中位数
df.fillna(df.median(), inplace=True)  # 用中位数填充
```

    - 对于分类特征,可以使用众数进行填充。

```python
df['category_feature'].fillna(df['category_feature'].mode()[0], inplace=True)
```

3. 插值法:
   - 对于时间序列数据,可以使用插值法填充缺失值。

```python
df['value'].interpolate(method='linear', inplace=True)
```

4. 使用机器学习模型进行缺失值填充:
   - 训练一个模型使用其余已知特征来预测缺失值。这种方法通常更复杂,但在某些情况下可能会更有效。
     """

# %% [markdown]
# `可以看出,数据没有缺失值,且数据量较大,可以进行分析`
# 

# %%
import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split, GridSearchCV, StratifiedKFold
from sklearn.metrics import classification_report
from imblearn.over_sampling import ADASYN
from matplotlib import pyplot as plt
# 假设 turing_data 已经被定义并准备好了
x = turing_data.iloc[:, :-1]  # 特征(去掉最后一列)
y = turing_data.iloc[:, -1]  # 标签(最后一列)

# 将数据集分为训练集和测试集,测试集大小为30%
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=42)

# 使用ADASYN进行过采样
adasyn = ADASYN(random_state=42)
X_train, y_train = adasyn.fit_resample(X_train, y_train) 

# 训练随机森林模型并获取特征重要性
forest = RandomForestClassifier(n_estimators=100, random_state=42)
forest.fit(X_train, y_train)

num_iterations = 10  # 迭代次数
threshold = 0.005  # 初始阈值0.005

# 使用分层交叉验证
skf = StratifiedKFold(n_splits=5)

for iteration in range(num_iterations):
    # 重新计算特征重要性
    importances = forest.feature_importances_
    
    # 根据阈值选择特征
    selected_features = X_train.columns[importances > threshold]
    
    # 使用选定的特征创建新的特征集
    X_train_selected = X_train[selected_features]
    X_test_selected = X_test[selected_features]

    # 参数调优的网格
    param_grid = {
        'n_estimators': range(10, 2000, 10),
        'max_depth': range(1, 10, 1),
        'min_samples_split': range(2, 10, 2),
        'min_samples_leaf': range(1, 5, 1),
        'max_features': ["sqrt", "log2"],
    }

    # 使用GridSearchCV进行参数调优
    grid_search = GridSearchCV(estimator=RandomForestClassifier(random_state=42), param_grid=param_grid, cv=skf,n_jobs=-1) # 多线程
    grid_search.fit(X_train_selected, y_train)

    # 获取最佳参数
    best_params = grid_search.best_params_

    # 使用最佳参数和选定的特征重新训练模型
    forest_selected = RandomForestClassifier(**best_params, random_state=42)
    forest_selected.fit(X_train_selected, y_train)

    # 评估模型性能
    score = forest_selected.score(X_test_selected, y_test)
    y_pred = forest_selected.predict(X_test_selected)
    print(classification_report(y_test, y_pred))
    print(f'Iteration {iteration + 1}, Accuracy: {score}')
    
    # 基于性能调整阈值
    if score < 0.8:  # 假设我们的目标准确率是0.8
        threshold *= 0.9  # 降低阈值以选择更多特征
    else:
        threshold *= 1.1  # 提高阈值以选择更少特征

# 最终模型已经训练完成,可以使用forest_selected进行预测或进一步分析
# 在计算特征重要性之后,添加可视化
plt.figure(figsize=(30, 18))
importances = forest.feature_importances_
indices = np.argsort(importances)[::-1]  # 降序排列特征

# 绘制特征重要性条形图
plt.barh(range(X_train.shape[1]), importances[indices], align='center')
plt.yticks(range(X_train.shape[1]), X_train.columns[indices])
plt.xlabel('Feature Importance')
plt.title('Feature Importance for Random Forest Model')
plt.show()