5.1 抽象化

5.1 抽象化

R是一个好东西的主要原因是它是一门语言.而语言的魅力便是抽象.在R语言中,函数便是实现抽象的方式.假如我们想要把1到3的整数重复两次.这是一个简单的命令:

c(1:3, 1:3)

现在假如想要重复这些数字六次或者六十次.用函数来抽象这个操作就变得有意义了.事实上,这种抽象已经有前人做了:

rep(1:3, 6)

rep()可以完成我们上面的任务和其他一些相似的任务.

我们在做一个新的任务.我们有两个向量;我们想生成一个新的向量,首先将第一个向量重复到第二个向量的长度,然后第二个向量重复到第一个向量的长度.一个向量被重复到的长度如果小于它本身的长度意味着只需要这个向量的前边的那一部分.使用rep()函数可以轻松地将其抽象到一个函数中:

repeat.xy <- function(x, y)
{
 c(rep(x, length=length(y)), rep(y, length=length(x)))
}

repeat.xy()现在就可以在R中被使用了.

repeat.xy(1:4, 6:16)

这种很轻易地写出一个函数好像就意味着我们能够很自然地从仅仅使用R升级到用R编程.

除了可以抽象操作,函数还凝结着智慧.π大约是 3.1415926535897932384626433832795028841971693993751058209749445

923078便是智慧.

函数:

circle.area <- function(r) pi * r ^ 2

智慧与抽象兼而有之–它可以帮你算出任何你想知道的园的面积(约等于).

这里并不是一个纯粹讨论R语言结构的地方,而是一个评论我们上边讲的两个函数细节的地方.repeat.xy()的主体被一对大括号包围着而circle.area()没有.函数的主体应该是一个简单地表达式.大括号将主体内的表达式转换成一个单独的(组合)表达式.当函数的主体只有一条命令的时候,大括号是可选的.大括号也被应用在循环,分支和判断的结构中.

理想的情况是每个函数通过让人容易理解的输入输出完成一个被明确定义的任务.初学者通常都是用一个函数来完成所有的事情.一个普遍来讲总是更好的方法是:写很多的小巧的函数,然后有一个更大的函数调用这些小的函数来完成所有事情.一步步将任务拆分可以让我们清楚地知道什么是真正应该去做的.而且当程序出现bug时可以让我们的调试变得更简单.使用小函数普及程度更高.

R语言抽象的一个瑰宝是函数入参的默认值.比如,sd()中的入参na.rm的默认值是FALSE.如果你的需求正好是FALSE,你在调用sd()的时候便不需要修改na.rm的值.如果你希望丢掉缺失值,你在调用sd()的时候加入参数na.rm=TRUE.假如你编写了自己的函数而仅仅只是改变函数默认入参,那么你可能就不会感激函数提供给你的抽象性了.

函数最总返回一个结果给你,而函数的返回值几乎证明着自己的存在.函数中最后的一条语句被定义为返回值.然而很多函数并没有服从这样的机制,但是return()会强制返回你想返回的.

函数的其他一些影响是它会有一个或者多个负作用.一个负作用便是除了会返回结果外,还会改变代码系统.R的哲学是将这些负作用集中在少数几个我们明确知道的并且希望对系统造成影响的函数中(比如print(),plot(),rm()).

R函数处理的事物是对象.R有丰富的对象类型.表 5.1展示了一些重要的对象类型.

你也许会注意到每个原子类型都有一个可能存在的值–NA(Not Available),这被称作缺失值,一些初次接触R的使用者花费了大量的时间努力去避免NAs.对于0的首次出现,他们或许也会这样做.然而NA是一个对你非常有价值的好东西.当你的数据中存在缺失值的时候你通常是不会高兴的,但是生活有NA总比没有好.

R的设计理想是nothing is important.我们再读一次”nothing” is important.向量的长度可以为0.这是另外一个愚蠢的设计但是被证明是难以置信地有用–这么说来并不是愚蠢的设计啦.我们并不经常去处理一个不存在的事物,所以一些情况下,这是个问题–我们将会在轮回8,轮回8.1.15看到示例.

对象的大多数价值在于处理它们的属性.很多属性改变着R和使用者对它们的认知.通常大多数情况下,对象的一个属性都会有自己的名字.决定着对象的方向的属性是类别.表5.2列举了少许非常重要的由属性决定的对象.

初学者的一个普遍问题是把数据框和矩阵混为一谈.它们看起来好像一样.但是它们确实是不一样的.在轮回8.2.37将会为你展示它们为什么不同.

“vector”在R中有很多含义:

1. 一个原子对象(和列表相反),这或许是最普遍的用法.

2. 一个没有属性的对象(除了可能名称).这是被is.vector()和as.vector()影响的定义.

3. 一个可以有任意长度的对象(包括列表).

很明显第一个定义和第三个定义看起来是矛盾的,它们的到底属于哪一个只有通过代码的上下文才能够清楚.当我们讨论向量跟矩阵的区别时,第二个定义就派上用场了.

单词”list”在R中有一个专业的含义–一个可以包含不同类型,包括自己本身的长度可伸缩的对象.有时这个单词也会被用到非专业的地方,比如在”search list”或者”argument list”.

并不是所有的函数都被平等地被制造出来.它们可以被随意地分为三种类型.

下边是一个无名函数:

apply(x, 2, function(z) mean(z[z > 0]))

这个函数充当了apply()的第三个参数,它是如此短暂以至于我们都没必要给它命名.

这些函数仅仅在一个特定的场合被使用,这些就是你的一次性函数.

然而对于一些对你来说确实珍贵的函数.本来它们就是一次性的而你却重写它们让它们变得更加抽象.诚然,你可能非常希望一个文件或者R包能够引入你的珍贵有用的函数.

从无名函数的例子中我们可以看到,一个函数也可以是另外一个函数的入参.在R中,函数和向量或者矩阵一样都是对象.你可以把函数想象成数据.

一个全新级别的抽象是一个函数的返回值是另外一个函数. 经验分布函数就是一个例子:

> mycumfun <- ecdf(rnorm(10))
> mycumfun(0)
[1] 0.4

只要你写了一个函数返回另一个函数的这种代码,你就可以直接去下一个轮回了.

在第二轮回(12页)我们短暂地分析了do.call().一些人对这个函数甚是迷惑.这是没有必要且不幸的–实际上它是一个非常简单但又非常强大的函数.一般情况下我们都是通过函数的的函数名外和一个”入参列表”来调用这个函数,这样很简单:

sample(x=10, size=5)

do.call()函数允许你以一个真正的列表来提供函数的入参:

do.call("sample", list(x=10, size=5))

有时在调用一个函数时能看到具体的执行情况是非常有用的.函数被调用的时候会建立一个环境,当这个被调用的函数再去调用其他函数时,系统也会为这些其他函数建立自己的环境.因此内存里会有一个环境栈随程序的运行而伸缩.

让我们定义一些函数吧:

ftop <- function(x)
{
# time 1
x1 <- f1(x)
# time 5
ans.top <- f2(x1)
# time 9
ans.top
}

f1 <- function(x)
{
# time 2
ans1 <- f1.1(x)
# time 4
ans1
}

f2 <- function(x)
{
# time 6
ans2 <- f2.1(x)
# time 8
ans2
}

然后我们进行调用:

# time 0
ftop(myx)
# time 10

图 5.1向我们展示了这次调用随着时间栈中的环境怎么变化的.注意在ftop(),f1(),f2()的环境中都有一个x.x在ftop()中被称作myx(或者可能是x的副本),在f1()也是这样.但是f2()中的x就有些不同了.

当我们调试代码的时候,我们将会研究这个栈特定时刻的情况.比如,如果一个代码当一个bug出现在f2.1,我们就要查找在time 7附近的栈的情形.

R语言有丰富的对象类型.这是R优点的一部分.这些对象的一些是语言本身的元素–函数调用,表达式等等.这提供了一种非常强大的抽象形式–在语言上计算.虽然几乎所有的新人对语言的元素混淆看起来是十分的令人费解的,然而很多人对这种观点十分迟钝.

时间: 2024-11-09 06:45:29

5.1 抽象化的相关文章

RDVECore来自锐动的无UI,高度抽象化API的视频编辑SDK--IOS版

1 编写目的 预期读者: 有视频编辑开发经验或者无经验的,打算或者正在使用"锐动IOS版RDVECore"的相关工程师. iOS软件工程师. 产品经理. QA 2 名词解释 分辨率:用于计算机视频处理的图像,以水平和垂直方向上所能显示的像素数来表示分辨率.常见视频分辨率的有1080P即1920x1080,720P即1080x720,640x480等. 帧率:每秒的帧数(fps)或者说帧率表示图形处理器处理场时每秒钟能够更新的次数. 码率: 数据传输时单位时间传送的数据位数,一般我们用的

RDVECore来自锐动的无UI,高度抽象化API的视频编辑SDK

1 编写目的 预期读者: 有视频编辑开发经验或者无经验的,打算或者正在使用"锐动IOS版RDVECore"的相关工程师. iOS软件工程师. 产品经理. QA 2 名词解释 分辨率:用于计算机视频处理的图像,以水平和垂直方向上所能显示的像素数来表示分辨率.常见视频分辨率的有1080P即1920x1080,720P即1080x720,640x480等. 帧率:每秒的帧数(fps)或者说帧率表示图形处理器处理场时每秒钟能够更新的次数. 码率: 数据传输时单位时间传送的数据位数,一般我们用的

整合大量开源库项目(六)ListView动画,Activity&quot;抽象化&quot;,顺便提一提”抽象类“And&quot;接口&quot;

转载请注明出处:王亟亟的大牛之路 昨天发了一个自己写的简单的诸如EditText一个自定义控件,不过貌似反响不太好,这里再推一推,希望大家给予意见和支持:http://blog.csdn.net/ddwhan0123/article/details/50235151 OK,言归正传,上一次添加了一个"个人开发:界面,希望把之后自己写的一些东西都加入里面,作为一个"大型Lib"使用,所以就简单的把内容和界面搭了一下,也大致区分了下栏目,这种展示性的还是以ListView为佳,上

json格式和抽象化思想

一周的学习,这周最大的收获是JS里json格式的运用和抽象化思想,例如: var book=[{id:1,bookname:"软件开发",writer:"Tom",type:"编程技术",time:"1999-2-30",price:50,picture:"a.jpg"}, {id:2,bookname:"HTml",writer:"wersMith",type:&q

DOM:文档对象模型 --树模型 文档:标签文档,对象:文档中每个元素对象,模型:抽象化的东西

DOM:文档对象模型 --树模型文档:标签文档,对象:文档中每个元素对象,模型:抽象化的东西 一:window: 属性(值或者子对象):opener:打开当前窗口的源窗口,如果当前窗口是首次启动浏览器打开的,则opener是null,可以利用这个属性来关闭源窗口. 方法(函数):事件(事先设置好的程序,被触发): 1.window.open("第一部分","第二部分","第三部分","第四部分"): 特征参数: 第一部分:写要

读《向外行一样思考、像专家一样实践》之 简单、省略、抽象化

当你遇到一个复杂问题的时候,你会怎么做呢? 你会使用分析的方法,将这个复杂的问题理解清楚,之后从上到下地“结构性”的构造解决方案.——这是我们被教育的解决问题的方法. 金出武雄是这样说的,“在我们进行研究的时候,如果直接从复杂的现实开始思考,是无法顺利进展的.如果将发生的事情简单.省略.抽象化后再看,就会清晰很多,这是科学与工学的基本要求”....... 省略的思考过程,将问题简化到最合适的程度,这是需要有预见能力的....... 我认为科学和工学都是门艺术.人们经常笼统地看待现实世界的现象和事

ListView抽象化

抽象化,虚拟话 getView(^^^^):在这里判断ViewHolder是否为空,进行初始化Holder,加载View,初始化view ,设置标记,若有复用,直接从标记中拿出来aaa:设置数据 class ViewHolder{ //写listview中item布局里面的元素 } 嵌套checkbox 主要写重写两个方法 数据多的话,需要 listview 分批 修改数据库方法,加入参数(起始位置,和最大位置) select num,mode from blacknumber order by

Android视频编辑SDK--RDVECore来自锐动的无UI,高度抽象化API

RDVECore功能概述 RDVECore是锐动推出的无UI,高度抽象化API的视频编辑SDK,支持以下功能: 1.1 丰富的编辑功能 RDVECore包含了丰富的基础功能,对于编辑中的视频.图片.音乐有各种 处理方式,并且可以根据实际的业务需求,进行搭配组合,所有处理都可以精确 到毫秒级,达到最专业的的要求,主要功能如下: · MV MV根据配置资源进行混合以及动画,增强短视频效果 · 滤镜 RDVEUISdk本身提供丰富的滤镜效果让开发者进行选择,同时用户还可以根据自己的需求进行滤镜扩展.

SICP-2.1-数据的抽象化

本地数据类型 检查数据类型 type(2) <class 'int'>