吴恩达机器学习 第三课 week2 推荐算法(下)

目录

01 学习目标

02 基于内容的过滤算法

03 实现“电影推荐系统”

3.1 问题描述

3.2 算法实现

04 大项目(数据很大)的推荐方法※

4.1 方法原理

4.2 实施示例

05 总结


01 学习目标

     (1)理解基于内容的过滤算法(Content-Based Filtering Algorithm)推荐原理

     (2)利用基于内容的过滤算法构建“电影推荐系统”

     (3)了解大项目(数据集很大)的推荐方法

02 基于内容的过滤算法

      基于内容的过滤算法,是采用神经网络架构提取用户特征物品特征后向用户推荐相似物品。用户特征包括:年龄、性别、国家、喜好和评分等等,物品(比如电影)特征包括:年份、类型、影评及所有评价用户的平均年龄等等。

       Content-based filtering的原理如下图所示:

      首先(准备内容),准备两组数据,一组是用户内容Xu,一组是物品的内容Xm。(需说明,Xu数组内均为工程特征,即经过处理后的内容,而Xm数组由原始数据和工程特征组合构成)

      然后(提取特征),定义神经网络模型,其架构为两个并联的模型,将Xu和Xm作为输入,可分别输出用户特征Vu和物品特征Vm。

      接着(用户喜好预测),利用多元线性回归模型,预测用户对所有物品的评分,但Content-based filtering中的回归模型是没有偏置项b的,如下:

\textbf{Y}_j^{(i)}=\textbf{V}_u^{(j)}\cdot \textbf{V}_m^{(i)}

式中,Y为预测结果(分数),i为物品的序数,j为用户的序数。

      现在(相似度计算),根据物品的特征计算物品之间的相似度,物品相似度有很多计算方法,这里根据课程采用欧氏距离平方:

distance=||\textbf{V}_m^{(k)}-\textbf{V}_m^{(i)}||^2=\sum_{l=1}^{n}(v_{ml}^{(k)}-v_{ml}^{(i)})^2

        最后(生成推荐),有了用户对每个物品的预测分数,也有了物品相似度,就可以向用户推荐他喜爱之物的相似物品了。

03 实现“电影推荐系统”

3.1 问题描述

       这次,我们依然采用从GroupLens网站的 MovieLens 栏目下载电影数据集来构建“电影推荐系统”。我们的任务是:根据一位用户的行为,预测其喜好,并为其推荐电影。

3.2 算法实现

    (1)导入模块

# 导包
import pickle
import csv
import numpy as np
import numpy.ma as ma
from numpy import genfromtxt
from collections import defaultdict
import pandas as pd
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.models import Model
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.model_selection import train_test_split
import tabulate
pd.set_option("display.precision", 1)
# Import Lambda layer at the beginning if not already imported
from tensorflow.keras.layers import Lambda

      (2)读取数据

       ① 由于数据较多,定义函数读取:

# 定义函数,读取数据
def load_data():
    item_train = genfromtxt('./data/content_item_train.csv', delimiter=',')
    user_train = genfromtxt('./data/content_user_train.csv', delimiter=',')
    y_train    = genfromtxt('./data/content_y_train.csv', delimiter=',')
    with open('./data/content_item_train_header.txt', newline='') as f:
        item_features = list(csv.reader(f))[0]
    with open('./data/content_user_train_header.txt', newline='') as f:
        user_features = list(csv.reader(f))[0]
    item_vecs = genfromtxt('./data/content_item_vecs.csv', delimiter=',')
       
    movie_dict = defaultdict(dict)
    count = 0
    with open('./data/content_movie_list.csv', newline='') as csvfile:
        reader = csv.reader(csvfile, delimiter=',', quotechar='"')
        for line in reader:
            if count == 0: 
                count +=1  #skip header
            else:
                count +=1
                movie_id = int(line[0])  
                movie_dict[movie_id]["title"] = line[1]  
                movie_dict[movie_id]["genres"] =line[2]  
    with open('./data/content_user_to_genre.pickle', 'rb') as f:
        user_to_genre = pickle.load(f)

    return(item_train, user_train, y_train, item_features, user_features, item_vecs, movie_dict, user_to_genre)

       ② 读取数据:

# 导入原始数据
item_train, user_train, y_train, item_features, user_features, item_vecs, movie_dict, user_to_genre = load_data()

num_user_features = user_train.shape[1] - 3  # 原始数据移除用户ID、评论总数、平均评分三列
num_item_features = item_train.shape[1] - 1  # 原始数据移除电影ID列
uvs = 3  # 用户特征向量开始索引
ivs = 3  # 物品特征向量开始索引
u_s = 3  # 训练集中用户内容开始列索引
i_s = 1  # 训练集中物品内容开始列索引
scaledata = True  # 应用标准化尺度缩放

     (3)数据处理、拆分

       ① 数据标准化:

# 原始数据标准化:均值为0、标准差为1
if scaledata:
    item_train_save = item_train
    user_train_save = user_train

    scalerItem = StandardScaler()
    scalerItem.fit(item_train)
    item_train = scalerItem.transform(item_train)

    scalerUser = StandardScaler()
    scalerUser.fit(user_train)
    user_train = scalerUser.transform(user_train)

       ② 数据拆分为训练集和测试集:

# 数据集拆分,训练集:测试集=8:2
item_train, item_test = train_test_split(item_train, train_size=0.80, shuffle=True, random_state=1)
user_train, user_test = train_test_split(user_train, train_size=0.80, shuffle=True, random_state=1)
y_train, y_test       = train_test_split(y_train,    train_size=0.80, shuffle=True, random_state=1)

       ③ 数据集的数据归一化:

# 训练集、测试集数据归一化
scaler = MinMaxScaler((-1, 1))
scaler.fit(y_train.reshape(-1, 1))
ynorm_train = scaler.transform(y_train.reshape(-1, 1))
ynorm_test = scaler.transform(y_test.reshape(-1, 1))

      (4)人工神经网络模型提取特征

       ① 定义模型架构:

# 定义神经网络模型
num_outputs = 32
tf.random.set_seed(1)
user_NN = tf.keras.models.Sequential([  
    tf.keras.layers.Dense(256, activation='relu'),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(num_outputs) 
])

item_NN = tf.keras.models.Sequential([     
    tf.keras.layers.Dense(256, activation='relu'),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(num_outputs)  
])

# 创建用户输入并指向基础网络
input_user = tf.keras.layers.Input(shape=(num_user_features,))
vu = user_NN(input_user)

# 创建物品输入并指向基础网络
input_item = tf.keras.layers.Input(shape=(num_item_features,))
vm = item_NN(input_item)

# 使用 Keras Lambda layer计算L2范数标准化向量
norm_user = Lambda(lambda x: tf.linalg.l2_normalize(x, axis=1))(vu)
norm_item = Lambda(lambda x: tf.linalg.l2_normalize(x, axis=1))(vm)

# 点乘计算两个标准化向量
output = tf.keras.layers.Dot(axes=1)([norm_user, norm_item])

# 指定模型的输入和输出
model = Model([input_user, input_item], output)

model.summary()

       运行以上代码,结果如下(warning不用理会)

       ② 模型编译及训练:

# 模型编译、训练
tf.random.set_seed(1)
cost_fn = tf.keras.losses.MeanSquaredError()
opt = keras.optimizers.Adam(learning_rate=0.01)
model.compile(optimizer=opt,
              loss=cost_fn)
model.fit([user_train[:, u_s:], item_train[:, i_s:]], ynorm_train, epochs=20)

        运行以上代码,结果如下:

      

      ③ 模型评估:

# 模型评估
model.evaluate([user_test[:, u_s:], item_test[:, i_s:]], ynorm_test)

         运行以上代码,结果如下:

      

       (5)用户喜好预测

        ① 定义函数,提取指定用户的信息内容:

def get_user_vecs(user_id, user_train, item_vecs, user_to_genre):
    """ 输入user_id, user_train, item_vecs, user_to_genre,返回:
        user_vecs:用户特征向量,与电影特征向量item_vecs同尺度
        y vector: 用户对所有电影的评分 """
    # 判断id是否存在
    if user_id not in user_to_genre:
        print("error: unknown user id")
        return(None)
    else:
        user_vec_found = False
        for i in range(len(user_train)):
            if user_train[i, 0] == user_id:
                user_vec = user_train[i]
                user_vec_found = True
                break
        if not user_vec_found:
            print("error in get_user_vecs, did not find uid in user_train")
        num_items = len(item_vecs)
        user_vecs = np.tile(user_vec, (num_items, 1))

        y = np.zeros(num_items)
        for i in range(num_items): 
            movie_id = item_vecs[i, 0]
            if movie_id in user_to_genre[user_id]['movies']:
                rating = user_to_genre[user_id]['movies'][movie_id]
            else:
                rating = 0
            y[i] = rating
    return(user_vecs, y)

         ② 定义函数,根据用户内容(利用model)预测并对预测结果排序:

# 对预测结果排序
def predict_uservec(user_vecs, item_vecs, model, u_s, i_s, scaler, ScalerUser, ScalerItem, scaledata=False):
    """ given a user vector, does the prediction on all movies in item_vecs returns
        an array predictions sorted by predicted rating,
        arrays of user and item, sorted by predicted rating sorting index
    """
    if scaledata:
        scaled_user_vecs = ScalerUser.transform(user_vecs)
        scaled_item_vecs = ScalerItem.transform(item_vecs)
        y_p = model.predict([scaled_user_vecs[:, u_s:], scaled_item_vecs[:, i_s:]])
    else:
        y_p = model.predict([user_vecs[:, u_s:], item_vecs[:, i_s:]])
    y_pu = scaler.inverse_transform(y_p)

    if np.any(y_pu < 0) : 
        print("Error, expected all positive predictions")
    sorted_index = np.argsort(-y_pu,axis=0).reshape(-1).tolist()  #negate to get largest rating first
    sorted_ypu   = y_pu[sorted_index]
    sorted_items = item_vecs[sorted_index]
    sorted_user  = user_vecs[sorted_index]
    return(sorted_index, sorted_ypu, sorted_items, sorted_user)

        ③ 定义函数,展示(预测的)用户喜好:

def print_existing_user(y_p, y, user, items, item_features, ivs, uvs, movie_dict, maxcount=10):
    """ print results of prediction a user who was in the datatbase. 
    inputs are expected to be in sorted order, unscaled. 
    """
    count = 0
    movies_listed = defaultdict(int)
    disp = [["y_p", "y", "user", "user genre ave", "movie rating ave", "title", "genres"]]
    listed = []
    count = 0
    for i in range(0, y.shape[0]):
        if y[i, 0] != 0:
            if count == maxcount:
                break
            count += 1
            movie_id = items[i, 0].astype(int)

            offset = np.where(items[i, ivs:] == 1)[0][0]
            genre_rating = user[i, uvs + offset]
            genre = item_features[ivs + offset]
            disp.append([y_p[i, 0], y[i, 0],
                        user[i, 0].astype(int),      # userid
                        genre_rating.astype(float),
                        items[i, 2].astype(float),    # movie average rating
                        movie_dict[movie_id]['title'], genre])

    table = tabulate.tabulate(disp, tablefmt='html', headers="firstrow", floatfmt=[".1f", ".1f", ".0f", ".2f", ".2f"])
    return(table)

       ④ 开始为ID=18的用户预测其电影喜好:

# 从原始数据中指定一位用户ID进行推荐
uid =  18 
# 处理原始数据,形成一组用户内容向量
user_vecs, y_vecs = get_user_vecs(uid, scalerUser.inverse_transform(user_train), item_vecs, user_to_genre)

# 缩放内容向量,并预测该用户对所有电影的评分
sorted_index, sorted_ypu, sorted_items, sorted_user = predict_uservec(user_vecs, item_vecs, model, u_s, i_s, scaler, 
                                                                      scalerUser, scalerItem, scaledata=scaledata)
sorted_y = y_vecs[sorted_index]   # 返回按评级排序的结果

# 生成预测排序结果
print_existing_user(sorted_ypu, sorted_y.reshape(-1,1), sorted_user, sorted_items, item_features, ivs, uvs, movie_dict, maxcount = 10)

      运行以上代码,结果如下:

      (6)为用户推荐电影

        ① 定义函数,计算电影相似度:

def sq_dist(a,b):
    """
    Returns the squared distance between two vectors
    Args:
      a (ndarray (n,)): vector with n features
      b (ndarray (n,)): vector with n features
    Returns:
      d (float) : distance
    """   
    d = np.sum((a - b) ** 2)    
    return (d)

        ②  新建模型计算电影特征向量:

# 利用已训练参数新建模型计算物品向量
input_item_m = tf.keras.layers.Input(shape=(num_item_features,))    # input layer
vm_m = item_NN(input_item_m)                                        # use the trained item_NN
# 使用item_NN的输出在Lambda层中定义L2归一化
normalized_output = Lambda(lambda x: tf.linalg.l2_normalize(x, axis=1))(vm_m)

# 使用修正后的逻辑重新定义model_m,确保输入和输出正确关联
model_m = Model(inputs=input_item_m, outputs=normalized_output)

model_m.summary()

# 标准化处理特征向量,并使用model_m预测
scaled_item_vecs = scalerItem.transform(item_vecs)
vms = model_m.predict(scaled_item_vecs[:,i_s:])

       运行以上代码,结果如下:

     

       (新建一个模型,利用已经训练好的参数进行预测,好处是易于分离职责和维护、效率更高、便于调试和优化) 

       ③ 向用户(ID=18)推荐:

# 向用户推荐
count = 10  # 推荐数量
liked_movie_ids = item_vecs[sorted_index[:10], 0].astype(int)  # 实际应用中应根据用户评分数据动态获取

# 使用训练好的模型和标准化的电影特征向量计算喜欢的电影的特征向量
liked_movie_vectors = []
for movie_id in liked_movie_ids:
    try:
        # 尝试在item_vecs中找到movie_id
        movie_index = np.where(item_vecs[:, 0] == movie_id)[0]
        if len(movie_index) > 0:
            # 如果找到了,进行后续操作
            scaled_movie_vec = scalerItem.transform(item_vecs[movie_index, :])[:, i_s:]
            liked_movie_vectors.append(model_m.predict(scaled_movie_vec).flatten())
        else:
            print(f"Warning: Movie ID {movie_id} not found in item vectors despite attempt.")
    except Exception as e:
        print(f"An unexpected error occurred while processing movie ID {movie_id}: {e}")

# 初始化相似度计算和推荐列表
distances = []
recommendations = []

# 对于每部喜欢的电影,找到与其最相似的未看过的电影
for liked_vector in liked_movie_vectors:
    liked_vector_normalized = liked_vector[:32] / np.linalg.norm(liked_vector[:32])  # 取前32个元素并正则化
    #
    for i, v in enumerate(vms):
        v_normalized = v / np.linalg.norm(v)  # 正则化处理当前比较的电影向量
        sim_score = np.dot(liked_vector_normalized, v_normalized)  # 使用点积计算相似度
        distances.append((sim_score, i))  # 记录电影索引及其相似度

# 对所有相似度进行排序并选择前N部电影(排除已喜欢的)
top_movies_indices = [idx for _, idx in sorted(distances, reverse=True)[:count]]
unique_top_movies = list(set(top_movies_indices))

# 构建推荐列表
disp = [["Movie Title", "Genres"]]
for movie_idx in unique_top_movies:
    movie_id = int(item_vecs[movie_idx, 0])
    title, genres = movie_dict[movie_id]['title'], movie_dict[movie_id]['genres']
    disp.append([title, genres])

table = tabulate.tabulate(disp, tablefmt='html', headers="firstrow")
table

       运行以上代码,结果如下:

     

        至此,完成了“基于内容过滤的电影推荐系统”搭建任务,上述系统尽量复现了吴恩达机器学习course3(week2)中的课后代码(因为原代码跑不通略作修改),推荐的结果可采纳度较高,预测用户(ID=18)的电影喜好类型为悬疑片(mystery)和恐怖片(thriller),最终推荐的电影也以恐怖片为主。

04 大项目(数据很大)的推荐方法※

4.1 方法原理

      针对数据量特别大的推荐系统,课程中给出一种提升推荐效率的方法:检索 + 排序

4.2 实施示例

       假设一个电影视频网站有数万部电影,即使仅为1位用户作推荐,每次从数万部电影中寻找适合的电影也很耗时。

      “检索 + 排序”的步骤为:

     (1)检索

       首先,根据用户最近观看的10部电影,作近似度计算,各取前3;

       然后,用户历史记录中选出3类电影类型,找出各类型榜单前10部;

       最后,找出该用户所在国家榜单的前10部;

       还可以采用其他筛选标准……

     (2)排序

        假设以上检索出100部电影,将这100部电影的特征输入神经网络模型进行计算,然后采用基于内容的过滤算法向用户推荐。

05 总结

     (1)基于内容的过滤算法,其推荐分5个步骤:准备内容>神经网络模型提取特征>用户喜好预测>近似度计算>向用户推荐。

     (2)推荐算法的原理易于理解而实际操作较为复杂,根本原因为数据量大,所以各类变量较多,因此数据处理是重点工作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/747284.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(四十六)Vue Router组件所独有的两个钩子activate、deactivated

文章目录 activated钩子函数deactivated钩子函数demo 上一篇&#xff1a;&#xff08;四十五&#xff09;Vue Router之编程式路由导航 Vue Router提供了两个钩子函数&#xff0c;分别是activated和deactivated。 这两个钩子函数可以用于在路由组件的激活状态发生变化时执行相…

前端开发实战项目:实时天气预报应用

引言 在本实战项目中&#xff0c;我们将开发一个实时天气预报应用。这个项目将帮助你掌握前端开发的核心技能&#xff0c;包括HTML、CSS、JavaScript&#xff0c;以及如何使用API来获取实时数据。通过这个项目&#xff0c;你将学会如何构建用户界面、处理用户交互、以及与第三…

HarmonyOS Next开发学习手册——通过startAbility拉起文件处理类应用

使用场景 开发者可以通过调用startAbility接口&#xff0c;由系统从已安装的应用中寻找符合要求的应用来实现打开特定文件的意图&#xff0c;例如&#xff1a;浏览器下应用下载PDF文件&#xff0c;可以调用此接口选择文件处理应用打开此PDF文件。开发者需要在请求中设置待打开…

IO-Link ISDU

目录 一、引言 二、ISDU定义与功能 三、ISDU指令构成 四、ISDU应用场景 五、ISDU优势 六、总结 一、引言 IO-Link技术作为工业自动化领域的创新通信标准&#xff0c;通过单一电缆实现了设备层级的透明化通信。其中&#xff0c;Indexed Service Data Unit&#xff08;ISDU…

目标检测mAP

【目标检测】目标检测算法评估指标(性能度量) AP&#xff0c;mAP 详细介绍_ap和map的区别-CSDN博客 目标检测中的mAP | Clouds Blog 目标检测AP如何理解&#xff1f;_置信度与ap-CSDN博客 一、IOU (Intersection Over Union, 交并比) 二、查准率和查全率 True Positive (TP…

力扣随机一题 6/26 哈希表 数组 思维

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;IT竞赛 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 题目一&#xff1a; 2869.收集元素的最少操作次数【简单】 题目&#xff…

Scania斯堪尼亚SHL题库综合能力性格测试真题题型解析及面试经验

一、走进Scania斯堪尼亚 Scania是一家成立于1891年的瑞典公司&#xff0c;专注于重型卡车和巴士的制造&#xff0c;以其模块化系统和环保设计闻名。作为全球领先的运输解决方案提供商&#xff0c;Scania不仅提供高质量的车辆&#xff0c;还提供相关服务和融资解决方案。公司秉…

我对AI赋能的未来畅想

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

经验分享,在线word转图片

这里分享一个在线word转图片的网站&#xff0c;比较好用 网址&#xff1a;http://www.docpe.com/word/word-to-image.aspx 截图&#xff1a;

一加全机型TWRP合集/橙狐recovery下载-20240603更新-支持一加12/Ace3V手机

TWRP是目前安卓平台的刷机神器&#xff0c;可快速刷写第三方ROM或官方系统&#xff0c;刷入TWRP之前需要解锁BL&#xff0c;目前已适配一加多个机型。ROM乐园小编20240603整理&#xff0c;涵盖一加1到一加Ace3V多机型专用TWRP文件&#xff0c;个人机型橙狐recovery适配相对完整…

react学习——17react中todoList案列

1、项目目录 2、App.js //创建“外壳”组件APP import React, {Component} from "react"; //引入Header组件 import Header from "./components/Header"; //引入List组件 import List from "./components/List"; //引入Footer组件 import Foot…

[极客大挑战 2020]Roamphp2-Myblog

又来喽 经过一番测试&#xff0c;发现文件包含&#xff0c;使用伪协议读取文件 例&#xff1a;php://filter/readconvert.base64-encode/resourcelogin //这里我只写php部分 //login.php <?php require_once("secret.php"); mt_srand($secret_seed); $_SESSION…

Kubernetes之Controller详解

本文尝试从Kubernetes Controller的种类、交互逻辑、最佳实践、伪代码示例及历史演进5个方面对其进行详细阐述&#xff0c;希望对您有所帮助&#xff01; 一、Kubernetes Controller种类 Kubernetes Controller Manager 是 Kubernetes 集群的核心组件之一&#xff0c;负责管理…

分布式系统:常见的陷阱和复杂性

分布式系统的复杂性是工程师和开发人员面临的重要挑战。复杂性往往会随着系统的发展而增加&#xff0c;因此积极主动非常重要。让我们来谈谈您可能会遇到哪些类型的复杂性以及在工作中应对它的有效策略。 分布式系统和复杂性 在开发中&#xff0c;分布式系统是相互连接并执行…

nacos 简述 安装运行

一、下载 官网:Redirecting to: https://nacos.io/ 文档:Nacos 快速开始 github地址:GitHub - alibaba/nacos: an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications. 下载nacos server(tips:也…

CVPR2024|vivo提出使用对抗微调获得泛化性更强的SAM,分割性能直接登顶 SOTA!

在计算机视觉不断发展的领域中&#xff0c;基础模型已成为一种关键工具&#xff0c;显示出对多种任务的出色适应性。其中&#xff0c;由 Meta AI 开发的 Segment Anything Model&#xff08;SAM&#xff09;在图像分割任务中表现杰出。然而&#xff0c;和其他类似模型一样&…

docker环境安装redis

docker下载redis镜像 docker pull redis:bullseye查看redis镜像 docker images创建redis容器 docker run \ -d \ --name redis \ -p 6379:6379 \ --restart unless-stopped \ -v /mydata/redis/data:/data \ -v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf \ redi…

【Leetcode】520. 检测大写字母

文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接&#x1f517;我们定义&#xff0c;在以下情况时&#xff0c;单词的大写用法是正确的&#xff1a; 全部字母都是大写&#xff0c;比如 “USA” 。单词中所有字母都不是大写&#xff0c;比如 “le…

【前端项目笔记】4 权限管理

权限管理 效果展示&#xff1a; &#xff08;1&#xff09;权限列表 &#xff08;2&#xff09;角色列表 其中的分配权限功能 权限列表功能开发 新功能模块&#xff0c;需要创建新分支 git branch 查看所有分支&#xff08;*表示当前分支&#xff09; git checkout -b ri…

机器学习辅助的乙醇浓度检测(毕设节选)

目录 1.为什么要机器学习 2. 神经网络一般组成 3.BP神经网络工作过程 4.评价指标 5.实操代码 1.为什么要用机器学习 人工分析大量的谐振模式&#xff0c;建立各种WGM的响应与未知目标之间的关系&#xff0c;是一个很大的挑战。机器学习(ML)能够自行识别全谱的全部特征。作为…