建模数据的预处理

科技   2024-10-09 20:33   广东  

 今天是生信星球陪你的第1003天


   

公众号里的文章大多数需要编程基础,如果因为代码看不懂,而跟不上正文的节奏,可以来找我学习,相当于给自己一个新手保护期。我的课程都是循环开课,点进去咨询微信↓

生信分析直播课程(每月初开一期,春节休一个月)

生信新手保护学习小组(每月两期)

单细胞陪伴学习小组(每月两期)

目录
  • 预处理

  • 缺失值处理

  • 数据标准化

虚拟变量

scikit-learn 对数据的要求是:
  • 数值型
  • 没有缺失值

处理分类数据

分类数据(例如颜色)不是数值,不符合scikit-learn对数据的要求。所以徐奥将他们转换为数值型特征。
我们需要把特征拆分为多个虚拟变量,每个类别对应一个虚拟变量,0表示不是这一类,1表示是这一类。
例如,将上面的10种音乐流派组成的特征,拆分成10列。
需要注意:如果一首歌不属于前9种音乐流派种的任何一种,那么就可以知道它属于第10种。所以我们只需要9个特征就可以了,否则相当于是提供了重复的信息。
要创建虚拟变量,可以使用
  • scikit-learn:OneHotEncoder
  • pandas:get_dummies
import pandas as pd 
music_df = pd.read_csv('music.csv'
music_dummies = pd.get_dummies(music_df["genre"], drop_first=True#drop_first=True是删除一个虚拟变量
print(music_dummies.head())
把上面的9个特征拼接到music表格上面去,并把原来的genre列删掉。
music_dummies = pd.concat([music_df, music_dummies], axis=1
music_dummies = music_dummies.drop("genre", axis=1)
如果整个表格里只有一个分类的列,可以不用拼接,直接使用get_dummies即可:
music_dummies = pd.get_dummies(music_df, drop_first=True
print(music_dummies.columns)

使用虚拟变量的线性回归

from sklearn.model_selection import cross_val_score, KFold 
from sklearn.linear_model import LinearRegression 
X = music_dummies.drop("popularity", axis=1).values 
y = music_dummies["popularity"].values 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,  random_state=42)  
kf = KFold(n_splits=5, shuffle=True, random_state=42
linreg = LinearRegression() 
linreg_cv = cross_val_score(linreg, X_train, y_train, cv=kf, 
                            scoring="neg_mean_squared_error"
print(np.sqrt(-linreg_cv))
这里使用的模型评测指标是-MSE,是因为执行交叉验证时假定分数越高模型越好,而MSE的实际情况是MSE越小,模型越好,所以用负值。

可以直接运行的例子

因为课程里没有提供music.csv这个文件,所以上述代码只能在网站上在线运行,我找kimi编了一个示例数据看,发现需要加一个参数dtype="int"。
import pandas as pd

# 创建示例数据框
data = {
    'Color': ['Red''Blue''Green''Blue''Red''Green''Yellow''Blue''Red'],
    'Shape': ['Circle''Square''Triangle''Circle''Square''Circle''Triangle''Square''Triangle']
}
df = pd.DataFrame(data)

print("Original DataFrame:")
print(df)
# 使用get_dummies()转换'Color'列为虚拟变量
df_dummies = pd.get_dummies(df, columns=['Color'])

print("\nDataFrame with dummy variables:")
print(df_dummies)

缺失值处理

其实music原始数据的每一列都有缺失值
print(music_df.isna().sum().sort_values())

删除缺失值:dropna

缺失值不到5%的列,可以把缺失值去掉。

缺失值插补:SimpleImputer

缺失值较多的列,可以插补,即填充上其他的值。
下面的代码是把分类型的列和数值型的列分开处理,分类型数据的插补策略是用出现频率最高的值来填充缺失值,数值型数据的插补策略是用该列的平均值来填充缺失值。
分开插补后又合并在了一起。
from sklearn.impute import SimpleImputer  
X_cat = music_df["genre"].values.reshape(-11
X_num = music_df.drop(["genre""popularity"], axis=1).values 
y = music_df["popularity"].values  
X_train_cat, X_test_cat, y_train, y_test = train_test_split(X_cat, y, test_size=0.2
                                                            random_state=12)  
X_train_num, X_test_num, y_train, y_test = train_test_split(X_num, y, test_size=0.2
                                                            random_state=12)  
imp_cat = SimpleImputer(strategy="most_frequent")  
X_train_cat = imp_cat.fit_transform(X_train_cat)  
X_test_cat = imp_cat.transform(X_test_cat) 
imp_num = SimpleImputer() 
X_train_num = imp_num.fit_transform(X_train_num) #数值型数据默认用平均值填充
X_test_num = imp_num.transform(X_test_num) 
X_train = np.append(X_train_num, X_train_cat, axis=1
X_test = np.append(X_test_num, X_test_cat, axis=1

用管道操作完成缺失值插补和建模

注意:管道中,除了最后一个步骤外,每个步骤都必须是transformer。

数据标准化

 print(music_df[["duration_ms""loudness""speechiness"]].describe())

为什么标准化?

  • 很多模型使用了点与点之间的距离
  • 如果特征的数据范围不同,会不成比例的影响模型
  • KNN在预测时就明确使用了距离。
所以我们希望每个特征都在相同的尺度上。(数值范围差不多)

怎么标准化?

有多种方法:
  • 1.对每一列,减去均值并除以方差,得到均值为零,方差为1的数据,这就是标准化。
  • 2.对每一列,家去最小值并除以方差,得到0~1范围的数据。
  • 3.对每一列,将数据中心化,得到-1~1范围的数据。
我们选择第一种,其他方法也有相应的函数实现。
from sklearn.preprocessing import StandardScaler 
X = music_df.drop("genre", axis=1).values 
y = music_df["genre"].values  
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,  
                                                    random_state=42)  
scaler = StandardScaler() 
X_train_scaled = scaler.fit_transform(X_train) 
X_test_scaled = scaler.transform(X_test) 
print(np.mean(X), np.std(X)) 
print(np.mean(X_train_scaled), np.std(X_train_scaled)) 

管道操作完成标准化和建模

可以把scale和构建模型放进管道里
 steps = [('scaler', StandardScaler()), 
          ('knn', KNeighborsClassifier(n_neighbors=6))] 
pipeline = Pipeline(steps)  
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,  
                                                    random_state=21)  
knn_scaled = pipeline.fit(X_train, y_train) 
y_pred = knn_scaled.predict(X_test) 
print(knn_scaled.score(X_test, y_test)) 
## 0.81
与没scale的数据作比较
 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,  
                                                     random_state=21
knn_unscaled = KNeighborsClassifier(n_neighbors=6).fit(X_train, y_train) 
print(knn_unscaled.score(X_test, y_test)) 
## 0.53
用pipeline实现交叉验证&scale
from sklearn.model_selection import GridSearchCV 
steps = [('scaler', StandardScaler()), 
         ('knn', KNeighborsClassifier())] 
pipeline = Pipeline(steps)  
parameters = {"knn__n_neighbors": np.arange(150)}  
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,  
                                                    random_state=21)  
cv = GridSearchCV(pipeline, param_grid=parameters)  
cv.fit(X_train, y_train)  
y_pred = cv.predict(X_test) 
#检查模型参数
print(cv.best_score_) 
print(cv.best_params_) 
管道中,超参数需要加上变量名加两个下划线,方便函数识别是谁的参数
# Build the steps
steps = [("scaler", StandardScaler()),
         ("logreg", LogisticRegression())]
pipeline = Pipeline(steps)

# Create the parameter space
parameters = {"logreg__C": np.linspace(0.0011.020)}
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2
                                                    random_state=21)

# Instantiate the grid search object
cv = GridSearchCV(pipeline, param_grid=parameters)

# Fit to the training data
cv.fit(X_train, y_train)
print(cv.best_score_, "\n", cv.best_params_)

生信星球
一个零基础学生信的平台-- 原创结构化图文/教程,精选阶段性资料,带你少走弯路早入门,收获成就感,早成生信小能手~
 最新文章