老码农学生信

Learn R 笔记(PART1)

2019-06-15  本文已影响0人  Angeladaddy

chp01_简介

mean(1:5)
?mean
?"+"
# 搜索所有包含 "plotting" 的主题
??plotting
help.search("plotting")
# 搜索所有与 regression model 相关的主题
??"regression model" 
help.search("regression model")
# apropos 函数能找到匹配其输入的变量(以及函数)
a_vector <- c(1:10)
apropos("vector")
apropos("z$")

# example函数查看它们。也有一些较长的概念演示,你可以通过 demo 函数查看
example(plot)
demo(plotmath) 


# 使用 browseVignettes 来浏览所有在你机器上的片段
browseVignettes()
# 可以使用 vignette 函数访问一个特定的片断
vignette("Sweave", package = "utils")
#  RSiteSearch ,它会查询整个 http://search.r-project.org 网站的包
RSiteSearch("{Bayesian regression}")

chp02_科学计算

rm(list = ls())

# 在 R 中,向量化有几种含义,其中最常见的含义是:运算符或函数能作用于向量中的每个元
# 素,而无需显式地编写循环语句(这种内置的基于元素的隐式循环也远远快于显式地写循环
# 语句)。向量化的第二个含义是:当一个函数把一个向量作为输入时,能计算汇总统计

# 运算符号用在向量上,将对每一项进行运算
a <- 1:5+6:10 # 7  9 11 13 15
b <- -2:2 * -2:2 # 4 1 0 1 4
c <- 1:3 / 3 # 0.3333333 0.6666667 1.0000000

# R 还包含了多种数学函数。有三角函数( sin 、 cos 、 tan ,以及相反的 asin 、 acos 和
# atan )、对数和指数( log 和 exp ,以及它们的变种 log1p 和 expm1 ,这两个函数对那些非常
# 小的 x 值能更加精确地计算 log(1 + x) 和 exp(x - 1) 的值),以及几乎所有其他你能想到
# 的数学函数。

# 比较
c(3, 4 - 1, 1 + 1 + 1) == 3 #  TRUE TRUE TRUE

# R 还提供了 all.equal 函数用于检查数字是否相等。它提供了一个容忍度(tolerance level,
# 默认情况下为 1.5e-8 ),因而那些小于此容忍度的舍入误差将被忽略:
# 比较值一样时返回TRUE
sqrt(2)^2==2 #FALSE
all.equal(sqrt(2) ^ 2, 2) #TRUE
# 比较值不一样时返回差值, 如果你需要它们在比较后返回
# 的是一个 TRUE 或 FALSE 值,则应把 all.equal 函数嵌入 isTRUE 函数中调用
isTRUE(all.equal(sqrt(2) ^ 2, 3))

# 我们可以使用 <- 或 = 给(本地)变
# 量赋值,虽然由于历史原因, <- 是首选。
# 还可使用 <<- 来对全局变量赋值
x <<- exp(exp(1))


# R 支持四种特殊值: Inf 、 -Inf 、 NaN 和 NA 。显然,前两个分别是正负
# 无穷,而后两个则需做些解释。 NaN 为“不是一个数”(not-a-number)的缩写,它意味着
# 我们的计算或没有数学意义,或无法正确执行。 NA 是“不可用”(not available)的缩写,
# 并代表缺失值

# TRUE 和 FALSE 是 R 中的保留字:你不能创建以它们命名的变量(但可使用它们的小写或大
# 小写混合,如 True )。当你启动 R 时,变量 T 和 F 已被系统默认定义为 TRUE 和 FALSE 。虽
# 然这能让你少打点字,但也会造成很大的问题。 T 和 F 不是保留字,因此用户可以重新定
# 义它们。这意味着你可以在命令行中使用它们的缩写名称,但如果你的代码需要与他人的
# 代码交互(特别是当他们的代码涉及时间、温度或数学函数时),请避免使用这两个缩写。


# 在 R 中有三个向量化逻辑运算符:
# ! • 代表非操作
# & • 代表与操作
# | • 代表或操作

x <- 1:10 >=5 #  FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRU
!x #  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE
y <- 1:10 %% 2 == 0
x&y # FALSE FALSE FALSE FALSE FALSE  TRUE FALSE  TRUE FALSE  TRUE


# 其他两个比较有用的处理逻辑向量的函数是 any 和 all
any(c(FALSE, FALSE, FALSE))
all(c(FALSE, TRUE, FALSE))

chp03_检查变量和工作区

# R 没有标量类型(scalar type)在 R 中“最小的”数据类型是向量。
#使用class,typeof,mode,storage.mode
a = c(1:10)
class(a) #"integer"
typeof(a)#"integer"
mode(a) # "numeric"
storage.mode(a) # "integer"
#  R 包含三种不同类别的数值变量:浮点值 numeric 、整数 integer 和复数 complex
class(1) # "numeric"
class(1L) # "integer", 整形必须加L
class(3+1i) # complex

# R 不区分整个字符串和单个字符——只包含一个字符的字符串与其他字符串的处理相同
class("1") # "character"

# 因子与其他语言中的枚举类似
gender <- factor(c("male", "female", "female", "male", "female"))
levels(gender) # "female" "male"   默认情况下因子水平按字母顺序分配。
# 在底层,因子的值被存储为整数而非字符
as.integer(gender) # 2 1 1 2 1
as.character(gender) # "male"   "female" "female" "male"   "female"


# 类型检查和转换
# 查看在 base 包中所有的 is 函数
ls(pattern = "^is",baseenv())
# 大部分的 is* 函数都有与之对应的 as* 函数
x <- "123.456"
as(x, "numeric") # 尽量不要用这种写法
as.numeric(x)# 应该使用这种写法
class(x) <- "numeric" # 这种写法也不推荐

# 查看对象信息的方法
# summary,head,str

# unclass函数显示底层信息
info = unclass(gender)
# attributes 函数能显示当前对像的所有属性列表
attributes(gender)
# 一个好方法是结合 View 和 head 函数来查看数据框的前几行
View(head(mtcars, 50)) # 查看前 50 行

chp04_向量、矩阵和数组

rm(list = ls())
# 冒号运算符 : 来创建从某个数到另一个数的数字序列,以及用 c 函数来拼接数值和向量,以创建更长的向量
a = 8.5:4.2 # 8.5 7.5 6.5 5.5 4.5
b = c(1:3,4,5:10) # c函数用来拼接处更长向量
# vector 函数能创建一个指定类型和长度的矢量。其结果中的值可为零、 FALSE 、空字符串,或任何相当于“什么都没有”(nothing)的类型:
c = vector("numeric",5) # 等同于 numeric(5) 
c = vector("complex",5) # 等同于 complex(5)
c = vector("logical",5) # 等同于 logical(5)
c = vector("character",5) # 等同于 character(5)
c = vector("list",5) # 等同于 list(5)


# 生成序列
d = seq.int(3,15,3) # 等同于 3:15,但可以指定步长
#  seq_len 函数将创建一个从 1 到它的输入值的序列
e = seq.int(0)
# seq_along 创建一个从 1 开始、长度为其输入值的序列:
f <- c("Peter", "Piper", "picked", "a", "peck", "of", "pickled", "peppers")
for(i in seq_along(f)) print(f[i])

# 长度
length(1:5)
sn <- c("Sheena", "leads", "Sheila", "needs")
length(sn) # 4
#nchar 计算每个字符串中字符数的长度
nchar(sn)

# 命名
# 创建时命名
g = c(apple = 1, banana = 2, "kiwi fruit" = 3, 4)
# 也可以在向量创建后用 names 函数为元素添加名字:
h = 1:4
names(h) = c("apple", "bananas", "kiwi fruit", "")


# 索引向量(重要)
# 给向量传入正数,它会返回此位置上的向量元素切片。它的第一个位置是 1 (而不像其他某些语言一样是 0) 。
# 给向量传入负数,它会返回一个向量切片,它将包含除了这些位置以外的所有元素。
# 给向量传入一个逻辑向量,它会返回一个向量切片,里面只包含索引为 TRUE 的元素。
# 对于已命名的向量,给向量传入命名的字符向量,将会返回向量中包含这些名字的元素切片。

x = (1:5) ^2
names(x) = c("one","two","three","four","five")
# 以下4种 方式都返回相同值
x[c(1,3,5)]
x[c(-2,-4)]
x[c(TRUE,FALSE,TRUE,FALSE,TRUE)]
x[c("one","three","five")]
x[c(TRUE,FALSE)] # 选取下标单数(true,false循环作用于向量每一项)
# which函数将返回逻辑向量中为TRUE的位置
which(x>5) #   3     4     5, 注意返回的是下标
x[which(x>5)] # 这样才能返回值
# which.min 和 which.max 分别是 which(min(x)) 和 which(max(x)) 的简写:
which.min(x)
which.max(x)


# 向量循环和重复
# 如果我们把一个单独的数字与向量相加,则向量的每个元素都会与该数字相加:
# 将两个向量相加时,R 将会循环较短向量中的元素以配合较长的那个,如果长向量的长度不是短向量长度的倍数,将出现一个警告:
# rep 函数允许我们重复使用元素来创建矢量:

rep(1:5, 3)
## [1] 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
rep(1:5, each = 3)
## [1] 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5
rep(1:5, times = 1:5)
## [1] 1 2 2 3 3 3 4 4 4 4 5 5 5 5 5
rep(1:5, length.out = 7)
## [1] 1 2 3 4 5 1 2


# 矩阵和数组
# 数组能存放多维矩形数据。“矩形”是指每行的长度都相等,且每列和其他长度也是如此。
# 矩阵是二维数组的特例。

# 可以使用 array 函数创建一个数组,为它们传入两个向量(值和维度)作为参数。另外,
# 你也可以为每个维度命名:
# 一个3维数组实例
arr = array(1:24,dim = c(4,3,2),dimnames = list(
  c("one", "two", "three", "four"),
  c("ein", "zwei", "drei"),
  c("un", "deux")
))

# 创建矩阵的语法非常类似,但无需传递维度 dim 参数,只要指定行数或列数即可:
m = matrix(1:12,nrow = 4,dimnames = list(
  c("one", "two", "three", "four"),
  c("ein", "zwei", "drei")
))
# 该矩阵也可以用 array 函数来创建
m = array(1:12,dim = c(4,3),dimnames = list(
  c("one", "two", "three", "four"),
  c("ein", "zwei", "drei") 
))
# 创建矩阵时,传入的值会按列填充矩阵。也可指定参数 byrow = TRUE 来按行填充矩阵:
m = matrix(1:12,nrow = 4,dimnames = list(
  c("one", "two", "three", "four"),
  c("ein", "zwei", "drei")
),byrow = TRUE)


# 行、列和维度
dim(arr) # 4 3 2
nrow(m)
ncol(m)
# length 用于矩阵和数组将返回所有维度的乘积
length(arr) # 4*3*2 = 24
# 把 nrow 、 ncol 和 dim 用于向量时将返回 NULL 值。
# 向量中与 nrow 和 ncol 相对的函数是 NROW 和NCOL 
recaman <- c(0, 1, 3, 6, 2, 7, 13, 20)
nrow(recaman)
## NULL
NROW(recaman)
## [1] 8
ncol(recaman)
## NULL
NCOL(recaman)
## [1] 1
dim(recaman)

# 行名、列名和维度名
rownames(arr)
## [1] "one" "two" "three" "four"
colnames(arr)
## [1] "ein" "zwei" "drei"
dimnames(arr)

# 索引数组
arr[1, c("one", "drei")] # 在第一行、第二列和第三列的两个元素
# 要包括所有维度,则只需置空相应的下标:
a = m[1,]

#合并矩阵
# 通过使用 cbind 和 rbind 函数按行和列来绑定两个矩阵,能更自然地合并它们:
another_matrix <- matrix(
  seq.int(2, 24, 2),
  nrow = 4, 
  dimnames = list(
    c("five", "six", "seven", "eight"),
    c("vier", "funf", "sechs")
  )
)

merge1 = cbind(m,another_matrix)
merge2 = rbind(m,another_matrix)


## 数组、矩阵可以进行运算

## t 函数用于转置矩阵(但不能转置更高维的数组,其中的概念没有被明确定义):
turnedM= t(m)

05. 列表和数据框

rm(list=ls())
# 向量、矩阵和数组所包含的元素的类型都是相同的。列表和数据框是两种特
# 殊的类型,允许我们把不同类型的数据合并到单一变量中。

# 列表其实是一个向量,但其中的每个元素类型可以不同

a_list = list(c(1:10),month.abb,matrix(1:4,nrow = 2),asin)
# [[1]]
# [1]  1  2  3  4  5  6  7  8  9 10
# 
# [[2]]
# [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
# 
# [[3]]
# [,1] [,2]
# [1,]    1    3
# [2,]    2    4
# 
# [[4]]
# function (x)  .Primitive("asin")

# 与向量的命名类似,你可以在构造列表时就给元素命名,或在构造之后使用 names 函数命名
names(a_list) <- c("catalan", "months", "involutary", "arcsin")

the_same_list <- list(
  catalan = c(1, 1, 2, 5, 14, 42),
  months = month.abb,
  involutary = matrix(c(3, -8, 1, -3), nrow = 2),
  arcsin = asin
)


# 原子变量和递归变量
# 由于列表具有这种把其他列表包含在内的能力,它被认为是递归变量。
# 与之相对,向量、矩阵和数组则是原子变量
# 函数 is.recursive 和 is.atomic 可测试它们的类型

is.recursive(list())
is.atomic(list())

# 只能使用NROW和NCOL作用在列表上(与矢量相同)
NROW(a_list) # 4
NCOL(a_list) # 1

# 索引列表
l <- list(
  first = 1,
  second = 2,
  third = list(
    alpha = 3.1,
    beta = 3.2
  )
)
# 以下索引操作[]都将返回另一个列表
l[1]
l[1:2]
l[-3]
l[c("first","second")]
l[c(TRUE,FALSE,TRUE)]
is.list(l[1]) # TRUE
# 我们要访问的是列表元素中的内容,使用[[]]返回索引下标
# [[number]]
# [["colname"]]

l[[1]] 
l[[3]]
l[["first"]]
is.list(l[[1]]) # FALSE

# 使用$ 访问列表元素
l$first
l$third$alpha

# 向量和列表之间的转换
# 向量可使用函数 as.list 函数来转换成列表
v1 <- c(1:10)
l1 <- as.list(v1)

# 如果一个列表各个元素都是标量,可以通过as函数转换为向量
list2 = list(1,3,5,7)
as.numeric(list2)

# 但如果列表中含有非标量元素,要使用unlist函数
list3 = list(a=c(1:10),b=c("aa","bb","bb"),c = rep("x",10))
target = unlist(list3)
# 可以看到列表被“拍平”了
# a1   a2   a3   a4   a5   a6   a7   a8   a9  a10   b1   b2   b3   c1   c2   c3   c4   c5   c6   c7   c8   c9  c10 
# "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9" "10" "aa" "bb" "bb"  "x"  "x"  "x"  "x"  "x"  "x"  "x"  "x"  "x"  "x"
class(target) # [1] "character"


# 列表合并
# 提示:cbind和rbind可以用于合并列表,但最好不要用
# 使用c来拼合列表
c(list(a = 1, b = 2), list(3))


# NULL
# NULL最常被用在列表中
uk_bank_holidays_2013 <- list(
  Jan = "New Year's Day",
  Feb = NULL,
  Mar = "Good Friday",
  Apr = "Easter Monday",
  May = c("Early May Bank Holiday", "Spring Bank Holiday"),
  Jun = NULL,
  Jul = NULL,
  Aug = "Summer Bank Holiday",
  Sep = NULL,
  Oct = NULL,
  Nov = NULL,
  Dec = c("Christmas Day", "Boxing Day")
)

# NULL是空,NA是缺失值
# NULL不占空间,NA占空间
length(NULL) #0
length(NA) #1

is.null(NULL) #TRUE
is.null(NA) # FALSE


# 将NULL赋值给列表中的元素可以删除元素
uk_bank_holidays_2013$Jan=NULL #Jan元素被删除
# 如果想将NULL值赋给列表元素,需要使用list(NULL)
uk_bank_holidays_2013$Mar=list(NULL)





# 数据框
# 1.每个元素具有相同的长度
# 2.可被看作是每列可存储不同数据类型的矩阵,几乎所有用于矩阵的函数亦可用在数据框上。
# 3.或是非嵌套的列表
# 4.每列的类型可与其他列不同,但在同一列中的元素类型必须相同

# 创建数据框,注意,每行的元素长度必须相等
# 如果把letters[1:5]改为[1:6]将会报错
a_data_frame <- data.frame(
  x = letters[1:5],
  y = rnorm(5),
  z = runif(5) > 0.5
)



# 如果输入的任何向量有名称,那么行名称就取自第一个向量名称。
y <- rnorm(5)
names(y) <- month.name[1:5]
data.frame(
  x = letters[1:5],
  y = y,
  z = runif(5) > 0.5
)
## x y z
## January a -0.9373 FALSE
## February b 0.7314 TRUE
## March c -0.3030 TRUE
## April d -1.3307 FALSE
## May e -0.6857 FALSE

# 这种命名规则可通过给 data.frame 函数传入参数 row.names = NULL 覆盖掉:
data.frame(
  x = letters[1:5],
  y = y,
  z = runif(5) > 0.5,
  row.names = NULL
)

# 另外,还可以通过给 row.names 传入一个向量来为每行命名
data.frame(
  x = letters[1:5],
  y = y,
  z = runif(5) > 0.5,
  row.names = c("Jackie", "Tito", "Jermaine", "Marlon", "Michael")
)


# 注意,length用于数据框将返回ncol,names将返回colnames
# 建议你避开这两个函数,而使用 ncol 和 colnames
length(a_data_frame)
#可以使用不同长度的向量来创建数据框,只要长度较短的向量能刚好循环至总长度。从技
# 术上讲,所有向量长度的最小公倍数必须与最长向量的长度相等:
data.frame( # 长度 1、2 和 4 是 OK 的
  x = 1, # 循环 4 次
  y = 2:3, # 循环 2 次
  z = 4:7 # 最长的输入,不需要循环
)
##  x y z
## 1 1 2 4
## 2 1 3 5
## 3 1 2 6
## 4 1 3 7


# 创建数据框时的另一个要点为:在默认情况下,列名必须是唯一且有效的变量名称。此功
# 能可通过给 data.frame 传入 check.names = FALSE 来关闭:
data.frame(
  "A column" = letters[1:5],
  "!@#$%^&*()" = rnorm(5),
  "..." = runif(5) > 0.5,
  check.names = FALSE
)
## A column !@#$%^&*() ...
## 1 a 0.32940 TRUE
## 2 b -1.81969 TRUE
## 3 c 0.22951 FALSE
## 4 d -0.06705 TRUE
## 5 e -1.58005 TRUE


# 索引数据框
# 比如:a_data_frame是一个3行5列的数据框
a_data_frame[1:2,2:3]
# y     z
# 1 -1.04397313 FALSE
# 2  0.01893394 FALSE
a_data_frame[c(FALSE, TRUE, TRUE, FALSE, FALSE), c("x", "y")]
#    如果只选择一个列,其结果将被简化为一个向量 
class(a_data_frame[2:3,3]) # logical

# 选择数据框中的某个子集
# 选择y列>0或者z列为TRUE的行的x列
a_data_frame[a_data_frame$y > 0 | a_data_frame$z, "x"]
# subset函数可以干的更漂亮
# subset(x, subset, select, drop = FALSE, ...)
subset(a_data_frame, y > 0 | z, x)

# t转置
# 数据框可使用 t 函数进行转置。但在此过程中,所有的列(它们即将变成行) 
# 将被转换为相同的类型,然后将变成一个矩阵:
b = t(a_data_frame)
## [,1] [,2] [,3] [,4] [,5]
## x "a" "b" "c" "d" "e"
## y " 0.17581" " 0.06894" " 0.74217" " 0.72816" "-0.28940"
## z "TRUE" "TRUE" "TRUE" "TRUE" "TRUE"
class(b) # matrix

# rbind,cbind,merge
# 数据框使用rbind没有任何问题
# 使用cbind要注意,其不会对列名做重复检查
another_data_frame <- data.frame( # 与 a_data_frame 有相同的 cols ,不过次序不同
  z = rlnorm(5), # 对数分布的数
  y = sample(5), # 1 到 5 随机排列的数
  x = letters[3:7]
)
cbind(a_data_frame, another_data_frame)
## x y z z y x
## 1 a 0.17581 TRUE 0.8714 1 c
## 2 b 0.06894 TRUE 0.2432 3 d
## 3 c 0.74217 TRUE 2.3498 4 e
## 4 d 0.72816 TRUE 2.0263 5 f
## 5 e -0.28940 TRUE 1.7145 2 g

# 当两个数据框有相同的列时,可使用 merge 函数合并
merge(a_data_frame, another_data_frame, by = "x")
## x y.x z.x z.y y.y
## 1 c 0.7422 TRUE 0.8714 1
## 2 d 0.7282 TRUE 0.2432 3
## 3 e -0.2894 TRUE 2.3498 5

# 如果数据框中只包含数值,那么 colSums 和 colMeans 函数可分别用于计算每列的总和和平
# 均值。同样地, rowSums 和 rowMeans 将计算每一行的总和及平均值:

chp6_环境和函数

rm(list = ls())
# 使用 new.env 函数创建环境
my_env = new.env()
# 向环境中指定变量
my_env$aaa = c(1:10)
my_env[["bbb"]] = c(1:10)
# assign函数等价
assign("ccc",c(1:10),my_env)
# assign 的对应函数是 get
get("ccc",my_env)
#ls/ls.str显示环境所有内容
ls(envir = my_env)
ls.str(envir = my_env)
# exists判断变量是否在环境中
exists("f",my_env)
# 使用as.list从环境转为列表
env_list = as.list(my_env)
# 还可以使用list2env转换为环境
env1 = list2env(env_list)
# 使用as.environment从列表转为环境
env2 = as.environment(env_list)
# globalenv获取全局变量
globalv <<- c(3:10)
get("globalv",envir = globalenv())



# 函数
rt(1000,40,40)
# R 的函数不需要return
traingle <- function(x,y){
  sqrt(x^2+y^2)
}
# formals和args函数返回函数参数列表
formals(traingle) # $x   $y
args(traingle) # function (x, y) NULL
# body和deparse查看函数方法体
body(traingle) # sqrt(x^2 + y^2)
deparse(traingle) # "function (x, y) "    "{"                   "    sqrt(x^2 + y^2)" "}" 
# ...匹配
# 假设有以下函数
normalize <- function(x,m = mean(x),s = sd(x)){
  (x-m)/s
}
# 如果传入的参数中有空值
normalize(c(1,3,5,10,NA)) # 将会得到NA结果:[1] NA NA NA NA NA
# ... 解决了这个问题
better_normalize <- function(x,m= mean(x,...),s=sd(x,...),...){
  (x-m)/s
}
better_normalize(c(1,3,5,10,NA)) # 依然输出[1] NA NA NA NA NA
better_normalize(c(1,3,5,10,NA),na.rm=TRUE) # [1] -0.97094667 -0.45310844  0.06472978  1.35932533          NA
# ...其实很精妙,上面例子中,传入的值匹配到最后一个..., 然后这个值会匹配到所有形参的...,
# 而mean和sd本来就有na.rm=TRUE参数,所以翻译过来就是
# better_normalize(c(1,3,5,10,NA),m= mean(x,na.rm=TRUE),s=sd(x,na.rm=TRUE),na.rm=TRUE)

# do.call将函数作为参数传递
# 注意:list里的每一项既是一个参数,其数量要和函数形参数量相等,否则报错
# 由于better_normalizez还有一个参数,所以list只能包含一个数据
do.call(better_normalize,list(c(1:100)))
# 最常见的是do.call与rbind混用
df1 = data.frame(x=1:5,y=rt(5,1))
df2 = data.frame(x=6:10,y=rt(5,1,1))
df3 = data.frame(x=11:15,y=rbeta(5,1,1))
do.call(rbind,list(df1,df2,df3))
# 匿名方式传递函数
do.call(function(x,y)x+y,list(1:10,10:1)) #  [1]  11 11 11 11 11 11 11 11 11 11

Chp7_字符串与因子

#############################################################
##################### 字符串 ################################
#############################################################

# 如何从现有的字符串中构造出一个新的字符串; •
# 如何格式化数字的打印格式; •
# 了解特殊字符,如制表和换行符; •
# 如何创建和操作因子
rm(list = ls())

# 在 R 中,“字符串”是个常用的非正式术语,因为正式的“字符向量元素”读起来相当拗口。
# c()创建字符向量
str = c("aaa","bbb")

# paste 函数能将不同字符串组合在起来。在它传入的参数向量中,每个元素都能自我循环
# 以达到最长的矢量长度,然后字符串就被拼接在一起,中间以空格分开。可以使用参数
# sep 更改分隔符,或使用相关的 paste0 函数去掉分隔符。所有的字符串被组合后,可使用
# collapse 参数把结果收缩成一个包含所有元素的字符串:
paste(c("red","green"),"lorry") # "red lorry"   "green lorry"
paste(c("red","green"),"lorry",sep = "-") # "red-lorry"   "green-lorry"
paste(c("red","green"),"lorry",collapse =  ",") # "red lorry,green lorry"
paste0(c("red","green"),"lorry") # "redlorry"   "greenlorry"

# toString 函数是 paste 的变种,它在打印向量时非常有用。它使用逗号和空格分隔每个元
# 素,且可限制打印的数量。在下例中, width = 40 将输出限制为 40 个字符:
x<-(1:15) ^2
toString(x) # [1] "1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225"
toString(x,width = 30) # [1] "1, 4, 9, 16, 25, 36, 49, 6...."

#noquote 函数去掉这些引号
noquote(str) # aaa bbb

## 格式化数字

# formatC函数使用C风格
formatC(pi,digits = 40,format = "e",flag = "+") # "+3.1415926535897931159979634685441851615906e+00
# C 风格的格式化函数 sprintf 
pow <- 1:3
powers_of_e <- exp(pow)
sprintf("%s %d = %f", "Euler's constant to the power", pow, powers_of_e) # "Euler's constant to the power 1 = 2.718282"  "Euler's constant to the power 2 = 7.389056"  "Euler's constant to the power 3 = 20.085537" 

# 特殊字符
#  \t 制表符
# \n 换行(注意不是\r\n)
alarm()
cat("\a")


# tolower() toupper()

# substring()和substr()截取字符串
# 在大多数情况下,你可以随便选一个使用。不过,如果你传入了不同长度的向量参数,
# 它们的行为会略有不同。对substring 来说,输出的长度与最长的输入一样;
# 而对 substr 来说,输出的长度只与第一个输入的相等:
woodchuck <- c(
  "How much wood would a woodchuck chuck",
  "If a woodchuck could chuck wood?",
  "He would chuck, he would, as much as he could",
  "And chuck as much wood as a woodchuck would",
  "If a woodchuck could chuck wood."
)
substring(woodchuck,1:6,3)
substr(woodchuck,1:6,3)

# strsplit分割字符串
# 一定注意此方法返回的是一个list
#  fixed = TRUE 意味着 split 的参数是固定长度的字符串而非正则表达式:
strsplit(woodchuck," ",fixed = TRUE)
# 正则匹配
strsplit(woodchuck,",? ")

# 文件路径
# file.path()类似c#的path.combine
file.path("c:","program files") # "c:/program files"
# path.expand将相对路径转换为绝对路径
path.expand("~") # "C:/Users/jnmcl/Documents"
path.expand(".")
# basename只返回文件名
basename("C:/Program Files/R/R-devel/bin/x64/RGui.exe")



#############################################################
##################### 因子 ##################################
#############################################################

# 当你用一列文本数据创建数据框时,R 将文本默认为类别数据并进行转换
heights <- data.frame(
  height_cm = c(153, 181, 150, 172, 165, 149, 174, 169, 198, 163),
  gender = c(
    "female", "male", "female", "male", "male",
    "female", "female", "male", "male", "female"
  )
)
class(heights$gender) # "factor"
# levels - 水平
levels(heights$gender) # "female" "male"
# nlevels - 水平的级数:相当于因子 level 的 length 
nlevels(heights$gender) # 2
# 也可以使用 factor 函数创建
genders <- factor(c("female", "male", "female", "male", "male"))
# 通过指定 levels 参数来更改因子被创建时水平的先后顺序
genders <- factor(c("female", "male", "female", "male", "male"),levels=c("male","female"))
# 不能使用 levels 函数直接改变因子的水平值。因为这将重新为每一个水平打
# 上标签,更改数据值,这通常不是我们想要的。
# 直接设置因子的水平值会将数据中的 male 变成 female,female 变成 male
levels(genders) <- c("male", "female")
# relevel 函数是另一种改变因子水平顺序的方法。在这种情况下,你只需指定第一个水平值
relevel(genders, "male")
#  droplevels 函数删除未使用的水平因子
genders <- factor(c("female", "male", "female", "male", "male"),levels=c("male","female","unknown"))
levels(genders)# "male"    "female"  "unknown"
droplevels(genders) # Levels: male female

######有序因子######
happy_choices <- c("depressed", "grumpy", "so-so", "cheery", "ecstatic")
happy_values <- sample(
  happy_choices,
  10000,
  replace = TRUE)
# 此时的5个因子在逻辑上其实是有序的,使用 ordered 函数
# (或通过给 factor传入 order = TRUE 参数)可实现这个功能
happy_ord <- ordered(happy_values, happy_choices)
head(happy_ord) # depressed < grumpy < so-so < cheery < ecstatic : 顺序和因子定义时一致

####将连续变量转换为类别####
# 例子:生成10000个服从beta分布的工人年龄数据
ages = 16+50*rbeta(10000,2,3)
# 按每十年分组
age_groups = cut(ages,seq.int(16,66,10))
head(age_groups)
table(age_groups) #(16,26] (26,36] (36,46] (46,56] (56,66] 
                  # 1789    3475    2945    1524     267


####将类别变量转换为连续变量####

#在清理脏数据时非常有用
#在下例中,其中一个数字有两个小数点
#遇到这样的情况,R会把这一列整体变成字符向量
dirty <- data.frame(
  x = c("1.23", "4..56", "7.89")
)

# 要想把 x 列转换为数字,先把因子转换为字符向量,再转换为数值
as.numeric(as.character(dirty$x)) # 1.23   NA 7.89
# 更好的方法是将因子水平转换为数字,然后再像上面一样重建因子
as.numeric(levels(dirty$x))[as.integer(dirty$x)]
# 如果你经常使用它,就把它包装成一个函数以方便调用:
factor_to_numeric <- function(f)
{
  as.numeric(levels(f))[as.integer(f)]
}


# 为了平衡数据,使到在每个水平上的数据点的数目相等,可用 gl 函数来生成因子。它最
# 简单的形式是:第一个整型参数为要生成的因子的水平数,第二个为每个水平需要重复的
# 次数。通常你想为每个水平命名,这可以通过给 label 参数传入一个字符向量来实现。
gl(3, 2, labels = c("placebo", "drug A", "drug B")) 
#[1] placebo placebo drug A  drug A  drug B  drug B 
#Levels: placebo drug A drug B
# 还可以通过传入 length 参数以创建更复杂的水平排序,例如交替值(alternating value)
gl(3, 1, 6, labels = c("placebo", "drug A", "drug B")) # 交替
## [1] placebo drug A drug B placebo drug A drug B
## Levels: placebo drug A drug B
# 合并因子
treatment <- gl(3, 2, labels = c("placebo", "drug A", "drug B"))
gender <- gl(2, 1, 6, labels = c("female", "male"))
interaction(treatment, gender)
## [1] placebo.female placebo.male drug A.female drug A.male
## [5] drug B.female drug B.male
## 6 Levels: placebo.female drug A.female drug B.female ... drug B.male

chp9_高级循环

rm(list = ls())

#######replacation######
#rep和replicate一样
rep(runif(1), 5)
replicate(5, runif(1))

####xpply家族###########33

# lapply , 作用于list,返回作用后的新list
list = list(one = 1,
            two = c(2, 2, 2),
            three = 1:10)
lapply(list, unique)

# lapply , 作用于list,返回vector,它一定需要第三个参数
# 即返回值的模板
vapply(list, length, numeric(1))

# sapply, 介于lapply和vapply之间,
# 其含义为:简化列表应用,它不需要模板,会尽可能的匹配
# 但正因为如此,其返回值是不可预测的,可能是列表,也可能是向量
sapply(list, length)
sapply(list(), length) # 返回list()

# 遍历文件夹下的所有R脚本并执行
scripts = dir(pattern = "\\.R$")
lapply(scripts, source)

# 以上所有xapply函数都能作用于向量
# 如果xapply的函数部分需要传额外的参数,紧跟逗号后传入即可
# 注意:这只适用于向量参数(下面例子里的1:5)是第一个参数的情况
lapply(1:5, rep.int, times = 3)
# 如果向量参数不是第一个,就需要自定义函数封装
lapply(1:5, function(x) {
  rep.int(4, times = x)
})

#eapply遍历环境列表
env = new.env()
env$ltes = letters
eapply(env, length)

# rapply是lapply的递归版本,但一般使用unlist扁平化列表后操作

######apply###########
# 所有的xapply函数都是将传入的列表或向量(x)打散,按照列来逐一执行的
# 如果想按行执行遍历操作,该怎么做呢?
# 为举例说明,先用matlab包生成一个4×4方阵
if (!require("matlab"))
  install.packages("matlab")
library(matlab)
magic4 = magic(4)
# 可使用rowSums计算行的总数
rowSums(magic4)
# 如何统计每行数据?答案是使用apply函数
# apply(a,b,c)
# a: 一般是一个matrix,也可以是数据框,但比较少见,因为数据框各列数据类型可以不同
# b: 应用于:1:应用于每一行2:每列,更大的数字表示更高的维度
# c:函数
apply(magic4, 2, summary)

#当对数据框按照列应用apply函数,其作用与sapply一样
# 因为sapply会自动决定返回类型,这种情况下它会返回数据框(数据框是非嵌套的列表)
sapply(magic4, summary)

a <- data.frame(1:14)
b <- data.frame(15:30)
mapply(summary, a, b)


# split-apply-combine
scores =  data.frame(player = rep(c("tom", "dick", "karry"), times = c(2, 5, 3)),
                     score = round(rlnorm(10, 8),-1))

# split 将数据框拆分成3个元素的列表
# split(x, f, drop = FALSE, ...)
# x:vector or dataframe
# f: x中的因子,上例中,player是因子
# drop: if levels that do not occur should be dropped (if f is a factor or a list).
scoreByPlayer = with(scores,
                     split(score, player))

# apply
scoreMean = lapply(scoreByPlayer, mean)

# combine
# 最后一步是把结果合并到单个向量中
result = unlist(scoreMean)
# dick    karry      tom
# 4124.000 4126.667 2110.000

######tapply#######
###一次性执行上述三个步骤
result = with(scores,
              tapply(score,  player, mean))




################ plyr package ############################
# plyr是一系列名为**ply的函数,其中的星号分别代表输入和输出的形式
# 如:llply,list-list; 相同于lapply
library(plyr)
llply(scoreByPlayer, mean)
# laply : list-vector(注意不是lapply)
laply(scoreByPlayer, mean)
#r开头的raply: 可以取代replicate
raply(5, runif(1)) # 0.90486329 0.07345407 0.04568905 0.54464207 0.75477330
# rlply返回列表
rlply(5, runif(1))
# rdply返回数据框
df = rdply(5, runif(1))
# ddply: 最常用,数据框-数据框,可以替换tapply
# 下面是第一种用法:使用colwise,表示除了.()里面的列以外,对其余列都使用mean方法
# ddply将对数据框自动分组
dfx <- data.frame(
  group = c(rep('A', 8), rep('B', 15), rep('C', 6)),
  sex = sample(c("M", "F"), size = 29, replace = TRUE),
  age = runif(n = 29, min = 18, max = 54)
)
d1 = ddply(dfx, .(group,sex), colwise(mean))
# group sex      age
# 1     A   F 36.31042
# 2     A   M 34.24761
# 3     B   F 32.15730
# 4     B   M 35.86387
# 5     C   F 40.98684
# 6     C   M 24.91566

#第二种是使用summarize,这时必须手动指定每一列 
d2 = ddply(dfx,.(group),summarize,age_mean = mean(age))
# group age_mean
# 1     A 35.27902
# 2     B 33.88703
# 3     C 35.62978
上一篇下一篇

猜你喜欢

热点阅读