网站上线后的工作南宁seo专员
某大厂搜推一面
一、tdidf怎么计算的?
TF-IDF(Term Frequency - Inverse Document Frequency) 是一种用于衡量词语在文档集中重要性的统计方法,常用于文本特征提取。
TF−IDF(t,d)=TF(t,d)×IDF(t)
TF-IDF(t, d) = TF(t, d) × IDF(t)
TF−IDF(t,d)=TF(t,d)×IDF(t)
t
:词语 termd
:文档 document
1.1. 词频 TF(Term Frequency)
TF(t,d)=ft,d/总词数
TF(t, d) = f_{t,d} / 总词数
TF(t,d)=ft,d/总词数
也可以使用对数平滑:
TF(t,d)=log(1+ft,d)TF(t, d) = log(1 + f_{t,d})TF(t,d)=log(1+ft,d)
- ft,df_{t,d}ft,d 是词 t 在文档 d 中出现的次数。
1.2. 逆文档频率 IDF(Inverse Document Frequency)
表示一个词在多少文档中出现,越常见的词权重越低:
IDF(t)=log(N/(1+nt))
IDF(t) = log(N / (1 + n_t))
IDF(t)=log(N/(1+nt))
N
:总文档数n_t
:包含词 t 的文档数
二、位置编码 Positional Encoding 实现细节
2.1. 背景
Transformer 架构没有循环结构或卷积结构,因此需要添加位置信息以表示序列中 token 的先后顺序。 位置编码是一种可加性结构,它与词向量相加,一同输入到模型中。
2.2. 原始实现(Sinusoidal Positional Encoding)
论文《Attention is All You Need》中提出的位置编码如下:
2.2.1. 数学表达式:
给定位置 pos
和维度 i
,编码为:
PE(pos, 2i) = sin(pos / 10000^(2i / d_model))
PE(pos, 2i+1) = cos(pos / 10000^(2i / d_model))
其中:
pos
是序列中的位置(从 0 开始)i
是维度索引d_model
是词向量维度(如 512)
说明:
- 每个维度使用不同频率的正余弦函数编码
- 偶数维用
sin
,奇数维用cos
- 编码具有周期性和位置相对信息的优良性质
2.3. PyTorch 实现
import torch
import math
import torch.nn as nnclass PositionalEncoding(nn.Module):def __init__(self, d_model, max_len=5000):super().__init__()# 初始化一个 [max_len, d_model] 的位置编码矩阵pe = torch.zeros(max_len, d_model)position = torch.arange(0, max_len).unsqueeze(1) # [max_len, 1]div_term = torch.exp(torch.arange(0, d_model, 2) * (-math.log(10000.0) / d_model))# 偶数维:sinpe[:, 0::2] = torch.sin(position * div_term)# 奇数维:cospe[:, 1::2] = torch.cos(position * div_term)pe = pe.unsqueeze(0) # [1, max_len, d_model]self.register_buffer('pe', pe)def forward(self, x):"""x: [batch_size, seq_len, d_model]return: same shape, with positional encoding added"""x = x + self.pe[:, :x.size(1), :]return x
三、L1 与 L2 距离的公式与图像差异
3.1. L1 距离(曼哈顿距离):
DL1(x,y)=∑i∣xi−yi∣D_{L1}(\mathbf{x}, \mathbf{y}) = \sum_i |x_i - y_i|DL1(x,y)=i∑∣xi−yi∣
对于向量 w=[x,y]\mathbf{w} = [x, y]w=[x,y] 的 L1 范数(距离原点)为:
∥w∥1=∣x∣+∣y∣\|\mathbf{w}\|_1 = |x| + |y|∥w∥1=∣x∣+∣y∣
3.2. L2 距离(欧几里得距离):
DL2(x,y)=∑i(xi−yi)2D_{L2}(\mathbf{x}, \mathbf{y}) = \sqrt{\sum_i (x_i - y_i)^2}DL2(x,y)=i∑(xi−yi)2
对于向量 w=[x,y]\mathbf{w} = [x, y]w=[x,y] 的 L2 范数为:
∥w∥2=x2+y2\|\mathbf{w}\|_2 = \sqrt{x^2 + y^2}∥w∥2=x2+y2
3.3. 实际意义
- L1 距离的等距图像是菱形,有尖角,更容易导致某些坐标为 0(稀疏性)
👉 用于 Lasso 正则,更利于特征选择。 - L2 距离的等距图像是圆形,光滑、连续
👉 用于 Ridge 正则,更适合抑制整体权重而不是置零。 - 高维空间中:
- L1 单位球是“超菱形”(角很多)
- L2 单位球是“超球面”(圆滑)
- 梯度方面:
- L2 正则的导数是线性的,易优化
- L1 的导数在 0 附近不连续,导致参数更容易变成 0
四、FM(Factorization Machines) vs LR(Logistic Regression)对比
4.1. 基本原理
项目 | Logistic Regression (LR) | Factorization Machines (FM) |
---|---|---|
目标 | 线性模型,用于预测分类概率或回归值 | 引入隐向量建模特征之间的交叉项 |
表达式 | y^=w0+∑iwixi \hat{y} = w_0 + \sum_i w_i x_i y^=w0+i∑wixi | y^=w0+∑iwixi+∑i<j⟨vi,vj⟩xixj \hat{y} = w_0 + \sum_i w_i x_i + \sum_{i<j} \langle \mathbf{v}_i, \mathbf{v}_j \rangle x_i x_j y^=w0+i∑wixi+i<j∑⟨vi,vj⟩xixj |
特征交叉 | 不考虑 | 显式考虑二阶特征交叉 |
模型容量 | 低,线性 | 更高,非线性(低阶多项式) |
4.2. 手撕逻辑回归
import numpy as npclass LogisticRegression:def __init__(self, learning_rate=0.01, num_iterations=1000):self.learning_rate = learning_rate # 学习率self.num_iterations = num_iterations # 迭代次数self.theta = None # 模型参数def sigmoid(self, z):"""计算 Sigmoid 函数"""return 1 / (1 + np.exp(-z))def compute_cost(self, X, y):"""计算交叉熵损失函数"""m = len(y)p = self.sigmoid(np.dot(X, self.theta))cost = - (1/m) * np.sum(y * np.log(p) + (1 - y) * np.log(1 - p))return costdef gradient_descent(self, X, y):"""梯度下降优化"""m = len(y)for i in range(self.num_iterations):p = self.sigmoid(np.dot(X, self.theta)) # 计算预测值gradient = (1/m) * np.dot(X.T, (p-y)) # 计算梯度self.theta -= self.learning_rate * gradient # 更新参数if i % 100 == 0: # 每100次输出一次损失值cost = self.compute_cost(X, y)print(f"Iteration {i}, Cost: {cost}")def fit(self, X, y):"""训练模型"""m, n = X.shapeself.theta = np.zeros(n) # 初始化参数self.gradient_descent(X, y)def predict(self, X):"""预测新样本的类别"""probabilities = self.sigmoid(np.dot(X, self.theta))return probabilities >= 0.5 # 预测类别:如果大于等于 0.5,分类为 1,否则为 0
4.3. 手撕FM
import torch
import torch.nn as nn
import torch.nn.functional as Fclass FactorizationMachine(nn.Module):def __init__(self, field_dims, embed_dim=4):"""参数:- field_dims: List[int],每个离散特征的取值总数- embed_dim: 每个特征的 embedding 维度(即 FM 中的 k)"""super().__init__()self.num_fields = len(field_dims)self.embed_dim = embed_dim# 一阶线性项:每个特征值一个标量 embeddingself.linear_emb = nn.ModuleList([nn.Embedding(field_size, 1) for field_size in field_dims])# 二阶交叉项 embedding:每个特征值一个向量(或者说一个one_hot值一个k维向量)self.fm_emb = nn.ModuleList([nn.Embedding(field_size, embed_dim) for field_size in field_dims])self.bias = nn.Parameter(torch.zeros(1))def forward(self, x):"""x: LongTensor of shape [batch_size, num_fields]每列是一个稀疏特征的索引(例如用户ID、性别、电影ID 等)"""# 一阶线性项,shape: [batch_size, 1]linear_part = sum(emb(x[:, i]) for i, emb in enumerate(self.linear_emb))print(linear_part.shape)# 二阶交叉项,每个是 [batch_size, embed_dim] -> [batch_size, num_fields, embed_dim]embed_vectors = [emb(x[:, i]) for i, emb in enumerate(self.fm_emb)] print(len(embed_vectors), embed_vectors[0][0].shape)embed_stack = torch.stack(embed_vectors, dim=1)print(embed_stack.shape)square_of_sum = torch.pow(embed_stack.sum(1), 2) # [batch_size, embed_dim]sum_of_square = (embed_stack ** 2).sum(1) # [batch_size, embed_dim]interaction = 0.5 * (square_of_sum - sum_of_square).sum(1, keepdim=True) # [batch_size, 1]output = linear_part + interaction + self.biasreturn torch.sigmoid(output) # 二分类输出
五、17. 电话号码的字母组合
- 代码:
mapping = ["","", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"]
class Solution:def letterCombinations(self, digits: str) -> List[str]:n = len(digits)if n == 0:return []res = []path = [""] * ndef dfs(i):if i==n:res.append("".join(path))returnfor c in mapping[int(digits[i])]:path[i] = cdfs(i+1)dfs(0)return res