05、基于梯度下降的协同过滤算法

news2025/1/23 21:16:20

05、基于梯度下降的协同过滤算法理论与实践Python

开始学习机器学习啦,已经把吴恩达的课全部刷完了,现在开始熟悉一下复现代码。对这个手写数字实部比较感兴趣,作为入门的素材非常合适。

协同过滤算法是一种常用的推荐算法,基于对用户历史行为数据的挖掘发现用户的喜好偏向,并预测用户可能喜好的产品进行推荐。它的主要实现方式包括

  1. 根据和你有共同喜好的人给你推荐。
  2. 根据你喜欢的物品给你推荐相似物品。

因此,常用的协同过滤算法分为两种,基于用户的协同过滤算法(user-based collaborative filtering),以及基于物品的协同过滤算法(item-based collaborative filtering)。

这种算法的特点可以概括为“人以类聚,物以群分”,并据此进行预测和推荐。例如,基于物品的协同过滤算法会给用户推荐与他之前喜欢的物品相似的物品;而基于用户的协同过滤算法会给用户推荐与他兴趣相似的用户喜欢的物品。

1、基于用户的协同过滤算法案例与直观解释

协同过滤算法算是上到今天的课中比较弯弯绕绕的东西了,在此以下面的电影打分案例为例:
在这里插入图片描述
竖过来那一栏是电影的名称,横着的四个是打分的人的名字,最后两个x是电影的特征。问号表示该用户没有对电影进行过评分,与此同时,电影的特征x是完全未知的

从电影推荐的角度来讲,对正在浏览的用户,若其对某个电影潜在的评分越高,则越有可能将此电影推荐给这个用户。而这个潜在的评分正是算法所需要得到的。

这个算法是如何运作的呢?其底层的直觉是基于用户的相似性。比如,小张是个爱猫人士,喜欢看有猫猫的电影,他看过许多猫猫电影并给这类电影打了高分;然后,小王来了,小王初来乍到也给几部猫猫片打了高分,平台此时认为小王和小张相似,从而把小张打高分的电影推荐给小王。
但是,平台并不知道小张和小王的相似之处在于喜欢看猫猫片(并不了解事物的特征的具体情况),其只知道这两个人爱好类似而已。

这种基于相似度的机制在很多文章中有介绍。如:推荐算法之协同过滤算法详解(原理,流程,步骤,适用场景)。但是,在吴恩达的课程里面,所介绍的基于梯度下降的协同过滤算法好像并没有专门涉及这一相似的矩阵计算概念?在此对这种基于机器学习的协同过滤算法简单介绍。

2、基于梯度下降的协同过滤算法实现原理

这边主要是介绍吴恩达视频里面的实现思路。用户给电影打高分,是因为用户喜欢电影的某项特征,以下面为例(用户Alice和Bob给Love at last打高分其实是两个条件,其一是电影具备浪漫特征,其二是用户喜欢浪漫的东西):
在这里插入图片描述
简单来说可以简化为以下的公式(w就是用户自己的喜好特征,x是电影本身的特质,最终得到的是电影的打分):
在这里插入图片描述
但是对于基于用户的协同过滤算法案例的数据,也就是第一张图,用户自己的喜好特征和电影本身的特质都是未知的(只有部分用户的打分已知),那么该如何进行打分呢?答案是随机初始化(或者合理猜测)然后使用梯度下降得到最优的w、x、b,然后就能计算打分数据y进而进行推荐了。

这个梯度下降实际包含两个过程,首先是从电影的特征和实际打分训练得到用户的特征w、b,其次是从用户的特征w、b和实际打分训练得到电影的特征,这两个过程的成本函数可以相加合一,毕竟实际的未知量是w、b、x:
在这里插入图片描述

3、基于梯度下降的协同过滤算法实现步骤

step1:加载数据
其中R是bool类型的矩阵,第i行第j列代表第j个用户是否对第i个电影打分
Y是打分的矩阵,第i行第j列代表第j个用户对第i个电影的打分的分数

def load_ratings_small():
    file = open('./Collaborative_Filtering_data/small_movies_Y.csv', 'rb')
    Y = loadtxt(file, delimiter=",")

    file = open('./Collaborative_Filtering_data/small_movies_R.csv', 'rb')
    R = loadtxt(file, delimiter=",")
    return (Y, R)
#加载数据

# Y是所有电影的打分的数据,数据大小是nm*nu
# R的数据大小是nm*nu,格式为bool,表示第j列的用户是否对第i行的用户打分
Y, R = load_ratings_small()
num_movies, num_users = Y.shape

step2:构建成本函数
成本函数的构建参考2、基于梯度下降的协同过滤算法实现原理中的图片里面的公式,当然可以使用循环来实现(X, W, b可以随机初始化):

def cofi_cost_func(X, W, b, Y, R, lambda_):  
    """  
    计算协同过滤的代价函数。  
      
    参数:  
    X -- 电影的特征矩阵  
    W -- 用户的权重矩阵  
    b -- 用户的偏置向量  
    Y -- 用户对电影的评分矩阵  
    R -- 指示用户是否对电影进行了评分的矩阵  
    lambda_ -- 正则化参数  
      
    返回:  
    J -- 代价函数的值  
    """  
    nm, nu = Y.shape  # 获取评分矩阵Y的形状,nm为电影数量,nu为用户数量  
    J = 0  # 初始化代价函数值为0  
      
    # 遍历每一个用户  
    for j in range(nu):  
        # 获取第j个用户的兴趣权重  
        w = W[j, :]  
        b_j = b[0, j]  # 获取第j个用户的偏置值  
          
        # 遍历每一部电影  
        for i in range(nm):  
            # 获取第i部电影的特征,和第j个用户对其的打分  
            x = X[i, :]  
            y = Y[i, j]  
            r = R[i, j]  # 获取第j个用户对第i部电影的评分指示值(是否进行了评分)  
              
            # 计算代价函数中的误差项并累加到J中  
            J += np.square(r * (np.dot(w, x) + b_j - y))  
      
    # 正则化部分,防止过拟合  
    J += lambda_ * (np.sum(np.square(W)) + np.sum(np.square(X)))  
    J = J / 2  # 对J进行平均处理  
    return J  # 返回计算得到的代价函数值

更好的方法是使用矩阵运算来实现,这样速度更快:

def cofi_cost_func_v(X, W, b, Y, R, lambda_):  
    """  
    计算基于内容的过滤的代价函数。  
    为了速度进行了向量化。使用TensorFlow操作以与自定义训练循环兼容。  
  
    参数:  
      X (ndarray (num_movies,num_features)):物品特征矩阵  
      W (ndarray (num_users,num_features)):用户参数矩阵  
      b (ndarray (1, num_users)):用户参数向量  
      Y (ndarray (num_movies,num_users)):用户对电影的评分矩阵  
      R (ndarray (num_movies,num_users)):矩阵,其中R(i, j) = 1表示第j个用户对第i部电影进行了评分  
      lambda_ (float):正则化参数  
  
    返回:  
      J (float):代价函数的值  
    """  
    # 使用矩阵乘法和偏置计算预测评分,然后与实际评分相减,并乘以评分指示矩阵R  
    j = (tf.linalg.matmul(X, tf.transpose(W)) + b - Y) * R  
      
    # 计算代价函数的值,包括正则化部分  
    J = 0.5 * tf.reduce_sum(j**2) + (lambda_ / 2) * (tf.reduce_sum(X**2) + tf.reduce_sum(W**2))  
    return J

step3:训练数据预处理与随机初始化

def normalizeRatings(Y, R):
    """
    规范化用户评分矩阵,使其具有零均值。

    参数:
    Y (ndarray): 用户对物品的评分矩阵,形状通常为 (num_users, num_items)。
    R (ndarray): 指示矩阵,其中 R[i, j] = 1 表示用户 i 对物品 j 进行了评分,否则为 0。
    
    返回:
    Ynorm (ndarray): 规范化后的评分矩阵。
    Ymean (ndarray): 每个用户的平均评分。
    """
    # 计算每个用户的加权平均分。这里,加权是指只考虑用户实际评分的项目。
    # 分母加上 1e-12 是为了避免除以零的情况。
    Ymean = (np.sum(Y * R, axis=1) / (np.sum(R, axis=1) + 1e-12)).reshape(-1, 1)
    # 从原始评分中减去每个用户的平均分,得到规范化后的评分。
    # 注意,我们只更新那些用户实际评分的项目。
    Ynorm = Y - np.multiply(Ymean, R)
    return Ynorm, Ymean
# 加载评分 
Y, R = load_ratings_small()  
# 规范化数据集,使其具有零均值  
Ynorm, Ymean = normalizeRatings(Y, R)  
  
# 开始训练  
num_movies, num_users = Y.shape  # 获取电影和用户的数量  
num_features = 100  # 设置特征的数量  
  
# 设置初始参数(W, X),使用tf.Variable来跟踪这些变量,这样在训练过程中可以更新它们。  
tf.random.set_seed(1234)  # 设置随机种子以确保结果的一致性  
W = tf.Variable(tf.random.normal((num_users,  num_features), dtype=tf.float64), name='W')  # 用户参数矩阵  
X = tf.Variable(tf.random.normal((num_movies, num_features), dtype=tf.float64), name='X')  # 电影特征矩阵  
b = tf.Variable(tf.random.normal((1, num_users), dtype=tf.float64), name='b')  # 用户偏置参数

step4:设置优化器,开始梯度下降

# 实例化一个优化器,这里选择的是Adam优化器,学习率设置为0.1  
optimizer = keras.optimizers.Adam(learning_rate=1e-1)  
  
# 设置迭代次数和正则化参数  
iterations = 400  
lambda_ = 1  
  
# 开始迭代  
for iter in range(iterations):  
    # 使用TensorFlow的GradientTape来记录计算代价所涉及的操作  
    with tf.GradientTape() as tape:  
        # 计算代价(前向传播已经包含在cost_value中)  
        cost_value = cofi_cost_func_v(X, W, b, Ynorm, R, lambda_)  
      
    # 使用gradient tape自动获取可训练变量关于损失的梯度  
    grads = tape.gradient(cost_value, [X, W, b])  
      
    # 使用优化器运行一步梯度下降,更新变量的值以最小化损失  
    optimizer.apply_gradients(zip(grads, [X, W, b]))  
      
    # 定期记录训练损失  
    if iter % 20 == 0:  
        print(f"Training loss at iteration {iter}: {cost_value:0.1f}")

step5:对所有用户进行预测,并去归一化

# Make a prediction using trained weights and biases
p = np.matmul(X.numpy(), np.transpose(W.numpy())) + b.numpy()
#restore the mean
pm = p + Ymean


step6:查看结果

# 查看第一个用户的结果
my_predictions = pm[:,0]
# sort predictions
ix = tf.argsort(my_predictions, direction='DESCENDING')
# 查看第一个用户的打分最高的结果
for i in range(17):
    j = ix[i]
    if j not in my_rated:
        print(f'Predicting rating {my_predictions[j]:0.2f} for movie {movieList[j]}')
# 查看第一个用户的预测打分和实际打分对比     
print('\n\nOriginal vs Predicted ratings:\n')
for i in range(len(Y[:,0])):
    if Y[i,0] > 0:
        print(f'Original {Y[i,0]}, Predicted {my_predictions[i]:0.2f} for {movieList[i]}')

查看的是第一个用户的结果,首先查看的是系统对第一个用户的打分的排名最高的结果,其次是系统对第一个用户预计的打分结果和实际打分结果的对比:
在这里插入图片描述

4、全部代码

数据集和全部代码在最上方链接下载:

import numpy as np
import tensorflow as tf
from tensorflow import keras
from numpy import loadtxt
import pandas as pd


def normalizeRatings(Y, R):
    """
    规范化用户评分矩阵,使其具有零均值。

    参数:
    Y (ndarray): 用户对物品的评分矩阵,形状通常为 (num_users, num_items)。
    R (ndarray): 指示矩阵,其中 R[i, j] = 1 表示用户 i 对物品 j 进行了评分,否则为 0。

    返回:
    Ynorm (ndarray): 规范化后的评分矩阵。
    Ymean (ndarray): 每个用户的平均评分。
    """
    # 计算每个用户的加权平均分。这里,加权是指只考虑用户实际评分的项目。
    # 分母加上 1e-12 是为了避免除以零的情况。
    Ymean = (np.sum(Y * R, axis=1) / (np.sum(R, axis=1) + 1e-12)).reshape(-1, 1)
    # 从原始评分中减去每个用户的平均分,得到规范化后的评分。
    # 注意,我们只更新那些用户实际评分的项目。
    Ynorm = Y - np.multiply(Ymean, R)
    return Ynorm, Ymean


def load_precalc_params_small():
    file = open('./Collaborative_Filtering_data/small_movies_X.csv', 'rb')
    X = loadtxt(file, delimiter=",")

    file = open('./Collaborative_Filtering_data/small_movies_W.csv', 'rb')
    W = loadtxt(file, delimiter=",")

    file = open('./Collaborative_Filtering_data/small_movies_b.csv', 'rb')
    b = loadtxt(file, delimiter=",")
    b = b.reshape(1, -1)
    num_movies, num_features = X.shape
    num_users, _ = W.shape
    return (X, W, b, num_movies, num_features, num_users)


def load_ratings_small():
    file = open('./Collaborative_Filtering_data/small_movies_Y.csv', 'rb')
    Y = loadtxt(file, delimiter=",")

    file = open('./Collaborative_Filtering_data/small_movies_R.csv', 'rb')
    R = loadtxt(file, delimiter=",")
    return (Y, R)

def load_Movie_List_pd():
    """ returns df with and index of movies in the order they are in in the Y matrix """
    df = pd.read_csv('./Collaborative_Filtering_data/small_movie_list.csv', header=0, index_col=0,  delimiter=',', quotechar='"')
    mlist = df["title"].to_list()
    return(mlist, df)
def cofi_cost_func(X, W, b, Y, R, lambda_):
    nm, nu = Y.shape
    J = 0
    for j in range(nu):
        # 获取第j个用户的兴趣权重
        w = W[j, :]
        b_j = b[0, j]
        for i in range(nm):
            #获取第i个电影的特征,和第j个用户对其的打分
            x = X[i, :]
            y = Y[i, j]
            r = R[i, j]
            J += np.square(r * (np.dot(w, x) + b_j - y))
    # 正则化
    J += lambda_ * (np.sum(np.square(W)) + np.sum(np.square(X)))
    J = J / 2
    return J


def cofi_cost_func_v(X, W, b, Y, R, lambda_):
    """
    计算基于内容的过滤的代价函数。
    为了速度进行了向量化。使用TensorFlow操作以与自定义训练循环兼容。

    参数:
      X (ndarray (num_movies,num_features)):物品特征矩阵
      W (ndarray (num_users,num_features)):用户参数矩阵
      b (ndarray (1, num_users)):用户参数向量
      Y (ndarray (num_movies,num_users)):用户对电影的评分矩阵
      R (ndarray (num_movies,num_users)):矩阵,其中R(i, j) = 1表示第j个用户对第i部电影进行了评分
      lambda_ (float):正则化参数

    返回:
      J (float):代价函数的值
    """
    # 使用矩阵乘法和偏置计算预测评分,然后与实际评分相减,并乘以评分指示矩阵R
    j = (tf.linalg.matmul(X, tf.transpose(W)) + b - Y) * R

    # 计算代价函数的值,包括正则化部分
    J = 0.5 * tf.reduce_sum(j ** 2) + (lambda_ / 2) * (tf.reduce_sum(X ** 2) + tf.reduce_sum(W ** 2))
    return J

#加载数据
# Y是所有电影的打分的数据,数据大小是nm*nu
# R的数据大小是nm*nu,格式为bool,表示第j列的用户是否对第i行的用户打分
Y, R = load_ratings_small()
num_movies, num_users = Y.shape

print("Y", Y.shape, "R", R.shape)
print("num_movies",   num_movies)
print("num_users",    num_users)


# 按照自己的喜好给电影打分
movieList, movieList_df = load_Movie_List_pd()
my_ratings = np.zeros(num_movies)          #  Initialize my ratings
# Check the file small_movie_list.csv for id of each movie in our dataset
# For example, Toy Story 3 (2010) has ID 2700, so to rate it "5", you can set
my_ratings[2700] = 5
#Or suppose you did not enjoy Persuasion (2007), you can set
my_ratings[2609] = 2;
# We have selected a few movies we liked / did not like and the ratings we
# gave are as follows:
my_ratings[929]  = 5   # Lord of the Rings: The Return of the King, The
my_ratings[246]  = 5   # Shrek (2001)
my_ratings[2716] = 3   # Inception
my_ratings[1150] = 5   # Incredibles, The (2004)
my_ratings[382]  = 2   # Amelie (Fabuleux destin d'Amélie Poulain, Le)
my_ratings[366]  = 5   # Harry Potter and the Sorcerer's Stone (a.k.a. Harry Potter and the Philosopher's Stone) (2001)
my_ratings[622]  = 5   # Harry Potter and the Chamber of Secrets (2002)
my_ratings[988]  = 3   # Eternal Sunshine of the Spotless Mind (2004)
my_ratings[2925] = 1   # Louis Theroux: Law & Disorder (2008)
my_ratings[2937] = 1   # Nothing to Declare (Rien à déclarer)
my_ratings[793]  = 5   # Pirates of the Caribbean: The Curse of the Black Pearl (2003)
my_rated = [i for i in range(len(my_ratings)) if my_ratings[i] > 0]
print('\nNew user ratings:\n')
for i in range(len(my_ratings)):
    if my_ratings[i] > 0 :
        print(f'Rated {my_ratings[i]} for  {movieList_df.loc[i,"title"]}')




# 加载评分
Y, R = load_ratings_small()
# Y= np.c_[my_ratings, Y]
# R= np.c_[(my_ratings != 0).astype(int), R]
# 规范化数据集,使其具有零均值
Ynorm, Ymean = normalizeRatings(Y, R)

# 开始训练
num_movies, num_users = Y.shape  # 获取电影和用户的数量
num_features = 100  # 设置特征的数量

# 设置初始参数(W, X),使用tf.Variable来跟踪这些变量,这样在训练过程中可以更新它们。
tf.random.set_seed(1234)  # 设置随机种子以确保结果的一致性
W = tf.Variable(tf.random.normal((num_users, num_features), dtype=tf.float64), name='W')  # 用户参数矩阵
X = tf.Variable(tf.random.normal((num_movies, num_features), dtype=tf.float64), name='X')  # 电影特征矩阵
b = tf.Variable(tf.random.normal((1, num_users), dtype=tf.float64), name='b')  # 用户偏置参数

# 实例化一个优化器,这里选择的是Adam优化器,学习率设置为0.1
optimizer = keras.optimizers.Adam(learning_rate=1e-1)
# 设置迭代次数和正则化参数
iterations = 400
lambda_ = 1
# 开始迭代
for iter in range(iterations):
    # 使用TensorFlow的GradientTape来记录计算代价所涉及的操作
    with tf.GradientTape() as tape:
        # 计算代价(前向传播已经包含在cost_value中)
        cost_value = cofi_cost_func_v(X, W, b, Ynorm, R, lambda_)

        # 使用gradient tape自动获取可训练变量关于损失的梯度
    grads = tape.gradient(cost_value, [X, W, b])

    # 使用优化器运行一步梯度下降,更新变量的值以最小化损失
    optimizer.apply_gradients(zip(grads, [X, W, b]))

    # 定期记录训练损失
    if iter % 20 == 0:
        print(f"Training loss at iteration {iter}: {cost_value:0.1f}")



# Make a prediction using trained weights and biases
p = np.matmul(X.numpy(), np.transpose(W.numpy())) + b.numpy()
#restore the mean
pm = p + Ymean



my_predictions = pm[:,0]
# sort predictions
ix = tf.argsort(my_predictions, direction='DESCENDING')

for i in range(17):
    j = ix[i]
    if j not in my_rated:
        print(f'Predicting rating {my_predictions[j]:0.2f} for movie {movieList[j]}')
print('\n\nOriginal vs Predicted ratings:\n')
for i in range(len(Y[:,0])):
    if Y[i,0] > 0:
        print(f'Original {Y[i,0]}, Predicted {my_predictions[i]:0.2f} for {movieList[i]}')



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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue3+ts 实现时间间隔选择器

需求背景解决效果视频效果balancedTimeElement.vue 需求背景 实现一个分片的时间间隔选择器,需要把显示时间段显示成图表,涉及一下集中数据转换 [“02:30-05:30”,“07:30-10:30”,“14:30-17:30”]‘[(2,5),(7,10),(14,17)]’[4, 5, 6, 7, 8, 9, 10, …

SpringBoot项目发送邮件

📑前言 本文主要是【SpringBoot】——SpringBoot项目发送邮件的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页听风与他 &#x1f3…

【人工智能Ⅰ】实验2:遗传算法

实验2 遗传算法实验 一、实验目的 熟悉和掌握遗传算法的原理、流程和编码策略,理解求解TSP问题的流程并测试主要参数对结果的影响,掌握遗传算法的基本实现方法。 二、实验原理 旅行商问题,即TSP问题(Traveling Salesman Proble…

每日一题 2336. 无限集中的最小数字(中等)

感觉就是模拟它的两个过程就行了啊 class SmallestInfiniteSet:def __init__(self):self.small 1self.delset set()def popSmallest(self) -> int:ans self.smallself.delset.add(self.small)while self.small in self.delset:self.small 1return ansdef addBack(self,…

MATLAB | 官方举办的动图绘制大赛 | 第三周赛情回顾

MATHWORKS官方举办的迷你黑客大赛第三期(MATLAB Flipbook Mini Hack)的最新进展!! 很荣幸前三周都成为了阶段性获奖者~: https://ww2.mathworks.cn/matlabcentral/communitycontests/contests/6/entries/13382 https://ww2.mathworks.cn/mat…

展开运算符(...)

假如我们有一个数组: const arr [7,8,9];● 我们如果想要数组中的元素,我们必须一个一个手动的去获取,如下: const arr [7,8,9]; const badNewArr [5, 6, arr[0], arr[1],arr[2]]; console.log(badNewArr);● 但是通过展开运…

计算机基础知识61

JsonResponse 功能例子 你自己写一个类,实现JsonResponse 功能,不需要传safeFalse,无论字典或列表,都能完成序列化返回给前端 1 响应头例子 四种情况,在响应头返回数据 xxxx # 第一种情况 JsonResponse def show(req…

软件测试项目大全,看你需要哪一个

软件测试是使用人工或者自动的手段来运行或者测定某个软件系统的过程,其目的在于检验它是否满足规定的需求或弄清预期结果与实际结果之间的差别。 在软件投入使用前,要经过一系列的严格测试,才能保证交付质量。 一、引言 1.编写目的 本文档…

Nat. Mach. Intell. | 预测人工智能的未来:在指数级增长的知识网络中使用基于机器学习的链接预测

今天为大家介绍的是来自Mario Krenn团队的一篇论文。一个能够通过从科学文献中获取洞见来建议新的个性化研究方向和想法的工具,可以加速科学的进步。一个可能受益于这种工具的领域是人工智能(AI)研究,近年来科学出版物的数量呈指数…

Kong处理web服务跨域

前言 好久没写文章了,大概有半年多了,这半年故事太多,本文写不下,就写写文章标题问题! 问题描述 关于跨域的本质问题我这里不过多介绍,详细请看历史文章 跨域产生的原因以及常见的解决方案。 我这边是新…

对二分搜索的理解 Go语言版

二分搜索大家都很熟悉&#xff0c;首先我们先来看看基本框架 func binarySearch(nums []int, target int) int {left, right : 0, ...for ... {mid : left (right-left)/2if nums[mid] target {...} else if nums[mid] < target {left ...} else if nums[mid] > targ…

【Pytorch】Visualization of Feature Maps(4)——Saliency Maps

学习参考来自 Saliency Maps的原理与简单实现(使用Pytorch实现)https://github.com/wmn7/ML_Practice/tree/master/2019_07_08/Saliency%20Maps Saliency Maps 原理 《Deep Inside Convolutional Networks: Visualising Image Classification Models and Saliency Maps》&…

如何设置Linux终端提示信息

如何设置Linux终端提示信息 1 方法一&#xff1a;只能在VSCode或者Pycharm显示2 方法二&#xff1a;只能在MobaXterm等远程软件上显示&#xff0c;但全用户都会显示3 方法三&#xff1a;避免用户没看到上面的提示&#xff0c;上面两种都设置一下 在使用远程终端时&#xff0c;由…

基于Qt QChart和QChartView实现正弦、余弦、正切图表

# 源码地址 https://gitcode.com/m0_45463480/QChartView/tree/main# .pro QT += charts​​HEADERS += \ chart.h \ chartview.h​​SOURCES += \ main.cpp \ chart.cpp \ chartview.cpp​​target.path = $$[QT_INSTALL_EXAMPLES]/charts/zoomlinechartINSTAL…

L1-004:计算摄氏温度

题目描述 给定一个华氏温度F&#xff0c;本题要求编写程序&#xff0c;计算对应的摄氏温度C。计算公式&#xff1a;C5(F−32)/9。题目保证输入与输出均在整型范围内。 输入格式&#xff1a;输入在一行中给出一个华氏温度。 输出格式&#xff1a;在一行中按照格式“Celsius C”…

如何使用录屏软件在电脑录制PDF文件

我有一个PDF文件&#xff0c;想用录屏软件将它录制下来并添加上详细的注释&#xff0c;然后发给客户看&#xff0c;请问应该如何录制呢&#xff1f;有没有推荐的录屏软件呢&#xff1f; 不用担心&#xff0c;本文将会详细的为您讲解如何使用录屏软件在电脑端录制PDF文件&#…

GoLang切片

一、切片基础 1、切片的定义 切片&#xff08;Slice&#xff09;是一个拥有相同类型元素的可变长度的序列它是基于数组类型做的一层封装它非常灵活&#xff0c;支持自动扩容切片是一个引用类型&#xff0c;它的内部结构包含地址、长度和容量声明切片类型的基本语法如下&#…

Mac单独修改应用语言

方法1: 方法2: defaults write com.microsoft.Excel AppleLanguages ("zh-cn") defaults write com.microsoft.Word AppleLanguages ("zh-cn")参考&#xff1a;https://www.zhihu.com/question/24976020

Javaweb之Vue组件库Element案例的详细解析

4.4 案例 4.4.1 案例需求 参考 资料/页面原型/tlias智能学习辅助系统/首页.html 文件&#xff0c;浏览器打开&#xff0c;点击页面中的左侧栏的员工管理&#xff0c;如下所示&#xff1a; 需求说明&#xff1a; 制作类似格式的页面 即上面是标题&#xff0c;左侧栏是导航&…

vue高频面试题(2023),有回答思路,并且让你回答清晰

一、对MVC&#xff0c;MVP&#xff0c;MVVM的理解 三者都是项目的架构模式&#xff08;不是类的设计模式&#xff09;&#xff0c;即&#xff1a;一个项目的结构&#xff0c;如何分层&#xff0c;不同层负责不同的职责。 1、MVC&#xff1a; MVC的出现是用在后端&#xff08;…