计算欧式距离别再傻憨憨地去背两点之间的距离公式了,直接一个二范数就搞定了。
比如,A=[1 1;2 2;3 3]
为三行两列的矩阵,行表示点,列表是 X X X 和 Y Y Y 坐标,同理,B=[5 5;6 6;7 7]
。
那么计算A和B三点对应的欧氏距离,可以直接用vecnorm(A-B,2,2)
。
vecnorm
和norm
都是计算范数的函数,但是vecnorm
可以指出对行或列上的范数(默认是对列计算)。
第二个参数是要计算的范数类型,第三个参数是对行计算,对列计算是 1 1 1,对行计算为 2 2 2。
pdist
函数可以计算各种距离。
重复数组不要去用循环什么的,直接repmat
函数就好了。
比如,把A矩阵横向重复三次,repmat(A,1,3)
。把 A \mathbf{A} A矩阵纵向重复两次,repmat(A,2,1)
。
注意,这里虽然也有横向和纵向的区分,但是并不是想上面的例子中那样,纵向用1表示,横向用2表示。而是在第二和第三个参数来指出每个维度上的重复次数。当然,也可以是三维,四维等等。
当然repmat(A,2,2)
可以理解为把矩阵A看做一个单元,扩充为[A, A; A, A]
这两个函数都是随机选取整数,randperm
是无放回的选取,randi
是有放回的选取。
比如,要从1-10之间选出3个不重复的整数,可以用randperm(10,3)
。而不加上第二个参数,就是1-10之间的整数随机排列。
如果要从1-10之间选出3个整数,可以重复,可以用randi(10,1,3)
,这样生成的就是1行3列的3个整数。还可以写成randi([1,10],1,3)
这样的形式来指出选取的范围。
对数据的归一化处理公式如下,其中, x ˉ \bar{x} xˉ为均值。
y i = x i − x m i n x m a x − x m i n y_i=\frac{x_i-x_{min}}{x_{max}-x_{min}} yi=xmax−xminxi−xmin
虽然计算不难,但是对矩阵的每一行进行归一化,就还是比较麻烦。可以采用mapminmax
函数。注意,mapminmax
是对每一行进行归一化。
比如,对矩阵 X 每一行进行归一化,Y=mapminmax(X,0,1)
。得到的 Y 是处于 0-1 之间的归一化。函数默认的是 -1到1的归一化。
这个函数应该是比较常见的函数,但是这里想要想要记录下是因为参数位置不同,返回的结果也是不一样的。
比如, a a a为一个标量, B \mathbf{B} B为一个向量,如果 B \mathbf{B} B中含有 a a a,即Lia=ismember(B,a)
,则得到的Lia
为一个向量,只有数值为 a a a的位置才等于1,其余的为0。
而要表示 a a a是否被包含在 B \mathbf{B} B中,可以写作Lia=ismember(a,B)
,这样得到的就是0或者是1了。
总结一下,就是函数ismember
返回的结果与第一个参数的大小相同。
在计算分贝值的时候,很多时候会遇到功率值与分贝之间的换算。换算并不难,但是写多了就很麻烦(主要是懒得记。。。)。分贝换算公式如下:
X ( d B ) = 10 log 10 ( X ) X(dB)=10\log_{10}(X) X(dB)=10log10(X)
这里再写上 d B dB dB与 d B m dBm dBm的换算
P ( d B ) = 10 log 10 ( P ( W ) 1000 ) P(dB)=10\log_{10}(\frac{P(W)}{1000}) P(dB)=10log10(1000P(W))
为了简单,可以采用x=pow2db(x)
计算分贝,这里要注意,如果计算功率的 d B m dBm dBm形式,变量x
要换成毫瓦。同理,将功率计算为毫瓦的形式,可以用x=db2pow(x)
。
当然也可以用x=db(x,"power")
,这个函数是将能量或功率测量值转换为分贝,可以通过制定第二个参数来实现功率与分贝之间的转换。
在做连续凸近似的时候往往会需要对范数进行一阶泰勒展开,当然可以选择手写求偏导,但是很容易出现错误。这里先给出泰勒展开式的公式。
一元函数 f ( x ) f(x) f(x) 在点 x 0 x_0 x0 处的泰勒展开如下:
f ( x ) = f ( x 0 ) + f ′ ( x 0 ) ( x − x 0 ) + O ( x − x 0 ) ≈ f ( x 0 ) + f ′ ( x 0 ) ( x − x 0 ) \begin{array}{ll} f(x)&=f(x_0)+f'(x_0)(x-x_0)+O(x-x_0)\\ &\approx f(x_0)+f'(x_0)(x-x_0) \end{array} f(x)=f(x0)+f′(x0)(x−x0)+O(x−x0)≈f(x0)+f′(x0)(x−x0)
二元函数 f ( x , y ) f(x,y) f(x,y) 在点 ( x 0 , y 0 ) (x_0,y_0) (x0,y0) 处的泰勒展开如下:
f ( x , y ) ≥ f ( x 0 , y 0 ) + ( ∂ f ∂ x + ∂ f ∂ y ) f ( x 0 , y 0 ) + ⋯ + 1 n ! ( ∂ f ∂ x + ∂ f ∂ y ) n f ( x 0 , y 0 ) f(x,y)\geq f(x_0,y_0)+(\frac{\partial f}{\partial x}+\frac{\partial f}{\partial y})f(x_0,y_0)+\cdots+\frac{1}{n!}(\frac{\partial f}{\partial x}+\frac{\partial f}{\partial y})^nf(x_0,y_0) f(x,y)≥f(x0,y0)+(∂x∂f+∂y∂f)f(x0,y0)+⋯+n!1(∂x∂f+∂y∂f)nf(x0,y0)
但是当你在对 norm(x-y)
直接用 taylor
展开时,Matlab会报错,告诉你无法使用泰勒级数。这是因为,函数泰勒级数存在的条件之一是该函数应该是无限可微的。而 x − y x-y x−y 会在 0 0 0 处产生从 − 1 -1 −1 到 0 0 0 到 1 1 1 的阶跃。因此是不满足可微的条件。
不过可以在求泰勒级数之前,加上 x > y x>y x>y 的条件。
assume(x>y)
补充一点:
当在调用 norm(x-y)
函数时,Matlab会将其写作 (abs(x-y)^2)^(1/2)
。因此在对其求导之后得到一个 sign(x-y)
的符号函数。
获取无重复项,或者判断矩阵内是否包含重复项也是挺常见的操作。有时候操作的时候,会要求整行进行比对。比如判断坐标矩阵 A N × 2 A^{N\times 2} AN×2中是否有重复的坐标。这个时候需要将考虑x坐标和y坐标是否都相同。当然可以通过写循环来逐一判断。但是这样不仅容易出错,也很麻烦。这时候就可以用unique(·)
函数。
unique(·)
函数可以返回无重复项,但是对整行操作时,需要加上参数'rows'
,即unique(A,'rows')
。
unique(·)
函数默认是对数组进行排序的,如果不想排序想按照原来的顺序,可以再加上参数'stable'
,即unique(A,'rows','stable')
。
这个是我现在新学的一个技巧,我觉得很实用。对于两个维度不一样的矩阵对点操作,需要类似于Python中的广播的操作。之前的写法,往往是通过repmat
的方法,将两个矩阵的大小补齐。这种方法虽然快但是占内存。当然也可以选择不占内存的方式,for
循环即可,这种方式虽然不占内存但是耗时。于是就有了介于两者之间的bsxfun
,隐式扩展。
函数形式为C = bsxfun(@fun,A,B)
,其中,@fun
时函数句柄(不了解句柄的自行百度以下,自己写得匿名函数,不需要加@),A
和B
为矩阵,注意,这里要求两个矩阵中必须有一个某一个维度上是1。这也很好理解,比如 A N × 1 A^{N\times 1} AN×1和 B N × 3 B^{N\times 3} BN×3进行首先会将A
在第二维度上repmat
上3,然后再对点相乘。如果 A N × 2 A^{N\times 2} AN×2这就不好算了,至少更复杂了。
支持bsxfun
的句柄函数除了自己写得匿名函数,还有一些函数。
函数 | 符号 | 说明 | 函数 | 符号 | 说明 |
---|---|---|---|---|---|
plus | + | 加 | eq | == | 等于 |
minus | - | 减 | ne | ~= | 不等于 |
times | .* | 对点乘 | gt | > | 大于 |
rdivide | ./ | 对点右除 | ge | >= | 大于等于 |
ldivide | .\ | 对点左除 | lt | < | 小于 |
power | .*+ | 对点幂 | le | <= | 小于等于 |
and | & | 按元素逻辑 AND | or | | | 按元素逻辑 OR |
Matlab想要计算数组的长度一般有这么几种方式(x = [[1 2 3];[3 4 5]]
举例):
length
,length(x)=3
size
,size(x)=[2 3]
numel
,numel(x)=6
,其实就相当于prod(size(x))
,也就是每个维度大小的乘积。在Python中,最常用的就是列表的初始化,直接x = []
就可以了,其实matlab也可以这样做,甚至更好用,比如
>> x = []
x = []
>> x(1, :) = [1 2]
x =
1 2
>> x(3, :) = [3 4]
x =
1 2
0 0
3 4
可以看出matlab没有数组长度范围的限制,可以中间隔几行赋值。但是不推荐采用这种方法,因为矩阵没有预分配,运行速度会变慢。