时隔一天,我又来了。
今日也是函数的内容。

向量化的ifelse()函数

除了多数语言中常见的if-then-else结构,R还有一个向量化的版本:ifelse()函数。它的形式如下:

ifelse(b,u,v)

其中b是一个布尔值向量,而u和v是向量
该函数返回的值也是向量,如果b[i]为,则返回值的第i个元素为u[i],如果b[i]为,则返回值的第i个元素为v[i]。这一概念相当抽象,因此我们看一个例子:

> x<-1:10
> y<- ifelse(x %% 2==0,5,12)  #%% is the mod operator
> y
 [1] 12  5 12  5 12  5 12  5 12  5

在这里,我们希望产生一个向量,这个向量在x中对应元素为偶数的位置取值是5,且在x中对应元素为奇数的位置取值12。因此,对应到形式参数b的实际参数是(F,T,F,T,F,T,F,T,F,T)。对应到u的第二个实际参数5,通过循环补齐成为(55…)(十个5)。第三个参数12,同样循环补齐为(12,12,…)。
这里有另一个例子:

> x<-c(5,2,9,12)
> ifelse(x>6,2*x,3*x)
[1] 15  6 18 24

我们返回的向量由x的元素乘以2或3构成,到底是乘以2还是乘以3,取决于该元素是否大于6。

再次申明,弄明白这里真正发生了什么很重要。
表达式x>6是一个布尔值向量。如果第1个元素为真,则返回值的第1个元素将被设定为2x的第1个元素,否则,它将被设定为3x[i],以此类推。
ifelse()相对干标准的if-then-else结构的优点是,它是向量化语句,因此有可能快很多

  • 扩展案例:度量相关性

评估两个变量的统计关系时,除了标准相关性度量方法(Pearson级差相关系数)之外,还有几种备选方法。一些读者可能听过的Spearman秩相关。这些度量方法有不同的目标,比如针对异常值的稳健性,异常值指的是那些取值很极端的数据,即很有可能出错的数据
在这里,我们提出一种新的度量方法,这不是统计学上的新发现(实际上它与广泛使用的Kendall’s t方法有关),只是为了阐述本节中的一些R编程技术,尤其是ifelse()
考虑向量x和y,它们是时间序列,出如它们是每小时收集的气温和气压测量值。我们定义两者的相关性为x和y同时上升或下降次数占总观测数的比例,即y[i+1]-y[i]与*[i+1]-x[i]符号相同时的次数占总数i的比例。以下是代码:

> #findud() converts vector v to 1s,0s,representing an element
> #increasing or not, relative to the previous one; output length is 1s
> #less than input
> findud<- function(v){
+   vud<-v[-1] -v[-length(v)] 
+   return(ifelse(vud >0,1,-1))
+   }
> udcorr<- function(x,y){
+   ud <- lapply(list(x,y),findud)	
+   return(mean(ud[[1]]==ud[[2]]))
+ }

这里有一个例子:

> x<-c(5,12,13,3,6,0,1,15,16,8,88)
> y<-c(4,2,3,23,6,10,11,12,6,3,2)
> udcorr(x,y)
[1] 0.4

在本例中,x和v在10次中同时上升3次(第一次同时上升是12到13,2到3),并同时下降1次。得到相关性的估计为4/10=0.4

书上后面的解释让人感到痛苦,没看懂就先略过了 p43

  • 扩展案例:对鲍鱼数据集重新编码

由于其参数向量化的特性,ifelse()函数可以嵌套使用。下面的例子是鲍鱼的数据集,性别被编码为MFI(是Infant的缩写,这里意为幼虫)。我们希望将这些字符重新编码为1、2或3。实际的数据集包含超过4000条的观测值,但对于我们的例子,我们假设只有很少的数据存储在g中:

>g
[1] "M""F" "F" "I" "M" "M" "F"
>ifelse(g == "M",1,ifelse(g == "F",2,3))
>[1]1 2 2 3 1 1 2

嵌套的ifelse()实际上做了什么?让我们仔细看一下。首先,为了表述更具体一些,我们找出函数ifelse()中形式参数的名字:

>args(ifelse)
function (test, yes, no) 
NULL

记住,对test中每一个取值为真的元素,函数使用yes中对应的元素作为结果。同样,如果test[i]值为假,则函数计算结果为no[1]。这样生成的所有值组成一个向作为返回值。
在我们的例子中,R首先执行外层的ifelse(),其中的test是gM",yes是1(会被循环补齐);no将是(之后)执行ifelse(gF",23)得到的结果。现在由于test[1]取真,则生成 yes[1],也就是1。因此,外部函数调用所得的返回值第一个元素是1。

下一步,R将计算test[2],该值为假,因此R需要计算no[2]。R现在需要执行内部的 ifelse()调用。之前并没有这样做,因为直到现在才需要它。R使用“惰性求值”(lazy evaluation)的原则,这意味着只有当需要时表达式才被计算,否则不计算。
R现在将计算ifelse(g==“F”,2,3),得到(3,2,3,3,3,2),这是外部ifelse()的参数no,因此后者返回的第二个元素将是(3,2,3,3,3,2)中的第二个元素,即2。
当外层ifelse()函数调用执行到test[4]时,其取值为假,因此将返回no[4]。由于R已经计算过no,它有所需的值,即3。
需要注意,涉及的向量可能是矩阵的列,这是一个非常常见的情况。假设鲍鱼数据存储在矩阵ab中,性别是它的第一列。如果我们想像前例一样对其重新编码的话,可以这样做;

>ab[,1] <- ifelse(ab[,1] =="M",1,ifelse(ab[,1] …… "F",2,3))

假设我们希望按照性别形成子集。可以使用which()来寻找MF和I对应元素的编号。

>m<- which(g=="M")
>f <- which(g == "F")
>i <- which(g =="I")
>m
[1] 1 5 6
>f
[1] 2 37
> i
> [1] 4

更进一步,我们可以把这些子集保存在一个列表中,像如下这样:

>grps <- list()
> for (gen in c("M","F","I")) grps[[gen]] <- which(g==gen)>
>  grps
$M
[1] 1 5 6
$F
[1]23 7
$I
[1] 4

需要注意的是,R的for()循环可以对字符串向量进行循环,我们正是利用了这一事实。
我们可以使用编码后的数据来绘制一些图形,探索鲍鱼数据集中的各种变量。通过给文件添加以下表头来概括变量的性质:
Gender,Length,Diameter,Height,WholeWt,ShuckedWt,VisctWt,Shellwt,Rings
例如,可以分雄雌两组,针对直径和长度作图。使用以下代码:

aba<- readcsv("abalonedata"header=T,as.is=T)
grps <- list()
for (gen in c(“M,"F")) grps[[gen]] <- which(aba==[,1]gen) 
abam<- aba[grps$M,] 
abaf <- aba[grps$F,]
plot(abam$Length,abam$Diameter)
plot(abaf$Length,abaf$Diameter,pch="x",new=FALSE)

首先,我们读取数据集,将其赋值给变量aba为了提示我们这是鲍鱼数据)。read csv()类似于在第1使用过的readtable()。然后构造abam和 abaf,分别是aba下对应雄性和雌性的两个子矩阵。

接下来,我们来作图。第一条作图命令绘制了雄性鲍鱼直径对长度的散点图。第二条命令绘制的是雌性的图。因为希望此图与雄性的叠加在同一张图形上,我们设置参数 new=FALSE,告诉R不要创建一个新的图形。参数 pch="x"意思是我们希望绘制在雌性图形上的字符用x,而不是默认的字符。

if r语言中的else r语言if else函数_if r语言中的else


显然,直径和长度具有很强的相关性,以至于这些点密集地填充了部分图形,雄性和雌性的图形几乎完全一致(尽管雄性具有更多的变化)。这在统计图形中是一个常见的问题。更精细的图形分析会更有启发性,但至少我们看到了强相关的证据,而相关性在性别上的差距并不是很大。

这个地方不好的就在于没有原始数据,不晓得数据是如何呈现在表里面的。

我的脑瓜子确实不太聪明,但是没事,抄书一流