sklearn 模型在线学习、增量更新实现 (以SGD方式训练LR为例)

sklearn online learning

在 sklearn官方文档里以 online 为关键字进行检索

在这里插入图片描述
在线学习是可以通过小批量的数据迭代更新模型的权重,增量训练方法看 partial_fit,于是检索了一下 partial_fit,介绍如下:

在这里插入图片描述

不同与使用fit方法,partial_fit 方法不需要清空模型(不用清空模型原来就学习好的权重),只需要每次用小批量的数据进行 partial_fit,每个 batch 的数据的 shape 应保持一致。在可迭代训练的模型中(可以进行增量学习的模型),partial_fit 通常只执行一次迭代

通常,在使用 partial_fit 时,模型的参数不应该改变(每次使用 partial_fit 的模型参数保持一致)

partial_fit 使用的时候要返回对象

模型

这里使用逻辑回归模型,用 SGD 的方式进行模型训练,这里主要是为了说明 online learning 如何实现,所以尽量简化特征工程

数据集

https://www.kesci.com/home/dataset/5dd78542f41512002ceb25f3/document

实践

以用户行为数据为例,在原始数据集中取出 1/10作为增量学习的数据,测试进行增量学习之后的,模型特征对应的权重的改变,and 模型预测精度的改变。

具体步骤

  • 进行简单的 预处理&特征工程
  • 划分增量学习的数据(1/10) 和 另一部分数据(9/10)
  • 讲另一部分数据(9/10)划分训练集和测试集,使用训练集训练 LR 模型(fit
  • 使用 partial_fit 进行模型增量学习,并查看模型的特征权重、精度是否改变
import numpy as np
import pandas as pd
import warnings

warnings.filterwarnings('ignore')
book_ratings = pd.read_csv('BX-Book-Ratings1.csv', sep=';', encoding='utf-8')
# books = pd.read_csv('BX-Books1.csv', sep=';')
users = pd.read_csv('BX-Users1.csv', sep=';')
book_ratings.sample(10)
User-IDISBNBook-Rating
53570312911007868860210.0
59201614271506794476520.0
74576918049503754136340.0
114610727592201420017409.0
87170521095904454051985.0
83638920211306848382308.0
1743583790501401586188.0
110144226432108125586267.0
58658514165134780868330.0
1106262638898200500.0
users.sample(10)
User-IDLocationAge
258196258197seattle, washington, usa41.0
3601936020wuxi, jiangsu, china24.0
1559115592newark, delaware, usa23.0
267320267321scottsbluff, nebraska, usa28.0
109842109843braga, braga, portugal22.0
121294121295madrid, n/a, spain56.0
1607716078waldorf, maryland, usa37.0
7528375284vidalia, georgia, usaNaN
195592195593melbourne, victoria, australia26.0
177463177464hanover, michigan, usa52.0
# 空值情况
book_ratings.isnull().sum(), users.isnull().sum()
(User-ID        0
 ISBN           0
 Book-Rating    8
 dtype: int64, User-ID          0
 Location         0
 Age         110765
 dtype: int64)
users.shape
(278858, 3)
# 填充用户评分的空值为0
book_ratings.fillna(0.0, inplace=True)
# 用户的年龄用均值填充,由于缺失数量大,但是特征重要
users['Age'].fillna(users['Age'].mean(), inplace=True)
# 只要国家,不要详情的地区了
users['Location'] = users['Location'].str.split(',').apply(lambda str_list:str_list[-1])
users.Location.value_counts()
 usa               139711
 canada             21657
 united kingdom     18538
 germany            17041
 spain              13126
                    ...  
 toscana                1
 wood                   1
 bosnia                 1
 pasco                  1
 galiza neghra          1
Name: Location, Length: 755, dtype: int64
# 国家也不要了
users.drop('Location', axis=1, inplace=True)
dataset = pd.merge(book_ratings, users, on='User-ID')
dataset[dataset['Book-Rating'] > 0].shape
(433664, 4)
# 处理标签
dataset['Book-Rating'].apply(lambda x:1 if x>0 else 0).value_counts()
0    716116
1    433664
Name: Book-Rating, dtype: int64
dataset['Book-Rating'] = dataset['Book-Rating'].apply(lambda x:1 if x>0 else 0)
dataset.head()
User-IDISBNBook-RatingAge
0276725034545104X034.751661
12767260155061224134.751661
22767270446520802016.000000
3276729052165615X116.000000
42767290521795028116.000000
dataset.shape[0] /10
114978.0
user_item, data = dataset[['User-ID', 'ISBN']], dataset[['Book-Rating', 'Age']]
# 取出 1/10 作为后面要增量训练的数据
online_learning_train, train = data[:114978], data[114978:]
from sklearn.model_selection import train_test_split

X, y = train.drop(columns=['Book-Rating']), train['Book-Rating']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
from sklearn.linear_model import SGDClassifier
%%time
lr_sgd = SGDClassifier(loss='log', warm_start=True).fit(X_train, y_train)
Wall time: 5.49 s
X_train.shape, y_train.shape
((827841, 1), (827841,))
lr_sgd.score(X_test, y_test)
0.6276883084252589
lr_sgd.coef_
array([[-0.01391971]])
def get_batch(online_learning_train):
    for row in online_learning_train.iterrows():
        # 生成器,每次返回一个要训练的样本
        yield row[1]['Book-Rating'], row[1]['Age']
        
batch_generator = get_batch(online_learning_train)
# for i in range(10):
#     print(next(batch_generator))
# 增量更新模型

label, feature = next(batch_generator)
lr_sgd.partial_fit([[feature]], [label])
SGDClassifier(alpha=0.0001, average=False, class_weight=None,
              early_stopping=False, epsilon=0.1, eta0=0.0, fit_intercept=True,
              l1_ratio=0.15, learning_rate='optimal', loss='log', max_iter=1000,
              n_iter_no_change=5, n_jobs=None, penalty='l2', power_t=0.5,
              random_state=None, shuffle=True, tol=0.001,
              validation_fraction=0.1, verbose=0, warm_start=True)
lr_sgd.coef_
array([[-0.01697226]])
for i in range(20):
    label, feature = next(batch_generator)
    lr_sgd = lr_sgd.partial_fit([[feature]], [label])# 注意要返回这个对象
    print(lr_sgd.score(X_test, y_test))
    print(lr_sgd.coef_)
 0.6276883084252589
[[-0.00304325]]
0.6276883084252589
[[-0.00588775]]
0.6276883084252589
[[-0.00175116]]
0.6135455472287049
[[0.00449768]]
0.6276883084252589
[[-0.00060454]]
0.6276883084252589
[[-0.00468685]]
0.6276883084252589
[[0.00109888]]
0.6250839530153024
[[0.00402928]]
0.4302066572929199
[[0.00872931]]
0.3764235773889767
[[0.01224813]]
0.4302066572929199
[[0.00875256]]
0.5881011398282768
[[0.00540715]]
0.42067346021714236
[[0.00906837]]
0.5847188600750866
[[0.00570941]]
0.6267026154686148
[[0.00249447]]
0.6276883084252589
[[-0.00058331]]
0.6276883084252589
[[-0.00353084]]
0.6276883084252589
[[-0.00635496]]
0.6276883084252589
[[-0.00906232]]
0.6276883084252589
[[-0.01165938]]
### 机器学习模型修补或更新技术 #### 增量学习 增量学习允许模型在不重新训练整个数据集的情况下逐步改进。这种方法特别适用于实时应用,在这些场景中,新数据不断流入系统。通过调整现有参数而不是完全重置它们,可以更高效地适应变化的数据分布[^1]。 ```python from sklearn.linear_model import SGDClassifier # 创建一个支持在线/部分拟合的学习器实 clf = SGDClassifier(max_iter=1000) # 使用初始批次的数据进行第一次训练 X_initial, y_initial = ... # 初始数据 clf.partial_fit(X_initial, y_initial, classes=np.unique(y_initial)) # 随着时间推移接收新的数据并继续训练 for X_new_batch, y_new_batch in stream_of_data_batches: clf.partial_fit(X_new_batch, y_new_batch) ``` #### 转移学习 转移学习涉及利用预训练模型的知识来解决相似的任务。这通常意味着冻结源域中的某些层权重,并仅微调目标域特定的部分。对于资源有限的情况尤其有用,因为不需要大量标注样本即可获得良好性能[^2]。 ```python import torch.nn as nn model = torchvision.models.resnet50(pretrained=True) # 冻结所有层 for param in model.parameters(): param.requires_grad = False # 替换最后一层以匹配目标任务类别数 num_ftrs = model.fc.in_features model.fc = nn.Linear(num_ftrs, num_classes) # 继续训练只针对最后几层 optimizer = optim.SGD(model.fc.parameters(), lr=0.001, momentum=0.9) criterion = nn.CrossEntropyLoss() train_model(model, criterion, optimizer, num_epochs=25) ``` #### A/B 测试与影子部署 当引入经过离线验证的新版本算法时,A/B测试是一种评估其实际效果的有效方法。在此过程中,一部分流量被导向旧版服务而另一部分则交给新版处理;两者的结果会被比较分析以便做出最终决策。此外,“影子模式”下运行的新模型会接受真实请求但不会影响用户体验——只有预测结果用于监控目的[^3]。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值