R语言学习心得
首先,关于R语言,这是一个脚本语言并且十分容易上手,功能强大,非常便于进行数据处理,画图功能也很强同时也兼顾了面向对象编程的优点。
R语言的语法还是比较随意的,没有太过严格的要求,并且很灵活,甚至比js还灵活,变量的命名中是可以带.的,由此可见R语言里也无需了解指针的知识,它有自己的垃圾回收机制,它的赋值也有自己的特色,”<-“就是赋值符号,当然作为如此方便的一个语言,增强for循环也是不可或缺的,和python的语法差不多,也是for in就行了。
学习了一些R语言的数据结构,例如向量,矩阵,数组,列表,数据框,因子和表。下面详细谈谈我对这些数据结构的理解。
向量
首先,向量具有六类数据类型:
- 逻辑型
- 数字
- 字符串
- 整型数字
- 复合型
- 原型(Raw)
我们可以使用c()来将多个元素创建成一个向量,形如:
#create a vector
x <- c(1,2,3,4)
这个x的类型就是numeric,其它类型的向量创建与此是类似的。
关于向量的运算,在R语言里,向量的运算是可以循环补齐的,但是要尤其注意倍数的关系,比如
c(1,0,4)+c(5,3,6,7,9)#can't plus because the second vector is not integer multiple of the first
矩阵和向量相加一样的,当矩阵元素个数是向量元素个数的整数倍,可以相加,并且是按列循环相加。
向量运算中加减乘除,取余,取幂,还有逻辑运算都可以
向量和向量之间的运算得到的还是一个向量,关于向量生成有rep()函数,可以简便的生成一些有很多重复的元素的向量,当然我们可以用for循环实现,不过有函数调用当然还是用函数吧。
rep(2,3)# the result is 2 2 2
rep(1:3,3)# the result is 1 2 3 1 2 3 1 2 3
rep(1:3,each=3)# the result is 1 1 1 2 2 2 3 3 3
显然rep()还是很好用的,R语言里有关一些不太了解的函数可以用?再加上函数名称来查看帮助文档,了解函数中每个参数的意义,并且可以去github里查看R语言的源码,之前我看了一下rnorm()的源码,发现底层是用C语言写的。
这个向量里关于取值的操作
x[1]# take the first element of x
for(i in x)# i is the element of x
x[-1]#delete the first element of x
注意,这里的x[-1]并不是取出最后一个值,和python不一样,这是删除第一个元素。
关于all()和any(),比如all(x>5),若是x每个元素的值都大于5,则返回TRUE,而any(x>5),只要x里有一个元素的值大于5就会返回TRUE,否则返回FALSE。
还有NA和NULL,这是连个不同的概念,NA是not a number,代表缺值,有自己的空间分配,而NULL就是空,不会有空间分配,例如
x <- c(NA,NA,NA)
length(x)
#the result is 3
但是当
x <- c(NULL,NULL,NULL)
length(x)
#the result is 0
最后,向量里的ifelse(),也很简单,和?:这个条件运算符差不多,当满足条件时,执行第一个表达式否则执行第二个
ifelse(x==2,x+2,x+1)#if the element of x equals 2 then the element adds 2,else the element adds 1
列表
和Java里list没什么区别,都是由N个节点构成的,并且这些节点的数据类型是可以不一样的,非常适合存储一些类似于对象属性的内容,创建列表也很简单,如下
#create a list
l <- list(name="jack",salary=30000,union=T)
然后,取出列表的值也很简单,需要用到$符号,或者直接用下标也可以,如下
l$name # jack
l[1] # $name jack
l[[1]] # jack
l[["name"]] # jack
非常清晰明了,列表的取值就是这么一回事,l[1]取出来的是一个节点,l[[1]]取出来的是第一个节点的值,对于第一种取法,返回的类型依然是一个list,第二种返回的就是值的类型了。
关于apply()的运用,使用?apply查看apply的帮助文档,可以知道apply中的参数为apply(X,margin,fun,…),X是一个数组,矩阵,margin就是行或者列, 1代表行,2代表列,c(1,2)代表行和列,如果有名称的话可以直接把名称写进去,fun显然是函数的意思,也就是对这个X的某一margin进行的操作,后面的…就是这个函数需要的参数。
那么lapply(),显然是List的apply,可以对list进行fun的一些操作。如下
lapply(list(1:5,2:8),median)# 3 5
median的意思就是取中位数啦
使用unlist()可以将list变成向量,其它的关于列表的操作都比较逻辑化,意思就是很好懂
数组和矩阵
直接用一个matrix()就可以创建一个矩阵,里面的一些参数有data,nrow,ncol,byrow,dimnames,其中data就是这个矩阵的所有数据,nrow代表有几行,ncol代表有几列,byrow代表是否按行传入数据,dimnames标识的是矩阵行和列的名称,当然啦,是一个长度为2的list给的,如果长度为1的话,那就是行的名称了,没有列表的话就是null,无所谓。
关于矩阵的运算其实和向量运算也没什么太大的差别,语法特性也就是R的那些东西,在开头都有所提及。
which(lambda)可以给出这个满足这个表达式的矩阵元素的位置。
cbind(),对m列的矩阵和n列的矩阵进行合并,成一个m+n列的矩阵,2个矩阵的行数需要一样,如果只给一个数的话,会循环补齐
rbind(),行合并,和列合并没什么差别
x <- 1:16
x <- matrix(x,4)
x <- cbind(1,x)
#the result is follwoing
#x
# 1 1 5 9 13
# 1 2 6 10 14
# 1 3 7 11 15
# 1 4 8 12 16
如上可以看出这个cbind()的效果
当矩阵一行或者一列提取时,是会降维的,如下
x <- matrix(1:8,4)
r <- x[,2]
class(x)# integer
r <- x[,2,drop=FALSE]
class(x)# matrix array
用drop=FALSE是可以防止降维的,返回的依然是一个矩阵。
数据框
dataframe是R语言里的数据处理的利器,如何创建一个dataframe呢,直接用代码来演示:
kids <- c("jack","jill")
ages <- c(12,10)
d <- data.frame(kids,ages,stringsAsFactors=FALSE)
可以看一下d的内容
> d
kids ages
1 jack 12
2 jill 10
不愧为数据框,和数据库的表有些类似,这个里面的stringAsFactors是个逻辑变量,表明是否把字符转换为因子,R4.0.0之后就默认为false了,data.frame()里还有一些其它的参数,直接查看帮助文档就知道是什么了,大概就是定义行的名字啊,检查行啊名字啊之类的。
查询数据框,有很多种方法可以查询,最常用的有几个,一个是用$选择,还有是用下标,当然和列表的下标选择一样,举个例子
d[1]
# kids
# 1 jack
# 2 jill
d[[1]]
#"jack" "jill"
显然,d[1]返回的依旧是数据框,而d[[1]]返回的是单纯的数据。
还有一个是subset(),可以将数据框里的数据按照一定的要求取出,比如
subset(d,d$ages>10)
# kids ages
#1 jack 12
如果只想取一列出来的话,在subset里加一个select就行了,比如
subset(d,d$ages>10,select=1)
# kids
#1 jack
还有一些操作,和对列表的操作其实没什么区别,加一个列啊,对数据框apply的操作啊
合并数据框直接使用merge()就可以了,还有一堆左连接,右连接,全连接,自然连接,直接看帮助文档就完了,当然数据库里也学了这些连接的概念,只保留左边的空值啊,不重复加列啊什么的,比较简单。
对于数据框里的删除呢,很简单,删除第一行就用d[-1,]
因子和表
因子用于存储不同类别的数据类型,R 语言创建因子使用 factor() 函数,向量作为输入参数。
factor(x = character(), levels, labels = levels,
exclude = NA, ordered = is.ordered(x), nmax = NA)
参数:
- x:向量
- levels:指定各水平值,不指定时由x的各个不同值来决定
- labels:指定水平标签,不指定时由水平的字符串标识
- exclude:排除的字符
- ordered:逻辑值,指定水平是否有序
- nmax:水平的上限数量
x <- c("男", "女", "男", "男", "女")
sex <- factor(x)
#> sex
#[1] 男 女 男 男 女
#Levels: 男 女
因子的水平标签
sex=factor(c('f','m','f','f','m'),levels=c('f','m'),labels=c('female','male'),ordered=TRUE)
# > sex
#[1] female male female female male
#Levels: female < male
生成因子水平
我们可以使用 gl()函数来生成因子水平
gl(n, k, length = n*k, labels = seq_len(n), ordered = FALSE)
- n: 设置 level 的个数
- k: 设置每个 level 重复的次数
- length: 设置长度
- labels: 设置 level 的值
- ordered: 设置是否 level 是排列好顺序的,布尔值
v <- gl(3, 4, labels = c(1,2,3))
#> v
# [1] 1 1 1 1 2 2 2 2 3 3 3 3
#Levels: 1 2 3
因子主要的作用就是把数据可以分类,便于我们之后的一些操作,就是因为有这些结构存在,R语言才可以成为一门非常好的数据处理语言。
至此,R语言的一些数据结构都讨论完毕了,这些都是R语言的非常基础的工具,通过这些我们可以把数据转换成我们好处理的形式,与此同时,R中提供非常多的api来对这些数据结构进行处理,可以把数据处理成我们想要的样子。
下面我们来讨论R语言中的环境和变量的作用域
环境和变量的作用域
R语言中的环境和其它的编程语言中的地址差不多,一个函数是一个对象,然后我们可以通过environment()来查看这个对象的环境。
环境空间有一些特征,比如每个环境空间要有唯一的名字;环境空间是引入类型的,非赋值类型;环境空间都有父环境空间,空环境是最顶层的环境空间,没有父空间;子环境空间会继承父环境空间的变量等
R语言的环境是一种有层次关系的结构,每个环境都有上一层环境,直到最顶层的空环境。R语言中有5种环境的定义 全局环境,内部环境,父环境,空环境 和 包环境。
- 当前环境,即用户环境,是用户程序运行的环境空间。
- 内部环境,构造出来的环境,可以是通过 new.env()函数显示创建的环境空间,也可以是匿名的环境空间。
- 父环境,即上一层环境,环境空间的上一层。
- 空环境,即顶层环境,没有父环境空间。
- 包环境,包封装的环境空间。
函数的运行环境是临时的,当函数运行完后这个空间会自动销毁,和别的语言中其实是一样的,函数参数放在一个栈里,每当调用一个函数,就会多加一个栈,当函数运行完后就把这些空间释放掉。
闭包
闭包:内部函数(子函数)总是可以访问其所在的外部函数中定义的变量,即使在外部函数运行结束之后。子函数俘获了外层变量,使得外层变量在函数返回后不会消失。
R语言中,函数的求值过程实为在创建闭包,并在闭包上进行的演算,所以R语言又把函数叫做闭包。
闭包不仅包含了函数的参数、函数体,还包含了调用函数时的函数运行环境(environment)。
R中的面向对象
R中对象的创建的有2个类,S3类和S4类。
S3对象系统是一个简单且宽松的面向对象系统。每个基本对象的类型都有一个S3类名称。比如integer,numeric, character, logical, list和data.frame都属于S3类。
x <- list(name="Joe",salary=55000,union=T)
class(x)<-"employee"
x就是S3类,并且是employee类
k <- list(name="Kate",salary=10000,union=F,hrsthismonth=2)
class(k) <- c("hrlyemployee","employee")
k是hrlyemployee类,并且继承了employee类。
S4类是和java的类没什么差别的类,对于对象的创建都比较严谨。
setClass("employee",representation(name="character",salary="numeric",union="logical"))
j <- new("employee",name="Joe",salary=55000,union=T)
对于employee类里的属性都有约束类型,然后创建对象也是new一个出来的。
读写文件
在R里读写文件,有不少api可以用,比较方便,像read.table(),scan(),readline(),readLines(),都可以将文件读入成一个对象。
写文件的时候呢,write.table(),cat(),writeLines()都可以将数据写入文件里。
然后对于这些函数的参数,直接查看帮助文档就可以非常简单的运用了。
绘图
ok,让我来聊聊我觉得R语言中最秀的一部分内容,ggplot2的绘图,首先,它就像ps里的图层一样,可以一层一层的叠加。
首先要用ggplot2就得用library(“ggplot2”)把ggplot2加载进来。
ggplot(data = NULL, mapping = aes(), ..., environment = parent.frame())
里面的参数意义分别为
- data:要画的数据所在的数据框
- mapping:用于绘图的默认列表。 如果未指定,则必须在添加到绘图的每个图层中提供。
- …:其他参数传递给方法。 目前未使用。
- environment:已弃用。 在进行整洁评估之前使用。
当然,这一些东西python都可以方便的解决,不过,一个非常让人省心的就是R画出置信区间非常容易,添加置信区间的核心函数是:geom_ribbon()
当然,就本人而言,ggplot画出来的图,颜色相较于python来说更让人有好感。
对于R语言的学习心得就到此为止了,鉴于篇幅问题,还有一些更深入的内容没有提及,不过这些都可以去官方网站里去看文档,其实在整个R语言学习的过程中,我发现英语能力其实占据一个非常重要的位置,首先官方文档都是英文,然后在英文网络世界里,R语言的帮助解释都更多并且更有用一些,当然,我也想着以后有时间把一些我在中文网络里搜不到的问题但是在google上能找的搬运进中文网络里,有一些问题其实比较偏僻且遇到的概率较小,但是搜不到解答就真的很麻烦。
下面就开始讲一下我对三个统计知识的理解
三个统计知识
线性回归
线性回归是回归问题中的一种,线性回归假设目标值与特征之间线性相关,即满足一个多元一次方程。通过构建损失函数,来求解损失函数最小时的参数w和b。通长我们可以表达成如下公式:
y ^ = w x + b \hat{y}=\mathcal{w}x+b y^=wx+b
y ^ \hat{y} y^为预测值,自变量x和因变量y是已知的,而我们想实现的是预测新增一个x,其对应的y是多少。因此,为了构建这个函数关系,目标是通过已知数据点,求解线性模型中 w \mathcal{w} w和 b b b两个参数。
回归分析中,只包括一个自变量和一个因变量,且二者的关系可用一条直线近似表示,这种回归分析称为一元线性回归分析。如果回归分析中包括两个或两个以上的自变量,且因变量和自变量之间是线性关系,则称为多元线性回归分析。
最常用的方法是最小二乘法,其中求斜率的公式是
w = ∑ x y − n x ‾ y ‾ ∑ x 2 − n x ‾ 2 w=\frac{\sum xy-n\overline{x}\overline{y}}{\sum x^2-n\overline{x}^2} w=∑x2−nx2∑xy−nxy
截距的公式:
b = y ‾ − w x ‾ b = \overline{y}-w\overline{x} b=y−wx
高斯混合模型
单高斯模型
当样本数据 X 是一维数据(Univariate)时,高斯分布遵从下方概率密度函数(Probability Density Function):
P ( x ∣ θ ) = 1 2 π σ 2 e − ( x − μ ) 2 2 σ 2 P(x|\theta)=\frac{1}{\sqrt{2\pi\sigma^2}}e^{-\frac{(x-\mu)^2}{2\sigma^2}} P(x∣θ)=2πσ21e−2σ2(x−μ)2
其中 μ \mu μ为数据均值(期望), σ \sigma σ为数据标准差(Standard deviation)。
当样本数据 X 是多维数据(Multivariate)时,高斯分布遵从下方概率密度函数:
P ( x ∣ θ ) = 1 ( 2 π ) D 2 ∣ ∑ ∣ 1 2 e x p ( − ( x − μ ) T ∑ − 1 ( x − μ ) 2 ) P(x|\theta)=\frac{1}{(2\pi)^{\frac{D}{2}}|\sum|^{\frac{1}{2}}}exp(-\frac{(x-\mu)^T\sum^{-1}(x-\mu)}{2}) P(x∣θ)=(2π)2D∣∑∣211exp(−2(x−μ)T∑−1(x−μ))
其中, μ \mu μ 为数据均值(期望), ∑ \sum ∑为协方差(Covariance),D 为数据维度。
高斯混合模型
高斯混合模型可以看作是由 K 个单高斯模型组合而成的模型,这 K 个子模型是混合模型的隐变量(Hidden variable)。一般来说,一个混合模型可以使用任何概率分布,这里使用高斯混合模型是因为高斯分布具备很好的数学性质以及良好的计算性能。
- x j x_j xj表示第 j j j个观测数据, j = 1 , 2 , . . . , N j=1,2,…,N j=1,2,...,N
- K K K是混合模型中子高斯模型的数量, k = 1 , 2 , . . . , K k=1,2,…,K k=1,2,...,K
- α k \alpha_k αk 是观测数据属于第 k k k 个子模型的概率, α k ≥ 0 \alpha_k\ge0 αk≥0, ∑ k = 1 K α k = 1 \sum^K_{k=1}\alpha_k=1 ∑k=1Kαk=1
- ϕ ( x ∣ θ k ) \phi(x|\theta_k) ϕ(x∣θk) 是第 k k k个子模型的高斯分布密度函数, θ k = ( μ k , σ k 2 ) \theta_k=(\mu_k,\sigma^2_k) θk=(μk,σk2) 。其展开形式与上面介绍的单高斯模型相同
- γ j k \gamma_{jk} γjk 表示第 j j j个观测数据属于第 k k k个子模型的概率
高斯混合模型的概率分布为:
P ( x ∣ θ ) = ∑ k = 1 K α k ϕ ( x ∣ θ k ) P(x|\theta)=\sum^K_{k=1}\alpha_k\phi(x|\theta_k) P(x∣θ)=k=1∑Kαkϕ(x∣θk)
对于这个模型而言,参数 θ = ( μ k ~ , σ k ~ , α k ~ ) \theta=(\tilde{\mu_k},\tilde{\sigma_k},\tilde{\alpha_k}) θ=(μk~,σk~,αk~),也就是每个子模型的期望、方差(或协方差)、在混合模型中发生的概率。
EM算法
EM 算法是一种迭代算法,1977 年由 Dempster 等人总结提出,用于含有隐变量(Hidden variable)的概率模型参数的最大似然估计。
每次迭代包含两个步骤:
- E-step:求期望 E ( γ j k ∣ X , θ ) E(\gamma_{jk}|X,\theta) E(γjk∣X,θ) for all j = 1 , 2 , . . . , N j = 1,2,…,N j=1,2,...,N
- M-step:求极大,计算新一轮迭代的模型参数
这里不具体介绍一般性的 EM 算法(通过 Jensen 不等式得出似然函数的下界 Lower bound,通过极大化下界做到极大化似然函数),只介绍怎么在高斯混合模型里应用从来推算出模型参数。
通过 EM 迭代更新高斯混合模型参数的方法(我们有样本数据 x 1 , x 2 , . . . , x N x_1,x_2,…,x_N x1,x2,...,xN 和一个有 K K K个子模型的高斯混合模型,想要推算出这个高斯混合模型的最佳参数):
- 首先初始化参数
- E-step:依据当前参数,计算每个数据 j j j来自子模型 k k k的可能性
γ j k = α ϕ ( x j ∣ θ k ) ∑ k = 1 K α k ϕ ( x j ∣ θ k ) , j = 1 , 2 , . . . , N ; k = 1 , 2 , . . . , K \gamma_{jk}=\frac{\alpha\phi(x_j|\theta_k)}{\sum^K_{k=1}\alpha_k\phi(x_j|\theta_k)},j=1,2,…,N;k=1,2,…,K γjk=∑k=1Kαkϕ(xj∣θk)αϕ(xj∣θk),j=1,2,...,N;k=1,2,...,K
- M-step:计算新一轮迭代的模型参数
μ k = ∑ j N ( γ j k x j ) ∑ j N γ j k , k = 1 , 2 , . . . , K \mu_k=\frac{\sum^N_j(\gamma_{jk}x_j)}{\sum^N_j\gamma_{jk}},k=1,2,…,K μk=∑jNγjk∑jN(γjkxj),k=1,2,...,K
∑ k = ∑ j k γ j k ( x j − μ k ) ( x j − μ k ) T ∑ j N γ j k , k = 1 , 2 , . . . , K ( 用这一轮更新后的 μ k ) \sum_k=\frac{\sum^k_j\gamma_{jk}(x_j-\mu_{k})(x_j-\mu_k)^T}{\sum^N_j\gamma_{jk}},k=1,2,…,K\quad(\text{用这一轮更新后的}\mu_k) k∑=∑jNγjk∑jkγjk(xj−μk)(xj−μk)T,k=1,2,...,K(用这一轮更新后的μk)
α k = ∑ j = 1 N γ j k N , k = 1 , 2 , . . . , K \alpha_k=\frac{\sum^N_{j=1}\gamma_{jk}}{N},k=1,2,…,K αk=N∑j=1Nγjk,k=1,2,...,K
- 重复计算 E-step 和 M-step 直至收敛 ∣ ∣ θ i + 1 − θ i ∣ ∣ < ε ||\theta_{i+1}-\theta_i||\lt\varepsilon ∣∣θi+1−θi∣∣<ε, ε \varepsilon ε 是一个很小的正数,表示经过一次迭代之后参数变化非常小)
至此,我们就找到了高斯混合模型的参数。需要注意的是,EM 算法具备收敛性,但并不保证找到全局最大值,有可能找到局部最大值。解决方法是初始化几次不同的参数进行迭代,取结果最好的那次。
今天的文章R语言及三个统计知识学习心得分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/78547.html