可视化:RStudio 编程

221 阅读7分钟

本文已参加「新人创作礼」活动,一起开启掘金创作之路。

这次带来的是 RStudio 的编程基础。

各个知识点后面都有对应的小练习哦,大家可以利用刚刚学到的知识来试着写写看!


到目前为止, 我们所用到的R代码基本只能算是一条条命令的集合, 只能用于解决一些相对简单的问题, 当面对更复杂的情况时, 常常会显得力不从心.

从今天开始, 我们将会涉及R编程的核心. 通过对控制流与函数的学习, 我们将有能力利用计算机去解决一些比较复杂的问题, 这种实践能力需要足够时长的训练才能掌握, 这使它成为了高薪工作的门槛之一.

市面上的大部分R语言书籍都以统计/数据分析/机器学习为主, 并没有涉及或很少涉及R作为一门编程语言的内容, 如果你想更加深入的学习这部分, 可以参考这本书: The Art of R Programming (R语言编程艺术)


Conditionals 条件判断结构

本节开始,我们将学习对象之间的关系运算, 和 条件判断结构.

  • 关系运算
  • 相等
  • 关于浮点数之间的比较
  • 逻辑运算
  • 条件语句
  • 条件语句(2)
  • 练习:3n+1
# Relational Operators 关系运算
# Greater and less than 大于小于
1 < 2
pi > 3
exp(1) > pi
-1 <= 0
-1 >= -2

# - Equality 相等
3 == (2+1)
"intermediate" != "r"
TRUE != FALSE
"Rchitect" != "rchitect"

# 关于浮点数之间的比较
1.1 * 2 == 2.2
2 * 1.1 == 2.2
2/7 * 1.1 == 2.2/7

2/7 * 1.1 - 2.2/7
1.1 * 2/7 - 2.2/7
all.equal(2/7 *1.1 , 2.2/7)
abs(2/7 * 1.1 - 2.2/7)
abs(1.1 * 2/7 - 2.2/7)
abs(2/7 * 1.1 - 2.2/7) < 1e-10

# Logical Operators
TRUE > FALSE
as.numeric(TRUE)
as.numeric(FALSE)

TRUE & TRUE
TRUE & FALSE
FALSE & FALSE
TRUE | TRUE
TRUE | FALSE
FALSE | FALSE

!TRUE
!FALSE

# Conditional Statements 条件语句
# if...else...
if(condition){
  do sth ...
}

if(condition){
  do sth ...
}else{
  do sth else...
}

if(condition 1){
  do sth ...
}else if(condition 2){
  do sth else...
}else{
  do sth else...
}

x = 4
if(x > 0){
  print('x is positive')
}

if(x > 0){
  print('x is positive')
}else{
  print('x is NOT positive')
}

if(x > 0){
  print('x is positive')
}else if(x == 0){
  print('x is zero')
}else{
  print('x is negative')
}


# ifelse
ifelse(condition, yes, no)

ifelse(1:5 > 2, 'large', 'small')

# coding exercise
# 3n+1 problem
# 其正式名称是 Collatz Conjecture, 其内容是:
# 对于一个正整数n, 如果为偶数, 就变为n/2; 如果是奇数, 就变为3n+1
# 对于任意的正整数n, 都会变成1

# 写一段code, 对于我们任意指定的n, 完成一次'3n+1变换'

延伸阅读: Collatz conjecture

# Collatz conjecture
# From Wikipedia, the free encyclopedia
# (https://en.wikipedia.org/wiki/Collatz_conjecture)
# 
# The Collatz conjecture is a conjecture in mathematics that concerns a sequence defined as follows: start with any positive integer n. Then each term is obtained from the previous term as follows: if the previous term is even, the next term is one half of the previous term. If the previous term is odd, the next term is 3 times the previous term plus 1. The conjecture is that no matter what value of n, the sequence will always reach 1.
# 
# The conjecture is named after Lothar Collatz, who introduced the idea in 1937, two years after receiving his doctorate.

Loops 循环

循环结构可以让我们高效的处理大量重复性的工作. 本节我们将学习三种类型的循环结构.

  • For loop
  • 基于vector/list/matrix/array的For loop
  • While loop
  • break: 跳出循环
  • next: 跳过本次迭代中的剩余部分
  • Repeat loop
  • 练习
# for loop
for(var in seq) {
  expr
}

for(i in 1:5){
  print(i)
}
for(i in 1:5){
  cat(i)
}
L1 = list(1:3,1:4,5:9)
for(x in L1){
  print(x)
}
for(i in 1:5){
  for(j in 1:3){
    cat("( row:", i, " column:", j, ")")
  }
  cat("\n")
}

mat = matrix(1:18, nrow=3); mat
for(i in 1:3){
  for(j in 1:6){
    print(mat[i,j])
  }
}

# while loop
while(cond) {
  expr
}

# repeat loop
repeat{
  expr
}

# break
# 用于跳出循环

# next
# 用于跳过循环的本次迭代中的剩余部分, 直接进入循环的下一次迭代

# repeat loop 本身没有终止功能, 必须配合 break 使用.
# for loop 和 while loop 本身具有终止条件, 但也可以配合 break 使用.

# example
# 打印出向量x中每一个元素的平方
x = 11:15

for(i in x){
  print(i^2)
}

i = 1
while(i <= length(x)){
  print(x[i]^2)
  i = i + 1
}

i = 1
repeat{
  print(x[i]^2)
  i = i + 1
  if(i > length(x)) break
}

# example
# 创建一个5*5矩阵, 其i行j列的元素是i+j+ij
mat = matrix(0, nrow=5, ncol=5)
for(i in 1:5){
  for(j in 1:5){
    mat[i,j] = i + j + i*j
  }
}
mat

mat = matrix(0, nrow=5, ncol=5)
i = 1
j = 1
while(i <= 5){
  while(j <= 5){
    mat[i,j] = i + j + i*j
    j = j + 1
  }
  j = 1
  i = i + 1
}
mat

mat = matrix(0, nrow=5, ncol=5)
i = 1
j = 1
repeat{
  repeat{
    mat[i,j] = i + j + i*j
    j = j + 1
    if(j > 5) break
  }
  j = 1
  i = i + 1
  if(i > 5) break
}
mat


# coding exercise (用三种loop分别完成)

# 对于一个给定的正整数n, 其Collatz Sequence指的是:
# 其经过反复3n+1变换, 直到变为1, 的序列
# 比如5的Collatz Sequence 是: 5,16,8,4,2,1

# Q1:
# 写一段code, 对给定的正整数n, 打印出这个Collatz Sequence

# Q2:
# 写一段code, 对给定的正整数n, 不打印, 而是将其Collatz Sequence保存到一个向量中

# Q3:
# 阶乘是一种常用操作, R提供了函数factorial来计算阶乘. 
# 写一段code, 完成对指定非负整数计算阶乘 (不允许调用factorial)

习题

# Q1:
# 对于不超过10000的所有正整数, 不打印, 记录每个数的Collatz Sequence.
# hint: 思考用何种数据结构来记录

# Q2:
# 接上题, 不超过10000的所有正整数中, 哪个数具有最长的Collatz Sequence, 长度是多少? 并打印出这个序列

Introduction to Functions 函数

循环和条件判断可以帮助我们处理很多重复性的操作, 降低我们的工作量, 提高效率. 函数的引入将进一步提升这种工作效率. 同时, 通过将一些功能包装成函数, 代码的可读性和正确性也能得到极大的提高. 因此,在几乎所有编程语言中, 函数都是极端重要的. 在本节中, 我们将学习如何调用函数, 如何编写自定义函数.

  • 函数的介绍
  • 函数的文档
  • 调用函数
  • 函数内部的函数
  • 函数的参数(Arguments)
  • 编写自定义函数
  • 关于返回值和return
  • 复杂的返回值
  • 练习
# Introduction to Functions 函数的介绍
# 函数是一段经过包装的代码块, 通过输入允许的参数, 函数会执行内部代码并返回代码运行后的结果.

# Function documentation 函数的文档
read.table

help(read.table)
?read.table

# Arguments of function 函数的参数
args(read.table)

# Use a function 调用函数
read.table("./data/R0_09_student01.csv", header=T, sep=",")
sum(1:100)
sum(c(1:100,NA))
sum(c(1:100,NA), na.rm=T)

# Functions inside functions 函数内部的函数
# 在一个函数内部, 可以调用其它的函数, 这使得代码结构变得更清晰更易读
# 利用函数, 我们才能编写具有复杂功能的代码

# Writing Functions 编写自定义函数
function(arglist){
  expr
  return(value)
}

# example
# 编写函数: 返回一个整数向量中奇数的个数
f1 = function(x){
  n = 0
  for(k in x){
    if(k %% 2 == 1){
      n = n + 1
    }
  }
  return(n)
}
f1(1:10)

# 关于函数名和参数名: 尽量使用有意义的名字
count_odd_elements = function(x){
  n = 0
  for(k in x){
    if(k %% 2 == 1){
      n = n + 1
    }
  }
  return(n)
}

# 参数的默认值
# 有些参数具有预先设定的默认值, 因此这些参数在调用函数时可以不指定值, 属于可选参数
# 有些参数没有预先设定的默认值, 因此这些参数在调用函数时必须输入参数值.

# 关于返回值和return
# R函数支持 "不显式"调用return(), 此时R函数中最后一句"有输出"的代码的值将作为返回值
count_odd_elements = function(x){
  n = 0
  for(k in x){
    if(k %% 2 == 1){
      n = n + 1
    }
  }
  n
}
# 同时, 避免显式调用return()会使得代码执行时间略微缩短
# 但我个人一般更倾向于显式的调用return, 为了代码更易读


# 当你需要多个返回值时?
# 返回复杂对象
# 函数的返回值只能有一个, 准确的说, 只能有一个R对象, 
# 因此如果你需要多个返回值, 那么只要将它们包装成一个对象就可以了

basic_statistics = function(x){
  stat = list(min = min(x, na.rm=T),
              max = max(x, na.rm=T),
              mean = mean(x, na.rm=T),
              median = median(x, na.rm=T)
              )
  return(stat)
}
basic_statistics(c(1,2,7,10,13))


# coding exercise

# Q1:
# 创建一个函数, 对给定的正整数n, 返回这个数的Collatz Sequence

# Q2:
# 创建一个函数, 对给定的正整数n, 返回这个数的Collatz Sequence 和 Sequence的长度

# Q3:
# 阶乘是一种常用操作, R提供了函数factorial来计算阶乘. 
# 创建一个函数, 对给定的非负整数n, 返回其阶乘 (不允许调用factorial)

习题

# Q1:
# prime number (素数/质数) 指的是除了1和自身, 没有其它因数的正整数.
# 创建一个函数, 给定n, 判断n是否是素数, 返回TRUE or FALSE. 并检验这个函数的正确性

# Q2:
# 创建一个函数, 给定n, 返回不超过n的所有素数. 并检验这个函数的正确性