/images/avatar.png

vllbc

KNN

KNN

参考:https://cuijiahua.com/blog/2017/11/ml_1_knn.html

《统计学习方法》李航(kd树)

简介

k近邻法(k-nearest neighbor, k-NN)是1967年由Cover T和Hart P提出的一种基本分类与回归方法。它的工作原理是:存在一个样本数据集合,也称作为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据后,将新的数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。

主题模型

主题模型

主题模型也可以看成一种词向量表达,主要有LSA、PLSA、LDA。按照这个顺序来逐渐发展的

词袋模型

将所有词语装进一个袋子里,不考虑其词法和语序的问题,即每个词语都是独立的

Transformer

Transformer

\[ -\log \frac{\exp({\operatorname{sim}\left(\mathbf{h}_i, \mathbf{h}_i^{+}\right) / \tau})}{\sum_{j=1}^N\left(\exp({\operatorname{sim}\left(\mathbf{h}_i, \mathbf{h}_j^{+}\right) / \tau})+\exp({\operatorname{sim}\left(\mathbf{h}_i, \mathbf{h}_j^{-}\right) / \tau}\right))} \]

背景

先从word2vec开始说起,word2vec可以看作是一个预训练模型,但是它有个问题就是它没有办法解决一词多义的问题,比如说bank这个词语,有银行的意思,但在某些语义下,它也有河岸的意思,但对于word2vec来说,它区别不了这两种含义,因为它们尽管上下文环境中出现的单词不同,但是在用语言模型训练的时候,不论什么上下文的句子经过word2vec,都是预测相同的单词bank,而同一个单词占的是同一行的参数空间,这导致两种不同的上下文信息都会编码到相同的word embedding空间里去。

ELMo就解决了这个问题,它使用了双向的LSTM,具体的可以看ELMo,总之使用RNN作为特征提取器,解决了多义词的问题,但现在来看,RNN的特征提取的能力是远不如本文的Transformer的,为什么要介绍这些东西呢,这就是原因,Transformer出现后,取代了RNNCNN的地位,成为了最流行的特征提取器,大火的GPTBERT都与Transformer离不开关系。拿bank为例,RNN在读取整个句子之前不会理解bank的含义,也就是RNN的并行能力比较差,而在Transformer中,token之间会互相交互,也就是所谓的自注意力机制,直观地说,Transformer 的编码器可以被认为是一系列推理步骤(层)。在每一步中,token都会互相看着对方(这是我们需要注意的地方——self-attention),交换信息并尝试在整个句子的上下文中更好地理解对方。这发生在几个层(例如,6 个)中。

最大子序和

最大子序和

https://leetcode-cn.com/problems/maximum-subarray/

一开始直接暴力,结果tle了最后

class Solution:
    def maxSubArray(nums):
        res = -float('inf')
        for i in range(len(nums)):
            for j in range(i,len(nums)):
                res = max(res,sum(nums[i:j+1]))
        return res

这说明在leetcode尽量不要嵌套循环,大概率Tle

class Solution:
    def maxSubArray(nums):
        for i in range(1,len(nums)):
            maxs = max(nums[i-1]+nums[i],nums[i])
            nums[i] = maxs
        return max(nums)

最后巧妙地利用了替换的思想,将每次相加的值和当前比较,并将当前替换为较大的那个值,最后求整个列表的最大值。

使用最小花费爬楼梯

使用最小花费爬楼梯

每日一题刷到的。

动态规划类型的题目,重点就是找状态转移方程,因为我不太熟练,对动态规划的题目做的比较少,所以WA了好几次。

class Solution:
    def minCostClimbingStairs(cost):
        res = [] #res[i]就是到第i阶梯时最小的花费
        res.append(cost[0])  #到第一阶梯最小就是0+cost[0]
        res.append(cost[1]) #第二阶梯最小就是0+cost[1]
        #状态转移方程:res[i] = min(res[i-1],res[i-2])+cost[i]
        for i in range(2,len(cost)): 
            res.append(min(res[i-1],res[i-2])+cost[i]) #
        return min(res[-1],res[-2])

踏上第i级台阶有两种方法:

条件随机场

CRF

概率图模型与无向图

图是由结点和连接结点的边组成的集合。结点和边分别记作v和e,结点和边的集合分别记作V和E,图记作\(G=(V, E)\)

无向图是指没有方向的图。

概率图模型是由图表示的概率分布。设有联合概率分布P(Y), Y是一组随机变量,由无向图\(G=(V,E)\)表示概率分布P(Y),即在图G中,结点\(v\in V\)表示一个随机变量\(Y_v\)\(Y=(Y_v)\_{v\in V}\),边e表示随机变量之间的依赖关系。

Adaboost

Boosting算法的工作机制是首先从训练集用初始权重训练出一个弱学习器1,根据弱学习的学习误差率表现来更新训练样本的权重,使得之前弱学习器1学习误差率高的训练样本点的权重变高,使得这些误差率高的点在后面的弱学习器2中得到更多的重视。然后基于调整权重后的训练集来训练弱学习器2.,如此重复进行,直到弱学习器数达到事先指定的数目T,最终将这T个弱学习器通过集合策略进行整合,得到最终的强学习器。

分割等和子集

分割等和子集

题目:

https://leetcode-cn.com/problems/partition-equal-subset-sum/?utm_source=LCUS&utm_medium=ip_redirect&utm_campaign=transfer2china

思路:

典型的01背包问题,利用套路框架做即可

注意做了优化,把原本的二维dp降低了一维

代码:

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        if sum(nums) % 2:
            return False
        s = sum(nums) // 2
        dp = [False for _ in range(s+1)]
        dp[0] = True
        for i in range(1,len(nums)+1): 
            for j in range(s,nums[i-1]-1,-1): # 容量
                dp[j] = dp[j] or dp[j-nums[i-1]] # 用了or操作符
        return dp[s]

更一般的套路,定义二维数组,然后二维dp

kd树

kd树

knn算法就是用kd树实现的

二分查找

很简单 就不说了

BST

很简单 就不说了

多维数组

假设数组B为\([[6, 2], [6, 3], [3, 5], [5, 0], [1, 2], [4, 9], [8, 1]]\),有一个元素x,我们要找到数组B中距离x最近的元素,应该如何实现呢?比较直接的想法是用数组B中的每一个元素与x求距离,距离最小的那个元素就是我们要找的元素。假设x = [1, 1],那么用数组B中的所有元素与x求距离得到[5.0, 5.4, 4.5, 4.1, 1.0, 8.5, 7.0],其中距离最小的是1,对应的元素是数组B中的[1, 2],所以[1, 2]就是我们的查找结果。

最小公众前缀

最小公众前缀

leetcode上的简单题,最小公众前缀

有三种解法,一种常规,两种巧妙解法

# 最小公共前缀

#解1:常规解法 思路就是一个一个判断 先判断所有字符串第一个是否相同,不相同就返回,否则然后依次往后判断
def longestCommonPrefix1(strs):
        if len(strs) == 0:
            return ''
        if len(strs) == 1:
            return strs[0]
        minl=min([len(x) for x in strs])  #求最小长度
        end = 0
        while end < minl:   #判断是否到最小长度
            for i in range(1,len(strs)):  #以第一个字符串为基准
                if strs[i][end] != strs[i-1][end]:  #如果到end这里不再相等 则返回到end这里的字符串即最小公共前缀
                    return strs[0][:end]
            end+=1
        return strs[0][:end]
#常规方法容易想到 但是缺点是运行速度慢,从每次判断都要遍历所有字符串就可以看出

#解2: 通过ascii码来判断
#Python里字符串是可以比较的,按照ascII值排
def longestCommonPrefix2(strs):
        if not strs:
            return 0
        s1 = max(strs) 
        s2 = min(strs)
        #找出s1 s2的最小公共前缀即为整个列表的最小公共前缀
        for i,s in enumerate(s2):
            if s1[i] != s:
                return s1[:i]
        return s2
#通过max 和 min 函数来找到列表里面最大最小的两个字符串 然后找到这两个字符串的最小公共前缀。


#解3:通过python语法糖 将每个字符串的每个对应字符串存为一组,用zip函数,比如说所有的字符串第一个存在一起,然后用set去重,如果留下了一个,则说明都重复了,则就是相同的
def longestCommonPrefix3(strs):
        if not strs:
            return 0
        cc = list(map(set,zip(*strs)))  #为什么用map呢 因为要对zip压缩后的每一个序列去重
        res = ''  #结果
        for i,s in enumerate(cc):
            x = list(s)
            if len(x) > 1: #如果长度大于1 说明有不一样的 则直接退出
                break
            res += x[0]
        return res

如上!