mxxhcm's blog

  • 首页

  • 标签

  • 分类

  • 归档

logistic regression

发表于 2019-10-28 | 更新于 2019-12-17 | 分类于 机器学习

logistic regression

逻辑回归是使用线性模型进行分类的模型,它是一个对数线性模型。
在使用线性模型进行回归时,产生的预测值是实数值。而对于分类任务,函数的输出需要是离散值。对于二分类任务,类别分别记为$0$和$1$,如果将回归模型的值限制在$[0, 1]$之间,那么接下来我们要做的就是将$[0,1]$之间的值转换为$0$和$1$。比如单位跃阶函数:
$$y=\begin{cases}0, x \lt 0;\\0.5, x=0;\\1, x\gt 0\end{cases} \tag{1}$$
但是它是离散的,需要找一个连续的函数。这就是接下来介绍的logistic function。

logistic distribution

连续随机变量$X$服从logistic distribution指的是$X$具有以下分布函数和密度函数:
$$F(x) = P(X\le x) = \frac{1}{1 + e^{-(x-\mu)/\gamma} } \tag{2}$$
$$f(x) = F’(x) = \frac{e^{-(x-\mu)/\gamma} }{\gamma(1 + e^{-(x-\mu)/\gamma} )^2 } \tag{3}$$
其中$\mu$为位置参数,$\gamma \gt 0$是形状参数。分布函数属于logistic function,相应的图如下所示,它的取值在$[0,1]$之间,是一条sigmod曲线,以点$(\mu, \frac{1}{2})$为中心对称,即满足:
$$F(-x+\mu) - \frac{1}{2} = -F(x-\mu) +\frac{1}{2} \tag{4}$$
logistic_func
曲线在中心附近增长的速度很快,在两端增加的速度很慢。$\gamma$越小,曲线在中心附近增长的越快。当$\mu=0, \gamma=1$时,得到一个特殊的函数:
$$ f(x) = \frac{1}{1+e^{-x} } \tag{5}$$
用$w^T x+b$代替$f(x)$中的$x$,就得到了:
$$h(x) = \frac{1}{1+ e^{-(w^T x +b)} } \tag{6}$$
其中$x$是输入,$\theta$是要求的参数。

二项logistic regression

上面给出的$y=h(x)$其实是一个二项的logistic regression分类函数。式子$(6)$可以进行变形,得到
$$ \log\frac{y}{1-y} = \log\frac{\frac{1}{1+ e^{-(w^T x +b)} } }{1-\frac{1}{1+ e^{-(w^T x +b)} } }= \log\frac{\frac{1}{1+ e^{-(w^T x +b)} } }{\frac{e^{-(w^T x +b)} }{1+ e^{-(w^T x +b)} } } = \log\frac{1}{e^{-(w^T x +b) } } = w^T x +b \tag{7}$$
这里的$y$是一个函数值,给定一个$x$就会有一个$y$。将$y$看做给定$x$,事件发生的概率,$1-y$是该事件不发生的概率,两者的比值$\frac{y}{1-y}$被称为几率,反映了$x$发生的相对可能性。对几率取对数得到对数几率logit:
$$\log \frac{y}{1-y}$$
可以看出,公式$6$实际上是在近似真实标记的对数几率。所以这个模型叫作对数几率回归。如果将式子$(6)$中的$y$看成类后验概率估计$p(y=1|x)$,公式$(7)$可以写成:
$$\log \frac{p(y=1|x)}{p(y=0|x)} = w^T x+b \tag{8}$$
则有:
$$ p(y=1|x) = \frac{e^{w^T x+ b} }{1+e^{w^T x+ b} } \tag{9} $$
$$ p(y=0|x) = \frac{1}{1+e^{w^T x+ b} } \tag{10} $$
其实就是分子分母同时乘了$e^{w^T x+ b}$。线性模型$w^T x+b$的值域是实数域,然而logistic模型将线性函数$w^T x+b$转换成了如公式$(8),(9)$的概率。当$w^T x+b$的值越接近于$1$,$p(y=1|x)$的概率越接近于$1$。

最大似然估计进行参数估计

给定训练集样本$(x_1, y_1), \cdots, (x_N,y_N)$,可以使用最大似然估计求解给定的$w$和$b$:
$$l(w,b) =\prod_{i=1}^m p(y_i|x_i; w,b) \tag{11}$$
即让所有样本属于其真实标记的概率越大越好。设$p(y=1|x) = \pi(x), p(y=0|x) = 1-\pi(x)$,这两个式子可以用一个式子表示$\pi(x)^y (1-\pi(x))^{1-y} $,重写式子$(11)$,得到的似然函数为:
$$l(w,b) =\prod_{i=1}^m p(y_i|x_i; w,b) = \prod_{i=1}^m \left[\pi(x)\right]^{y_i} \left[1-pi(x)\right]^{1-y_i} \tag{12}$$

取对数得到对数似然:
\begin{align*}
L &= \log l(w,b) \\
& = \log \prod_{i=1}^m \left[\pi(x)\right]^{y_i} \left[1-pi(x)\right]^{1-y_i}\\
& = \sum_{i=1}^m \left[y_i\log\pi(x)+(1-y_i)\log(1-\pi(x_i)) \right] \tag{13}\\
& = \sum_{i=1}^m \left[y_i\log\frac{\pi(x)}{1-\pi(x_i)} + \log(1-\pi(x_i)) \right] \tag{14}\\
& = \sum_{i=1}^m \left[y_i (w^T x+b) - \log(1+e^{w^T x+b} ) \right]\\ \tag{15}
\end{align*}
然后求得$w$和$b$即可。

多项logistic regression

假设离散型随机变量的取值集合是${1, 2,\cdots, K}$,多项logistic regression的公式是:
$$P(Y=k|x) = \frac{e^{w^T x+b} }{ 1+ \sum_{k=1}^{K-1} e^{w^T x+b} }, k = 1, 2, \cdots, K-1 \tag{16}$$
$$P(Y=K|x) = \frac{1}{1+ \sum_{k=1}^{K-1} e^{w^T x+b} } \tag{17}$$

参考文献

1.周志华《西瓜书》
2.李航《统计机器学习》

beyesian classifier naive baye classifier

发表于 2019-10-27 | 更新于 2019-12-17 | 分类于 机器学习

朴素贝叶斯分类器

简介

朴素贝叶斯法是基于贝叶斯定理和特征条件独立假设的分类方法。对于给定的训练数据,根据特征条件独立假设学习,输入和输出的联合概率分布;然后基于此模型,对于新给定的输入$x$,利用贝叶斯定理求出后验概率最大的输出$y$。
朴素贝叶斯的一个假设:条件独立假设,拿公式举个例子就是
$$P(X|Y=y_k)=\prod_{i=1}^m P(x_i|Y=y_k) \tag{1}$$
其中$X=[x_1, x_2,\cdots, x_m]$即$m$个属性。朴素贝叶斯实际上学习到生成数据的机制,属于生成模型。条件独立假设是说用于分类的特征在类别确定的情况下都是条件独立的,这一假设让朴素贝叶斯变得好计算,但是可能会牺牲一定的精度。

训练过程

贝叶斯分类器的流程如下所示:

  1. 给出训练样本集,属性集合$X=[x_1, x_2,\cdots, x_m]$,标签集合$Y=[y_1, y_2,\cdots, y_n]$,计算每个类别$y_j$中出现属性$x_i$的条件概率,即
    $$P(x_i|y_j), 1 \le i \le m, 1 \le j \le n \tag{2}$$
  2. 给出一个新的样本$X$,根据贝叶斯定理以及条件独立假设,计算:
    $$P(y_k|X) = \frac{P(y_k)P(X|y_k)}{P(X)} = \frac{P(y_k) \prod_{i=1}^m P(x_i|y_k) }{P(X)} \tag{3}$$
  3. 从$P(y_k|X)$中选出最大的$P$对应的$y_k$当做label。

可以看出,朴素贝叶斯分类器的关键就是计算条件概率:

  • 当属性$X$是离散值时,可以统计样本中各个$P(x_i|y_j)$的频率近似计算概率
  • 当属性$X$是连续值时,可以假设变量服从某种分布,使用训练数据估计分布的参数。 如高斯分布的均值和方差。

后验最大化的含义

朴素贝叶斯法将实例分到后验概率最大的类中,相当于期望风险最小化。

参数估计方法

在朴素贝叶斯的训练过程中,我们需要学习先验概率以及条件概率。可以使用贝叶斯估计,最大似然估计和最大后验估计求朴素贝叶斯的先验概率和条件概率。

参考文献

1.https://www.cnblogs.com/phoenixzq/p/3539619.html
2.http://funhacks.net/2015/05/18/Bayesian-classifier/

C/C++ input and output

发表于 2019-10-27 | 更新于 2019-12-19 | 分类于 C/C++

特殊符号的ASCII

'\n’是10。
EOF是-1。

输入输出

C/C++语言中输入输出主要分为两种,一种是文件的输入输出,另一种是标准输入输出即stdin和stdout,从控制台进行输入输出。其实标准输入输出是一种特殊的文件流,这样子文件的输入输出也可以用在标准输入输出。

文件输入和输出常用函数

1
2
3
4
5
6
7
8
9
10
11
12
//字符
fgetc() and fputc()
getc() and putc()
// getc()和fgetc()功能功能一样,只不过getc()是宏实现,进行了优化,getc()可以被当做宏调用。而fgetc()只能当做函数被调用,getc()也能读取'\n'字符。

//n个项
fread() and fwrite()

//字符串
getline()
fgets() and fputs()
fscanf() and fprintf()

标准输入和输出常用函数

1
2
3
4
5
6
7
8
//字符
getchar() and putchar()
scanf() and printf()
getche()和getch() //不经过缓冲区

//字符串
scanf() and printf()
gets() and puts()

注意事项

  1. getline(),fgets()都能用于标准输入输出中的读入。
  2. 当用于标准输入输出时:
    getline(),fgets(),scanf(),gets()之间的区别和联系:
    getline()推荐使用,fgets()不推荐,scanf()不推荐,gets()别用。
    因为fgets()和scanf()都有缓冲区溢出的危险,而gets()最容易发生缓冲区溢出。
  3. fgetc()和getc()都是用于文件中字符操作的。而fgets()是用于文件中字符串操作的,gets()是用于标准输入输出中字符串操作的。
  4. getc()和fgetc()功能功能一样,只不过getc()是宏实现,进行了优化,getc()可以被当做宏调用。而fgetc()只能当做函数被调用,getc()也能读取’\n’字符。

缓冲区

我们在使用输入输出函数的时候,不管是从文件还是控制台中读取数据,数据都会先存放在缓冲区里面,在需要使用的时候会在缓冲区里面提取,缓冲区是一个队列,遵循先进先出的规则。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>
int main() {
int a, b;
scanf("%d %d", &a, &b);
printf("%d %d\n", a, b);

scanf("%d %d", &a, &b);
printf("%d %d\n", a, b);

scanf("%d %d", &a, &b);
printf("%d %d\n", a, b);
return 0;
}

在控制台输入:

1
12 23 34 45 56 67 78 89

控制台输出结果:

1
2
3
12 23
34 45
56 67

由于输入在控制台的数据已经到了缓冲区,所以除了第一次调用scanf()的时候控制台会弹出(缓冲区为空),另两次则不会弹出(缓冲区不为空),直接从缓冲区里面拿取数据。
如果不想这样做可以选择清空缓冲区,可以使用fclose()函数清空缓冲区并关闭流,但是这样我们就无法继续使用流了。我们还可以选择使用fflush()函数,在不关闭流的情况下清空缓冲区。

1
int fflush ( FILE * stream );

如果给出的文件流是一个输出流,那么fflush()把输出到缓冲区的内容写入文件;如果给出的文件流是输入类型的,结果未定义;
fflush(NULL)刷新所有的输出流;
fflush(stdin)刷新标准输入缓冲区,把输入缓冲区里的东西丢弃;但是fflush在linux上并不work。
fflush(stdout)刷新标准输出缓冲区,把输出缓冲区里的东西打印到标准输出设备上。
例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
int main() {
int a, b;
scanf("%d %d", &a, &b);
printf("%d %d\n", a, b);
fflush(stdin);

scanf("%d %d", &a, &b);
printf("%d %d\n", a, b);
fflush(stdin);

scanf("%d %d", &a, &b);
printf("%d %d\n", a, b);
return 0;
}

在控制台输入:

1
12 23 34 45 56 67 78 89

控制台输出

1
12 23

然后会等待控制台输入。(我在linux上并没有实验成功。)

文件输入/输出

打开文件fopen和关闭文件close

函数原型

1
2
3
4
5
/* 
* 打开文件,打开成功返回一个FILE指针,打开失败返回NULL
* type:是文件操作方法,包括'w', 'a', 'rb', 'wb', 'ab', 'r+', 'w+', 'a+', 'rb+', 'wb+', 'ab+'
FILE* fopen(char*filename, char* type);
int fclose(FILE* stream);

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h> 
#include <stdlib.h>

int main()
{
char filename[20] = "data.txt";
FILE *fp = fopen(filename, "r");
if (fp == NULL)
{
printf("Cannot open file.\n");
exit(0);
}
else
{
printf("Open file %s success.\n", filename);
}
fclose(fp);

return 0;
}

从文件流中读写字符

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
* 从文件流中读取单个字符,会读取'\n'字符,
* File* 读入文件流和输出文件流
* int ch: 待写入字符
* fgetc()和getc()返回读取的字符,
* fputc()和putc()返回输出字符的ascii,否则 返回 EOF .
*/
*/
int fgetc(FILE* stream);
int getc(FILE* stream);

int fputc(int ch, FILE* stream);
int putc(int ch, FILE* stream);

从文件流中读取和写入多个数据项

1
2
3
4
5
6
7
8
/*
* 从流指针指定的文件中读取nobj个数据项,每个数据项有size个字节,存入ptr指向的缓冲区。读取的数据项不一定等于nobj,可能读完了或者出错了。
* ptr:缓冲区指针
* size_t size: 每个数据项字节
* size_t nobj: 读取多少个数据
*/
size_t fread(void* ptr, size_t size, size_t nobj, FILE* stream);
size_t fwrite(const void* ptr, size_t size, size_t nobj, FILE* stream);

从文件流中读写字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
* 从文件中读取一行,getline会读入换行符。
* *lineptr指向一个动态分配的内存区域。*n是所分配内存的长度。如果*lineptr是NULL的话,getline函数会自动进行动态内存的分配(忽略*n的大小),所以使用这个函数非常注意的就使用要注意自己进行内存的释放。
* 如果*lineptr分配了内存,但在使用过程中发现所分配的内存不足的话,getline函数会调用realloc函数来重新进行内存的分配,同时更新*lineptr和*n。
* 注意*lineptr指向的是一个动态分配的内存,由malloc,calloc或realloc分配的,不能是静态分配的数组。
*/
ssize_t getline(char **lineptr, size_t *n, FILE *stream);

/*
* fgets从流文件中n个字符到指定数组中,遇到 "\n"就停止。
* char* str: 字符数组或者字符串指针,字符串指针一定要配内存空间,否则会出问题
* int n: 从流指针开始读取n个字符。
* fgets()返回值:
* n <= 0或者读入错误,或者遇到EOF,返回NULL
* n = 1返回空串
* 读入成功返回缓冲区地址
* fputs()返回值:
* 输出成功返回大于$0$的值,否则返回EOF
*/
char* fgets(char* str, int n, FILE* stream);
int fputs(char* str, FILE* stream);

int fscanf(FILE* stream, char* format, variable-list);
int fprintf(FILE* stream, char* format, variable-list);

标准输入/输出

读写字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
* scanf函数的格式说明符有几个就要取几次数据,
* 只要碰到格式说明符就必须把数据取走,没取完
* 的数据继续留在缓冲区中。
* scanf()加%c
*/
scanf();
printf();

/*
* 将用户输入的字符输出到标准输出设备,也是按下回车后从缓冲区读取。
*/
getchar();
putchar();

/*
* 不读取缓冲区的字符,只要用户输入字符,getche()函数会立刻读取,而不需等待按回车键,并在屏幕上显示读入的字符。
*/
getche();
//它与getche()的区别是,getch()不需将所输入的字符显示到屏幕上
getch();

读写字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
* gets
* /Never use gets(). 别用gets(),因为get()没有指定可以使用的缓冲区大小,它会在遇到换行符或者EOF才能停止,把所有的字符都存在缓冲区中,然而因为不知道要读多少个字符,所以可能会发生溢出。
*/
char *gets(char *s);
//* 以"\0"作为字符串的结束。
puts();

/*
* scanf()加%s,但是%s会在遇到空白符(空格,tab)时自动结束,而gets和fgets()都是以换行或者EOF为结束。
*/
scanf();
printf();

其他

可以定义文件指针,指向stdin和stdout,文件的读写函数就也可以使用到标准输入输出了。
如下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

void main()
{
int ch;

FILE *pfin = stdin; //定义一个文件指针,并指向标准输入设备(键盘)
FILE *pfout = stdout; //定义一个文件指针,并指向标准输出设备(屏幕)

printf("Enter a string: ");

ch = getc(pfin); //使用getc()函数获取缓冲区中的第一个字符

putc(ch, pfout); //使用putc()函数输出该字符
putc('\n', pfout); //使用putc()函数输出换行字符
}

文件输入示例

从文件中一行一行的读取数字

有data.txt如下所示:

1
2
3
13
38
28

读取程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h> 
#include <stdlib.h>

#define N 510

int main()
{
char filename[20] = "data.txt";
FILE *fp = fopen(filename, "r");
if (fp == NULL)
{
printf("Cannot open file \n");
exit(0);
}

char chunk[128];
int array[N] = {0};
int count = 0;
while (fgets(chunk, sizeof(chunk), fp)!=NULL)
{
array[count] = atoi(chunk);
count += 1;
}
fclose(fp);
return 0;
}

参考文献

1.https://blog.csdn.net/strongwangjiawei/article/details/7786085
2.https://solarianprogrammer.com/2019/04/03/c-programming-read-file-lines-fgets-getline-implement-portable-getline/
3.https://stackoverflow.com/questions/20378430/reading-numbers-from-a-text-file-into-an-array-in-c
4.http://manpages.ubuntu.com/manpages/bionic/man3/fgetc.3.html
5.https://www.cnblogs.com/JCSU/articles/1306308.html
6.https://www.cnblogs.com/JCSU/articles/1306308.html
7.https://blog.csdn.net/baidu_27435045/article/details/53313699
8.https://stackoverflow.com/questions/17318886/fflush-is-not-working-in-linux

bayesian decision theorem and bayesian classifier

发表于 2019-10-26 | 更新于 2019-12-17 | 分类于 机器学习

关键字

贝叶斯分类器,贝叶斯定理,朴素贝叶斯,贝叶斯错误率

贝叶斯决策理论

在概率论基础中已经简单介绍了频率学派和贝叶斯学派。贝叶斯学派中几个重要的概念:先验,后验。
贝叶斯决策理论是通过计算后验概率进行决策的,贝叶斯决策理论的实际意义不大,但是具有非常重要的理论意义,尤其是误差上界的计算。

贝叶斯定理(公式)

假设X,Y是一对随机变量,它们的联合概率$P(X=x, Y=y)$是指$X$取值$x$且$Y$取值为$y$的概率,条件概率是指一个随机变量在另一个随机变量取值已知的情况下取某一个特定值的概率。比如$P(Y=y|X=y)$是指在变量$X$取值$x$的情况下,变量$Y$取值$y$的概率。$X$和$Y$的联合概率和条件概率满足如下关系:
$$P(X,Y) = P(Y|X)\cdot P(X) = P(X|Y)\cdot P(Y) \tag{1}$$
由上面的公式可以得到下面公式,称为贝叶斯定理:
$$ P(Y|X) = \frac{P(X|Y)P(Y)}{P(X)} \tag{2}$$

贝叶斯公式最伟大之处就在于将先验概率转化为了后验概率。使得后验概率变得可以求解了。

最小错误率贝叶斯决策

最小风险贝叶斯决策

贝叶斯分类器

根据贝叶斯决策理论得到的分类器,以贝叶斯定理为基础,是一类分类算法的总称,叫做贝叶斯分类器。常见的贝叶斯分类器有朴素贝叶斯和贝叶斯信念网络。

贝叶斯决策边界

贝叶斯分类器产生最低的错误率,叫做贝叶斯错误率。因为贝叶斯分类器总是选择使式子$(1)$最大化的类,在$X=x_0$处的错误率是$1-\max_j Pr(Y=j|X=x_0)$。
整个贝叶斯分类器的错误率是:
$$1-\mathbb{E}\left(\max_j Pr(Y=j|X=x_0)\right) \tag{6}$$
其中期望表示计算所有$X$的可能取值上的平均错误率。

参考文献

1.https://www.cnblogs.com/phoenixzq/p/3539619.html
2.http://funhacks.net/2015/05/18/Bayesian-classifier/

generate random numbers in a interval from specify distribution

发表于 2019-10-26 | 更新于 2019-10-27 | 分类于 概率论与统计

问题

如何利用一个分布(高斯分布),生成指定区间内的随机数?
比如在[-100,100]区间内,利用生成分布产生200个随机数,这个其实是叫截断正态分布。
思路:
我的想法是先使用正态分布随机生成一个数,然后判断这个数是否是满足区间内,如果不满足,就生成下一个。

代码实现

C

1
2
3
4
```

### python
``` python

matlab

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
```

### R
``` R
rand_interval = function(min, max, number)
{
sd = (as.numeric(max)-as.numeric(min))/3
count = 0
res = 1:number
while(TRUE)
{
x = rnorm(1, mean=0,sd=sd)
if(x >= min && x <= max)
{
count = count+1
res[count] = x
}
}
return (res)
}

min = -100
max = 100
number = 20
x1 = rand_interval(min, max, number)
x2 = rand_interval(min, max, number)
x1
x2

参考文献

1.https://www.ilovematlab.cn/thread-302139-1-1.html
2.https://stats.stackexchange.com/questions/113230/generate-random-numbers-following-a-distribution-within-an-interval

generative model and discriminative model

发表于 2019-10-26 | 更新于 2019-12-17 | 分类于 机器学习

生成式模型

$$ P(Y|X) = \frac{P(X, Y)}{P(X)}$$
生成式模型为了对$X$进行分类,会对如何生成数据进行建模,学习联合概率密度函数$P(X,Y)$。然后基于学习的联合密度函数$P(X,Y)$,预测哪一类最有可能。而这也是为什么他叫生成式模型,因为模型表示了给定输入$X$产生输出$Y$的生成关系,根据联合概率$P(X,Y)$和已知的先验分布来计算后验分布$P(Y|X)$,而$P(X,Y)$可以看成生成样本$(X,Y)$的概率。
常见的生成模型有:朴素贝叶斯和隐马尔可夫。

判别式模型

$$P(Y|X)$$
判别式模型直接求的就是$P(Y|X)$即给定输入$X$的条件概率。不关心数据如何产生,只关心怎么分类就行了。而判别式模型,是直接根据$X$给出$Y$的判别。
常见的判别式模型有KNN,感知机,逻辑回归,决策树,最大熵,boost以及CRF等。

生成式模型vs判别式模型

  • 生成式模型和判别式模型都是用于分类问题的。分类问题的目标是给出输入$X$,预测它的类别$Y$,即:
    $$Y=f(X)$$
    或者
    $$P(Y|X)$$
  • 生成模型是利用数据学习联合概率密度分布,而判别模型是利用数据学习条件概率分布。
  • 存在隐变量时候,可以使用生成式不能使用判别式
  • 生成式方法可以计算联合概率分布$P(X, Y)$

参考文献

1.https://www.quora.com/What-are-the-differences-between-generative-and-discriminative-machine-learning
2.https://www.zhihu.com/question/20446337/answer/256466823

matlab basic

发表于 2019-10-26 | 更新于 2020-02-16 | 分类于 其他编程语言

Matlab基础

for循环

if语句

plot

1
2
xlabel('your x label', 'fontsize', 20);
xlim([0, 2*pi]);

矩阵大小

1
2
x = ones(20, 3);
size(x);

产生随机数

1
2
3
4
5
6
7
8
9
10
11
% 0和1之间均匀分布的随机数
R = rand(N);
%...

% 随机整数
R = randi(iMax);
%...

% 服从高斯分布的随机数
R = randn(N);
%...

矩阵减去向量

矩阵列拼接用,

1
2
3
4
5
6
x1 = ones(200, 1);
x2 = ones(200, 1);
x3 = ones(200, 1);
x4 = ones(200, 1);
x5 = ones(200, 3);
x = [x1(:, 1), x2(:, 1), x5(:, 2:3)]

矩阵行拼接用;

1
2
3
4
5
6
x1 = ones(1, 200);
x2 = ones(1, 200);
x3 = ones(1, 200);
x4 = ones(1, 200);
x5 = ones(3, 200);
x = [x1(1, :), x2(1, :), x5(2:3, :)]

指数运算

1
2
x = ones(10, 1);
x2 = x.^2;

Matlab进行回归分析

  • 多元线性回归
  • 多项式回归
  • 非线性回归
  • 逐步回归

多元线性回归

regress介绍

使用regress

1
[b, bint, r, rint, stats] = regress(Y, X, alpha)

需要注意的是,X中还需要加上一列ones表示截距,否则会计算出错。
其中
b表示回归系数估计值,
bint表示回归系数的置信区间,
r表示残差,
rint表示残差的置信区间。
stats返回的是统计量,前三个值分别是$R^2 $,F,以及F对应的p

示例

1
2
3
4
5
6
7
8
% 自变量
x=[143 145 146 147 149 150 153 154 155 156 157 158 159 160 162 164];
% 表示截距的ones
X=[ones(16,1) x];
% 因变量
Y=[88 85 88 91 92 93 93 95 96 98 97 96 98 99 100 102]';
% 回归分析
[b,bint,r,rint,stats]=regress(Y,X)

多项式回归

一元多项式

使用polyfit或者polytool

多元二项式

使用rstool或者rsmdemo

非线性回归

使用nlinfit

逐步回归

stepwise

标准差怎么计算

得到了参差平方和之后,可以计算标准差。
$$sd = \sqrt{\frac{R^2}{n-k} }$$
其中$n$是样本说,$k$是参数个数。

参考文献

1.https://www.cnblogs.com/hezhiyao/p/6824083.html
2.http://mcm.dept.ccut.edu.cn/u_newsfiles/1283049677/20120508/20120508204298149814.pdf
2.http://blog.sina.com.cn/s/blog_03f96e310106lktb.html
3.https://bbs.pinggu.org/thread-3065519-1-1.html
5.https://zhidao.baidu.com/question/1819455048729653268.html

C struct vs C++ struct

发表于 2019-10-25 | 更新于 2019-12-18 | 分类于 C/C++
  1. 在C中,struct names也在定义的struct的namespace中,如果定义struct Foo {};类型,如果需要创建这种类型的变量,
    在C中需要使用struct Foo foo;
    而在C++中只需要写 Foo foo; ,当然C那样子也是支持的。
    而对于C语言程序员,可以使用 typedef struct {} Foo; ,然后像C++那样创建变量。
  2. 在C++中,struct和class其实是相同的东西,除了struct的方法默认都是public的,class的方法默认都是`pri而C中,结构体不能拥有method。
  3. C中struct不能有static成员,而C++的struct可以。
  4. C中struct不能有构造函数,而C++的struct可以有构造函数。
  5. C中sizeof struct Foo {};是1,而C++中是0。

参考文献

1.https://www.quora.com/What-is-the-difference-between-C-structure-C+±structure
2.https://www.geeksforgeeks.org/difference-c-structures-c-structures/
3.https://stackoverflow.com/questions/2242696/c-structure-and-c-structure

C/C++ IEEE 754 Floating Point Standard

发表于 2019-10-24 | 更新于 2019-12-17 | 分类于 C/C++

小数转二进制

0.8125转换为二进制小数。

1
2
3
4
5
6
7
8
9
10
11
12
0.8125
x 2
1.6250 取整数部分1
0.6250
x 2
1.25 取整数部分1
0.25
x 2
0.5 取整数部分0
x 2
1.0 取整数部分1
最后得到1101,再加上小数点即0.1101

分数转二进制

将分数转换成小数。
下面的做法只针对于这一个,对于其他的一些并不简单。
$15/32$转换为二进制小数??这个是不是有问题,如果分母是28怎么算???
分开来算,
$15 = (1111)_2 = 2^3 + 2^2 + 2^1 + 2^0 $
$32 = (100000)_2 = 2^5 $
即
$15/32 = 2^{-2} + 2^{-3} + 2^{-4} + 2^{-5} $
而$2^{-2} = 0.01, 2^{-3} = 0.001, 2^{-4} = 0.0001, 2^{-5} = 0.00001 $
所以$15/32 = 0.01111$

浮点数

浮点数使用科学计数法表示实数,一个尾数(Mantissa),一个基数(Base),一个指数(Exponent)以及一个表示正负的符号来表达实数。比如 123.45 用十进制科学计数法可以表达为 1.2345 × 102 ,其中 1.2345 为尾数,10 为基数,2 为指数。浮点数利用指数达到了浮动小数点的效果,从而可以灵活地表达更大范围的实数。
有很多方法表示浮点数,IEEE 754是最有效的方法。在IEEE标准中,浮点数由符号域,指数域,尾数域组成。

  • The Sign of Manitissa(符号域):0代表正数,1代表负数
  • The Biased exponent(有偏指数域):指数域是有一个biased的。
  • The normalised Mantisa(尾数):有效数字
    通过调整尾数和指数就可以表达不同的数值。具体格式如下:
    Double
    Single
类型 符号位 有偏指数域 尾数域 偏置
单精度 第31位 第30-23位 第22-0位 127
双精度 第63位 第62-52位 第52-0位 1023

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
85.125 
先转换为二进制,然后计算符号域,指数域和尾数域。
0.125 = 001
85.125 = 1010101.001
=1.010101001 x 2^6
sign = 0

1. Single precision:
有偏指数:
biased exponent 127+6=133
133 = 10000101
规范化的尾数:
Normalised mantisa = 010101001
we will add 0's to complete the 23 bits

The IEEE 754 Single precision is:
= 0 10000101 01010100100000000000000
This can be written in hexadecimal form 42AA4000

2. Double precision:
biased exponent 1023+6=1029
1029 = 10000000101
Normalised mantisa = 010101001
we will add 0's to complete the 52 bits

The IEEE 754 Double precision is:
= 0 10000000101 0101010010000000000000000000000000000000000000000000
This can be written in hexadecimal form 4055480000000000

参考文献

1.https://www.cnblogs.com/xiabodan/p/4038623.html
2.https://www.geeksforgeeks.org/ieee-standard-754-floating-point-numbers/
3.https://www.cnblogs.com/xkfz007/articles/2590472.html
4.https://www.cnblogs.com/weixuqin/p/7086442.html
5.http://cs.furman.edu/digitaldomain/more/ch6/dec_frac_to_bin.htm

model evaluation and selection

发表于 2019-10-22 | 更新于 2019-12-17 | 分类于 机器学习

经验误差和过拟合

错误率:分类错误的样本数占总样本数的百分比。
精度:1-错误率
误差:样本的真实输出和实际预测输出之间的差异称为误差(error)。
训练误差(training error):在training set上的误差称为training error。
泛化误差(generalizatoin error):在新样本上的误差称为泛化误差。
过拟合:把训练样本的特点当成了所有潜在样本的特点。
欠拟合:没有充分学习样本的通用属性。

模型选择是从不同的学习算法,不同的参数中,选择一个合适的模型。

Model evaluation

通过对模型的泛化误差进行评估,选择处一个好的模型。通过使用testing set测试算法对于新样本的判别能力,以测试集上的testing error当做泛化误差的近似。

留出法(hold-out)

将数据集分为两个互斥的集合,一个用作训练集,一个用作测试集。通常使用$\frac{2}{3}$到$\frac{4}{5}$的样本用于训练,其余样本用于测试。

交叉验证法(cross validation)

将数据集划分为$k$个相同的子互斥子集。每次用$k-1$个子集进行训练,剩下的$1$个子集用于测试。进行$k$次训练和测试,返回这$k$个测试结果的均值。一般情况下最常用的$k$是$10$,称为$10$折交叉验证。

留一法(leave-one-out)

假设$m$是数据集样本的个数,令$k=m$,那么就是交叉验证的一个特例,留一法。它不容易受随机样本划分方式的影响,不论哪种方式,最后都只有一种划分。这种方法获得模型和数据集比较吻合,但是数据集太大时,不可取。

自助法(bootstrapping)

在留出法和交叉验证的中,训练模型使用的数据要比训练集小。
自助法解决了这个问题,他通过自助采样(bootstrap sampling)进行。给定$m$个样本的数据集$D$,对他进行采样得到数据集$D’$:每次随机从$D$中挑选一个样本,将其拷贝到$D’$,重复$m$次,得到了大小为$m$的$D’$,但是$D$中的元素可能在$D’$中重复出现,也可能不出现。
通过计算,大约有$36.8\%$的样本没有出现在$D’$中。用$D’$训练,$D-D’$做测试。
自助法适用于数据集小,难以划分训练集和测试集时很有用。能够产生多个不同的数据集,对集成学习等很有用。

估计标准差

自助法可以用来衡量一个指定的估计量或者统计学习方法中的不稳定因素。比如计算标准差。
自助法估计标准差流程:
用原始数据集重复$B$次产生$B$个数据集,计算出$B$个相应的$\alpha$估计。然后使用自助法据估计标准误差公式:
$$\text{SE}_{B}(\hat{\alpha}) = \sqrt{\frac{1}{B-1}\sum_{r=1}^B(\hat{\alpha} - \frac{1}{B}\sum_{r=1}^B \hat{\alpha})^2 }$$

调参

实际中遇到的数据称为测试数据。
模型评估和选择中用到的评估数据集称为验证集。

性能度量

错误率和精度

错误率:分类正确的样本占样本总数的百分比。
精度:1-错误率。

查准率和查全率

真正例(TP):真的预测成真的
假正例(FP):假的预测成真的
真反例(TN):假的预测成假的
假反例(FN):真的预测成假的
混淆矩阵:

真实情况 预测结果
正例 反例
正例 TP FN
反例 FP TN

查准率(precision):所有预测为正例的样本中真是正例的比例。
$$P = \frac{TP}{TP+FP}$$
查全率(recall):所有预测为正例的样本中真正例占真正例和假负例的和的比例。
$$R = \frac{TP}{TP+FN}$$
查准率和查全率是矛盾的。
混淆矩阵

ROC和AUC

TPR(真正例率),sensitive
$$\frac{TP}{TP+FN}$$
FPR(假正例率),type-1 error,反例中有多少被预测为正例
$$\frac{FP}{TN+FP}$$
TNR(真反例率),specify
$$\frac{TN}{TN+FP}$$
FNR(假反例率),type-2 error
$$\frac{FN}{FN+TP}$$

参考文献

1.西瓜书

1…121314…34
马晓鑫爱马荟荟

马晓鑫爱马荟荟

记录硕士三年自己的积累

337 日志
26 分类
77 标签
RSS
GitHub E-Mail
© 2022 马晓鑫爱马荟荟
由 Hexo 强力驱动 v3.8.0
|
主题 – NexT.Pisces v6.6.0