R 菜鸟入门篇 第05篇 循环

前两天 dapeng 用 R 给师妹做了一张"全国各省 PM10 浓度地图",以省会城市的 PM10 浓度值给各省涂上颜色,结果师妹说:这个用 ArcGIS 能又快又好地做出来。 dapeng 脑子里立刻涌现出多种说法要细数 R 的优势,第一条就是:若是有 20 年的数据,每年做一张图,R 菜鸟用简单一个循环就能编程搞定,ArcGIS 该怎么又快又好做出来?若不是资深用户的话,我等菜鸟恐怕得一张一张图点出来吧?这种操作费时费力并且毫无乐趣,就应该交给机器来解决,这是懒人的必备技能。本篇就来说说程序的基本结构之一:循环。

开胃小菜 男人至少要擅长一项运动,一种乐器,一种编程….和拿手的几个小炒. (语出小鸟学AHK)

所谓循环,就是兜圈子,就是一件事情重复操作。先从一个简单例子开始。在第 03 篇中,我们对 8 米和 100 米两个高度处测量的 PM2.5 做了日变化图。若要对三个高度的每一个都做日变化图,不用循环,那么是这样的:

pm <- read.csv(file = "c:\\R\\data\\dapengde_DummyR_PM25.csv")
par(mfrow=c(1, 3))
plot(pm[, 1], pm[, 2], cex = 2, type = "l") # 第一张图
plot(pm[, 1], pm[, 3], cex = 2, type = "l") # 第二张图
plot(pm[, 1], pm[, 4], cex = 2, type = "l") # 第三张图

如果使用循环,是这样的:

par(mfrow=c(1,3))
for (i in c(2, 3, 4)) plot(pm[, 1], pm[, i], cex = 2, type = "l") # 让 i 的取值在2, 3, 4这三个数中转一圈,做第 i 张图。

这里出现的 for() 就是循环语句。看起来跟不用循环也差不多嘛。是的。但是有一次 dapeng 要给 20 个观测点 一个月的 PM2.5 每天做一张日变化图来,总共要做 600 张,要是不用循环,那恐怕连死的心都有了。话说 dapeng 当年第一次接触计算机程序的时候,就为循环语句兴奋得睡不着觉,那种久旱逢甘露感觉记忆犹新。懒人福音啊!

i 转的那个圈,可以是数字,也可以是别的,比如字符串:

for (i in c("Good", "Morning", "!")) print(i)
练习05.1 用`print()` 指令打印 1 到 100 之间的奇数。

R 中常用的循环语句,除了 for() 之外,还有while()until(),相互之间可以换用。

下面我们用循环语句来做一个指数增长模型,再体会一下循环的意义。

指数增长模型,也叫马尔萨斯增长模型,一个函数的增长率与其函数值成比例。举个例子吧,我们用 N1 表示 2008 年世界总人口 66.8 亿,r 表示人口自然增长率,为简化起见假定 r 是个常数 0.011,那么在下一年的总人口就是 N2 = N1 + r * N1。我们想看看今后一百年的人口总数,可以这样做:

# 方法 1:每年分别计算,分别存储人口数。
N1 <- 66.8
r <- 0.011
N2 <- N1 + r * N1
N3 <- N2 + r * N2  # 如此一直写到 N100。

# 方法 2:每年分别计算,用一个向量来存储各年人口总数。
N <- numeric(100)
N[1] <- 66.8
N[2] <- N[1] + r * N[1]
N[3] <- N[2] + r * N[2]  # 如此一直写到 N[100]。

# 方法 3: 用循环语句计算,用一个向量来存储各年人口数。
N <- numeric(100)
N[1] <- 66.8
for (t in 1:99) N[t + 1] <- N[t] + r * N[t]  # 不必一直写到N100。
plot(N)

plot of chunk unnamed-chunk-1

循环的好处一览无余!

上面的例子里,每次重复的操作只有一条指令,所以直接写在 for () 后面就可以了。实际遇到的情况往往是重复一组指令,比如 每次给 N[t+1] 赋值时想显示一下当年人口和年份,那么可以用花括号把一组指令组合起来:

for(t in 1:99) 
{
N[t+1] <- N[t] + r * N[t]
print(t + 2007)
print(N[t+1])
}

到目前为止,R 中所有的括号都闪亮登场了一遍,这里小结一下它们的角色:

  • 圆括号 ()。用作命令和数学表达式,如 mean(x), (1 + 2) * 3
  • 方括号 []。用作下标,调用向量中的某个元素,如x[3], pm[2,6]
  • 花括号 {}。用作编程,把一组指令组合在一起,如for () {}
练习05.2 生成一个矩阵 m (方法见 matrix 函数的帮助信息),使得 m[i,j] = x[i] * y[j], 其中 x <- c(2, 3, 5), y <- c(1, 2, 3, 4)。

有用的信息:

循环语句 for(), while(), until()
括号的用法 () [] {}

( 连载中,待续 )

R 菜鸟入门篇 第05篇 循环》上有14条评论

  1. Yang

    只擅长运动和小炒的男淫路过。
    单次分析或者画图对于R来说,速度上是没有优势,拼的就是apm了

    回复
    1. dapeng 文章作者

      是啊,无奈生活经常是一次又一次的循环往复,日出日落,月圆月缺,年尾年头…….

      回复
  2. 卡卡

    男人至少要擅长一项运动,一种乐器,一种编程….和拿手的几个小炒.

    悲催,我一个都不会

    回复
  3. yaoyx001

    最后的小练习挺有意思的,不知道@dapeng还有没有别的练习题了?
    看了 R in Action 的前六章,感觉什么都会一点了,但是一到自己的数据上就麻爪。

    回复
    1. 大鹏 文章作者

      这个R菜鸟入门的重点就是练习,跟着做一遍就能处理自己的数据了。

      回复
  4. star2066

    求教:我的R code如下:
    for (i in c(1:7)) for (j in c(“wind”,”sorlar radiation”,”CO”,”NO”,”NO2″,”O3″,”HC”))plot(hw116[,i],ylab=(j))
    问题是R只显示最后一张HC图,前面6张就不显示了,请问怎么能让R显示前面6张?

    回复
    1. 大鹏 文章作者

      后面的把前面的覆盖了。需要事先设置好页面布局,分成几行几列,用par()或layout()都可以。

      回复
  5. 菜鸟

    大鹏:
    你好,这个怎么写呢?我刚开始学R,谢谢哈!
    生成一个矩阵 m (方法见 matrix 函数的帮助信息),使得 m[i,j] = x[i] * y[j], 其中 x <- c(2, 3, 5), y <- c(1, 2, 3, 4)。

    回复
    1. 大鹏 文章作者

      我也不知道有没有现成的函数。最笨的方法,就是用个for循环吧。

      回复
  6. 小奔

    大鹏,我也用R做过各省GDP地图,但有几个问题想和你探讨一下:
    一,和ArcGIS相比,总感觉R的色调等不是很上档次,
    二,如果要把31省份合并成七大区或东中西三大区,用R的话各区边界就乱套了。
    三,无法在地图上加上柱状图(ArcGIS可以)

    以上三点你有什么好的解决方案吗?

    回复
    1. 大鹏 文章作者

      R和ArcGIS比赛绘制地图的话,就好比铁人三项选手挑战游泳专业选手,R显得业余,毕竟它不是专门干这个的。R的优势在于免费和灵活。一方面,如果R能解决的GIS问题,就不必花钱购买昂贵的ArcGIS了(当然,盗版软件是另外一个话题了,不提);另一方面,R在编程上具有优势,如果结合现成的包来对数据进一步分析,那么是非常让人心动的。R的色调也是一门学问,怎么样好看全靠用户自己琢磨了。至于省份的合并和柱状图,我没有试过,但是这应该算不上高端功能,R应该能胜任的。
      用R处理GIS数据做地图我也很陌生,功夫粗浅得很,只是知道能实现,而且本文是个R入门介绍而已。用R处理GIS数据这种高大上的东西,还是期待你们发烧友多折腾。我已经老了,过了折腾这个的岁数了……

      回复
  7. 过客

    大鹏,第五章开始,练习题我就有做不出的了,列出1-100的奇数这个,我就写不出来,我只能照猫画虎,滑到这一步(如下),该怎么写呢?
    x <- 1:100
    x
    for (i in c(1:100))
    print(i)

    回复

发表评论

电子邮件地址不会被公开。 必填项已用*标注

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax