《R语言实战》第5章

Posted starjuly

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《R语言实战》第5章相关的知识,希望对你有一定的参考价值。

# 第五章 高级数据管理
# 5.2 数值和字符处理函数
# 5.2.1 数学函数
#   函数                                 描述
# abs(x)                          绝对值 abs(-4返回值为4)
# sqrt(x)                         平方根sqrt(25)返回值为5 和25^(0.5)同介
# ceiling(x)                      不小于x的最小整数 ceiling(3.457)返回值为4
# floor(x)                        不大于x的最大整数 floor(3.475)返回值为3
# trunc(x)                        向 0 的方向截取的x中的整数部分 trunc(5.99)返回值为5
# round(x, digits = n)            将x舍入为指定位的小数 round(3.475, digits=2)返回值为3.48
# signif(x, digits = n)           将x舍入为指定的有效数字位数 signif(3.475, digits=2)返回值为3.5
# cos(x)、sin(x)、tan(x)          余弦、正弦和正切  cos(2)返回值为–0.416
# acos(x)、asin(x)、tan(x)        反余弦、反正弦和反正切   acos(-0.416)返回值为2
# cosh(x)、sinh(x)、tanh(x)       双曲余弦、双曲正弦和双曲正切   sinh(2)返回值为3.627
# acosh(x)、asinh(x)、atanh(x)    反双曲余弦、反双曲正弦和反双曲正切 asinh(3.627)返回值为2
# log(x, base = n)                对x取以n为底的对数     
# log(x)                          为了方便起见 log(x)为自然对数  
# log10(x)                        log10(x)为常用对数 log(10)返回值为2.3026 log10(10)返回值为1 
# exp(x)                          数函数 exp(2.3026)返回值为10


# 5.2.2 统计函数
# mean提供了截尾平均数,即丢弃了最大5%和最小5%的数据和所有缺失值后的算术平均数
# z <- mean(x, trim = 0.05, na.rm = TRUE)
#       函数                              描述
# mean(x)                         平均数  mean(c(1,2,3,4))返回值为2.5
# median(x)                       中位数  median(c(1,2,3,4))返回值为2.5
# sd(x)                           标准差  sd(c(1,2,3,4))返回值为1.29
# var(x)                          方差  var(c(1,2,3,4))返回值为1.67
# mad(x)                          绝对中位差(median absolute deviation)   mad(c(1,2,3,4))返回值为1.48
# quantile(x, probs)              求分位数。其中x为待求分位数的数值型向量,probs为一个由[0,1]之间的概率值组成的数值向量 # 求x的30%和84%分位点 y <- quantile(x, c(.3,.84))  
# range(x)                        求值域  x<- c(1, 2, 3, 4) range(x)返回值为c(1, 4)  diff(range(x))返回值为3
# sum(x)                          求和    sum(c(1, 2, 3, 4)) 返回值为10
# diff(x, lag = n)                滞后差分,lag用以指定滞后几项。默认的lag值为1   x<- c(1, 5, 23, 29)  diff(x)返回值为c(4, 18, 6)
# min(x)                          求最小值  min(c(1,2,3,4))返回值为1 max(x) 
# max(x)                          求最大值    max(c(1, 2, 3, 4))返回值为4
# scale(x, center = TRUE,         为数据对象x按列进行中心化(center=TRUE)或标准化(center=TRUE,scale=TRUE);
#      scale = TRUE)                 

# 代码清单5-1 均值和标准差的计算
x <- c(1, 2, 3, 4, 5, 5, 7, 8)
# 简洁的方式
mean(x)
sd(x)
# 冗长的方式
# (1) x等于c(1, 2, 3, 4, 5, 6, 7, 8),x的平均值等于4.5(length(x)返回了x中元素 的数量);
n <- length(x)
meanx <- sum(x) / n
# (2) (x – meanx)从x的每个元素中减去了4.5,结果为c(-3.5, -2.5, -1.5, -0.5, 0.5, 1.5, 2.5, 3.5);
# (3) (x – meanx)^2将(x - meanx)的每个元素求平方,结果为c(12.25, 6.25, 2.25, 0.25, 0.25, 2.25, 6.25, 12.25);
# (4) sum((x - meanx)^2)对(x - meanx)^2)的所有元素求和,结果为42。
css <- sum((x - meanx) ^ 2)
sdx <- sqrt(css / (n - 1))
meanx
sdx

# 数据的标准化
# 默认情况下,函数scale()对矩阵或数据框的指定列进行均值为0、标准差为1的标准化:
# newdata <- scale(mydata)
# 要对每一列进行任意均值和标准差的标准化,可以使用如下的代码:
# newdata <- scale(mydata) * SD + M
# 其中的M是想要的均值,SD为想要的标准差。在非数值型的列上使用scale()函数将会报错。要 对指定列而不是整个矩阵或数据框进行标准化,你可以使用这样的代码:
# newdata <- transform(mydata, myvar = scale(myvar) * 10 + 50)


# 5.2.3 概率函数
# 在R中,概率函数形如(其中distribution_abbreviation()指分布名称的缩写。——译者注):
# [dpqr]distribution_abbreviation()
# 其中第一个字母表示其所指分布的某一方面:
# d = 密度函数(density)
# p = 分布函数(distribution function) 
# q = 分位数函数(quantile function)
# r = 生成随机数(随机偏差)

# 概率分布
#  分布名称           缩写         |       分布名称           缩写
# Beta分布            beta                Logistic分布        logis
# 二项分布            binom               多项分布            multinom
# 柯西分布          cauchy                负二项分布          nbinom
#(非中心)卡方分布  chisq                正态分布            norm
# 指数分布             exp                泊松分布            pois
# F分布                 f                 Wilcoxon符号秩分布  signrank
# Gamma分布           gamma               分布                t
# 几何分布             geom               均匀分布            unif
# 超几何分布          hyper W              eibull分布        weibull
# 对数正态分布          lnorm             Wilcoxon秩和分布    wilcox 

# 密度函数(dnorm)、分 布函数(pnorm)、分位数函数(qnorm)和随机数生成函数(rnorm)的使用示例如下
x <- pretty(c(-3, 3), 30)
y <- dnorm(x)
# 在区间[3, 3]上绘制标准正态曲线
plot(x, y,
     type = "l",
     xlab = "Normal Deviate",
     ylab = "Density",
     yaxs = "i")
# 位于 z=1.96 左侧的标准正态曲线下方面积是多少?
# pnorm(1.96)等于0.975
# 均值为500,标准差为100的正态分布的0.9分位点值为多少? qnorm(.9, mean=500, sd=100)等于628.16 
# 生成50个均值为50,标准差为10的正态随机数 rnorm(50, mean=50, sd=10)

# 1. 设定随机数种子
# 在每次生成伪随机数的时候,函数都会使用一个不同的种子,因此也会产生不同的结果。你 可以通过函数set.seed()显式指定这个种子,让结果可以重现(reproducible)。
# 以下两个值会不一样
runif(5)
runif(5)
# 通过设定种子,以下两个执行的结果会一样
set.seed(1234)
runif(5)
set.seed(1234)
runif(5)

# 2. 生成多元正态数据
# 在模拟研究和蒙特卡洛方法中,你经常需要获取来自给定均值向量和协方差阵的多元正态分布的数据。MASS包中的mvrnorm()函数可以让这个问题变得很容易。其调用格式为:
# mvrnorm(n, mean, sigma)
# 其中n是你想要的样本大小,mean为均值向量,而sigma是方差-协方差矩阵(或相关矩阵)。

# 代码清单5-3 生成服从多元正态分布的数据
library(MASS)
options(digits = 3)
# 设定随机种子
set.seed(1234)
# 指定均值向量、协方差阵
mean <- c(230.7, 146, 3.6)
sigma <- matrix(c(15360.8, 6721.2, -47.1,
                  6721.2, 4700.9, -16.5,
                  -47.1, -16.5, 0.3), nrow = 3, ncol = 3)
# 生成数据
mydata <- mvrnorm(500, mean, sigma)
mydata <- as.data.frame(mydata)
names(mydata) <- c("y", "x1", "x2")
# 查看结果
dim(mydata)
head(mydata, n = 10)
# 代码清单5-3中设定了一个随机数种子,这样就可以在之后重现结果 。你指定了想要的均
# 值向量和方差—协方差阵 ,并生成了500个伪随机观测 。为了方便,结果从矩阵转换为数据框,
# 并为变量指定了名称。最后,你确认了拥有500个观测和3个变量,并输出了前10个观测 。请注
# 意,由于相关矩阵同时也是协方差阵,所以其实可以直接指定相关关系的结构。



# 5.2.4 字符处理函数
# nchar(x):      计算x中的字符数量x <- c("ab", "cde","fghij")length(x)返回值为 3 nchar(x[3])返回值为5 
# substr(x, start, stop):     提取或替换一个字符向量中的子串x <- "abcdef"substr(x, 2, 4)返回值为"bcd" substr(x, 2, 4) <- "22222"(x将变成"a222ef")
# grep(pattern, x, ignore. case=FALSE, fixed=FALSE):         在x中搜索某种模式。若fixed=FALSE,则pattern为一个正则表达式。若fixed=TRUE,则pattern为一个文本字符串。返回值为匹配的下标 grep("A",c("b","A","c"),fixed=TRUE)返回值为2 
# sub(pattern, replacement, x, ignore.case=FALSE, fixed=FALSE) :  在x中搜索pattern,并以文本replacement将其替换。若fixed=FALSE,则pattern为一个正则表达式。若fixed=TRUE,则pattern为一个文本字符串sub("\\\\s",".","Hello There")返回值为Hello.There。注意,"\\s"是一个用来查找空白的正则表达式;使用"\\\\s"而不用"\\"的原因是,后者是R中的转义字符
# strsplit(x, split, fixed=FALSE):   在split处分割字符向量x中的元素。若fixed=FALSE,则pattern为一个正则表达式。若fixed=TRUE,则pattern为一个文本字符串y <- strsplit("abc", "")将返回一个含有1个成分、3个元素的列表,包含的内容为"a" "b" "c"unlist(y)[2]和sapply(y, "[", 2)均会返回"b"
# paste(…, sep=""):  连接字符串,分隔符为sep   paste("x", 1:3,sep="")返回值为c("x1", "x2", "x3")paste("x",1:3,sep="M")返回值为c("xM1","xM2" "xM3")paste("Today is", date())返回值为Today is Thu Jun25 14:17:32 2011(我修改了日期以让它看起来更接近当前的时间)
# toupper(x): 大写转换toupper("abc")返回值为"ABC"
# tolower(x):小写转换tolower("ABC")返回值为"abc"
# 请注意,函数grep()、sub()和strsplit()能够搜索某个文本字符串(fixed=TRUE)或
# 某个正则表达式(fixed=FALSE,默认值为FALSE)。正则表达式为文本模式的匹配提供了一套
# 清晰而简练的语法。例如,正则表达式:
# ^[hc]?at
# 可匹配任意以0个或1个h或c开头、后接at的字符串。因此,此表达式可以匹配hat、cat和at,但不会匹配bat。


# 5.2.5 其他实用函数
# length(x):对象x的长度x <- c(2, 5, 6, 9)length(x)返回值为4
# seq(from, to, by):生成一个序列indices <- seq(1,10,2)indices的值为c(1, 3, 5, 7, 9)
# rep(x, n):将x重复n次y <- rep(1:3, 2)y的值为c(1, 2, 3, 1, 2, 3)
# cut(x, n):将连续型变量x分割为有着n个水平的因子使用选项ordered_result = TRUE以创建一个有序型因子
# pretty(x, n):创建美观的分割点。通过选取n+1个等间距的取整值,将一个连续型变量x分割为n个区间。绘图中常用
# cat(..., file = "myfile", append = FALSE):连接...中的对象,并将其输出到屏幕上或文件中(如果声明了一个的话)firstname <- c("Jane")cat("Hello" ,firstname, "\\n")
# 表中的最后一个例子演示了在输出时转义字符的使用方法。\\n表示新行,\\t为制表符,\\'为单引号,\\b为退格,等等。(键入?Quotes以了解更多。)例如,代码:
name <- "Bob"
cat("Hello", name, "\\b.\\n", "Isn\\'t R", "\\t", "GREAT?\\n")


# 5.2.6 将函数应用于矩阵和数据框
# R函数的诸多有趣特性之一,就是它们可以应用到一系列的数据对象上,包括标量、向量、 矩阵、数组和数据框。
# 代码清单5-4 将函数应用于数据对象
a <- 5
sqrt(a)
b <- c(1,243, 5.654, 2.99)
round(b)
c <- matrix(runif(12), nrow = 3)
log(c)
mean(c)
# R中提供了一个apply()函数,可将一个任意函数“应用”到矩阵、数组、数据框的任何维 度上。apply函数的使用格式为:
# apply(x, MARGIN, FUN, ...) 
# 其中,x为数据对象,MARGIN是维度的下标,FUN是由你指定的函数,而...则包括了任何想传 递给FUN的参数。在矩阵或数据框中,MARGIN=1表示行,MARGIN=2表示列。
# 代码清单5-5 将一个函数应用到矩阵的所有行(列)
# 生成数据
mydata <- matrix(rnorm(30), nrow = 6)
mydata
# 计算每行的均值
apply(mydata, 1, mean)
# 计算每列的均值
apply(mydata, 2, mean)
# 计算每列的截尾均值
apply(mydata, 2, mean, trim = 0.2)
# FUN可为任意R函数,这也包括你自行编写的函数(参见5.4节),所以apply()是一种很强大的机制。apply()可把函数应用到数组的某个维度上,而lapply()和sapply()则可将函数应用 到列表(list)上。你将在下一节中看到sapply(它是lapply的更好用的版本)的一个示例。



# 5.3 数据处理难题的一套解决方案
# 5.1节中提出的问题是:将学生的各科考试成绩组合为单一的成绩衡量指标、基于相对名次(前 20%,下20%,等等)给出从A到F的评分、根据学生姓氏和名字的首字母对花名册进行排序。代码 2 清单5-6给出了一种解决方案。
# 代码清单5-6 示例的一种解决方案
options(digits = 2)
Student <- c("John Davis", "Angela Williams", "Bullwinkle Moose",
             "David Jones", "Janice Markhammer", "Cheryl Cushing",
             "Reuven Ytzrhak", "Grep Knox", "Joel England", "Mary Rayburn")
Math <- c(502, 600, 412, 358, 495, 512, 410, 625, 573, 523)
Science <- c(95, 99, 80, 82, 75, 85, 80, 95, 89, 86)
English <- c(25, 22, 18, 15, 20, 28, 15, 30, 27, 18)
roster <- data.frame(Student, Math ,Science, English,
                     stringsAsFactors = FALSE)
# 计算综合得分
# 由于数学、科学和英语考试的分值不同(均值和标准差相去甚远),在组合之前需 要先让它们变得可以比较。一种方法是将变量进行标准化,这样每科考试的成绩就都是用单位标 准差来表示,而不是以原始的尺度来表示了。这个过程可以使用scale()函数来实现:
z <- scale(roster[, 2:4])
# 对列求平均分
#  然后,可以通过函数mean()来计算各行的均值以获得综合得分,并使用函数 cbind()将其添加到花名册中:
score <- apply(z, 1, mean)
roster <- cbind(roster, score)
# 函数quantile()给出了学生综合得分的百分位数。可以看到,成绩为A的分界点 为0.74,B的分界点为0.44,
y <- quantile(score, c(.8, .6, .4, .2))
# 通过使用逻辑运算符,你可以将学生的百分位数排名重编码为一个新的类别型成绩变量。下面在数据框roster中创建了变量grade。
roster$grade[score >= y[1]] <- "A"
roster$grade[score < y[1] & score >= y[2]] <- "B"
roster$grade[score < y[2] & score >= y[3]] <- "C"
roster$grade[score < y[3] & score >= y[4]] <- "D"
roster$grade[score < y[4]] <- "F"
# 你将使用函数strsplit()以空格为界把学生姓名拆分为姓氏和名字。把strsplit() 应用到一个字符串组成的向量上会返回一个列表:
name <- strsplit((roster$Student), " ")
# 你可以使用函数sapply()提取列表中每个成分的第一个元素,放入一个储存名字 的向量,并提取每个成分的第二个元素,放入一个储存姓氏的向量。"["是一个可以提取某个对
#   象的一部分的函数——在这里它是用来提取列表name各成分中的第一个或第二个元素的。你将 使用cbind()把它们添加到花名册中。由于已经不再需要student变量,可以将其丢弃(在下标 中使用1)
lastname <- sapply(name, "[", 2)
firstname <- sapply(name, "[", 1)
# 合并
roster <- cbind(firstname, lastname, roster[,-1])
# 最后,可以使用函数order()依姓氏和名字对数据集进行排序
roster <- roster[order(lastname, firstname),]


# 5.4 控制流
# 牢记以下概念:
# 语句(statement)是一条单独的R语句或一组复合语句(包含在花括号  中的一组R语句,使用分号分隔);
# 条件(cond)是一条最终被解析为真(TRUE)或假(FALSE)的表达式;
# 表达式(expr)是一条数值或字符串的求值语句;
# 序列(seq)是一个数值或字符串序列。

# 5.4.1 重复和循环
# 1.for结构
# for循环重复地执行一个语句,直到某个变量的值不再包含在序列seq中为止。语法为:
# for (var in seq) statement
for (i in 1:10) 
  print("Hello")

# 2. while结构
# while循环重复地执行一个语句,直到条件不为真为止。语法为:
# while(cond) statement
i <- 10
while (i > 0) 
  print( i)
  i <- i-1


# 5.4.2 条件执行
# 1.if-else结构
str <- c("a", "b", "c")
if (is.character(str)) 
  str <- as.factor(str)
if(!is.factor(str))
  grade <- as.factor(grade) else
  print("Grade already is a factor")
# 2.ifelse结构
# ifelse结构是if-else结构比较紧凑的向量化版本,其语法为:
# ifelse(cond, statement1, statement2)
# 若cond为TRUE,则执行第一个语句;若cond为FALSE,则执行第二个语句。示例如下:
score <- 0.1
ifelse(score > 0.5, print("Passed"), print("Failed"))
# 在程序的行为是二元时,或者希望结构的输入和输出均为向量时,请使用ifelse。
outcome <- ifelse (score > 0.5, "Passed", "Failed")
# 3.switch结构
# switch根据一个表达式的值选择语句执行。语法为:
# switch(expr, ...)
feelings <- c("sad", "afraid")
for (i in feelings) 
  switch(i,
         happy = print("I am glad you are happy"),
         afraid = print("There is nothing to fear"),
         sad = print("Cheer up"),
         angry = print("Calm down now")
  )




# 5.5 用户自编函数
# 一个函数的结构看起来大致如此:
# myfunction <- function(arg1, arg2, ...) 
#   statements
#   return(object)
# 
# 代码清单5-8 mystats():一个由用户编写的描述性统计量计算函数
mystats <- function(x, parametric = TRUE, print = FALSE) 
  if (parametric) 
    center <- mean(x); spread <- sd(x)
   else 
    center <- median(x); spread <- mad(x)
  
  if (print & parametric) 
    cat("Mean=", center, "\\n", "SD=", spread, "\\n")
   else if (print & !parametric) 
    cat("Median=", center, "\\n", "MAD=", spread, "\\n")
  
  result <- list(center = center, spread = spread)
  return(result)


# 生成服从正态分布的,大小为500的随机样本
set.seed(1234)
x <- rnorm(500)
# 执行以下语句没有输出结果
y <- mystats(x)
# y$center将包含中位数(–0.0207),y$spread将包含绝对中位差(1.001)。另外,还会输出结果:
y <- mystats(x, parametric = FALSE, print = TRUE)

# 使用了switch结构的用户自编函数,此函数可让用户选择输出当天日期的格式。在函数声明中为参数指定的值将作为其默认值。在函数mydate()中,如果未指定type, 则long将为默认的日期格式:
mydate <- function(type = "long") 
  switch(type,
         long = format(Sys.time(), "%A %B %d %Y"),
         short = format(Sys.time(), "%m-%d-%y"),
         #cat(type, "is not a recogined type\\n") # 方式一提示
         warning(type, " is not a recogined type\\n") # 方式二提示
      )

# 调用
mydate()
mydate("long")
mydate("short")
mydate("medium")


# 5.6 整合与重构
# 5.6.1 转置
# 使用函数t()即可对 一个矩阵或数据框进行转置。对于后者,行名将成为变量(列)名。
cars <- mtcars[1:5, 1:4]
cars
# 转置
t(cars)

# 5.6.2 整合数据
# 在R中使用一个或多个by变量和一个预先定义好的函数来折叠(collapse)数据是比较容易的。调用格式为:
# aggregate(x, by, FUN)
# 其中x是待折叠的数据对象,by是一个变量名组成的列表,这些变量将被去掉以形成新的观测, 而FUN则是用来计算描述性统计量的标量函数,它将被用来计算新观测中的值。
# 代码清单5-10 整合数据
options(digits = 3)
attach(mtcars)
aggdata <- aggregate(mtcars, by = list(cyl, gear), FUN = mean, na.rm = TRUE)
# 在使用aggregate()函数的时候,by中的变量必须在一个列表中(即使只有一个变量)。你 可以在列表中为各组声明自定义的名称,例如by=list(Group.cyl=cyl, Group. gears=gear)。指定的函数可为任意的内建或自编函数,这就为整合命令赋予了强大的力量。
# aggdata <- aggregate(mtcars, by = list(Group.cyl = cyl, Group.gears = gear), FUN = mean, na.rm = TRUE)
# 在结果中,Group.1表示汽缸数量(4、6或8),Group.2代表挡位数(3、4或5)。举例来说, 拥有4个汽缸和3个挡位车型的每加仑汽油行驶英里数(mpg)均值为21.5。
aggdata
detach(mtcars)

# 5.6.3 reshape包
# reshape包是一套重构和整合数据集的绝妙的万能工具
install.packages("reshape")
# 大致说来,你需要首先将数据“融合”(melt),以使每一行都是一个唯一的标识符—变量组 合。然后将数据“重铸”(cast)为你想要的任何形状。在重铸过程中,你可以使用任何函数对数 据进行整合。
# 1. 融合
# 数据集的融合是将它重构为这样一种格式:每个测量变量独占一行,行中带有要唯一确定这个测量所需的标识符变量。要融合表5-8中的数据,可使用以下代码:
library(reshape)
id = c(1, 1, 2, 2)
time = c(1, 2, 1, 2)
X1 = c(5, 3, 6, 2)
X2 = c(6, 5, 1, 4)
mydata <- data.frame(id, time, X1, X2)
md <- melt(mydata, id=(c("id", "time"))) 
# 注意,必须指定要唯一确定每个测量所需的变量(ID和Time),而表示测量变量名的变量(X1 或X2)将由程序为你自动创建。

# 2. 重铸
# cast()函数读取已融合的数据,并使用你提供的公式和一个(可选的)用于整合数据的函数将其重塑。调用格式为:
# newdata <- cast(md, formula, FUN)
# 其中的md为已融合的数据,formula描述了想要的最后结果,而FUN是(可选的)数据整合函数。 其接受的公式形如:
# rowvar1 + rowvar2 + _ colvar1 + colvar2 + _
# 在这一公式中,rowvar1 + rowvar2 + ...定义了要划掉的变量集合,以确定各行的内容, 而colvar1 + colvar2 + ...则定义了要划掉的、确定各列内容的变量集合。
# 以下三个语句在自己本地都执行不了,搜了网上的答案也没有效的方案解决
# 报错如下:Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE,  : arguments imply differing number of rows: 4, 0
# cast(md, id ~ variable, mean)
# cast(md, time ~ variable, mean)
# cast(md, id ~ variable, mean)
# cast(md, id ~ time, mean)

以上是关于《R语言实战》第5章的主要内容,如果未能解决你的问题,请参考以下文章

《R语言实战》第4章

《R语言实战》第2章

R语言使用lsa包计算余弦相似度(Cosine Similarity)实战:两个向量的余弦相似度矩阵的余弦相度

Python绘制正弦余弦函数用到哪些函数?

R语言实战 第7章

《R语言实战》第1章