【R语言实战】Chapter5 高级数据管理

写在前面
前面的初级数据管理只能让你了解一下R在处理各种不同类型数据时发挥的便捷性,平时的科研工作中遇到最多的还是高级数据管理。包括各种需求的组合以及控制流的使用等。

5.1 一个数据处理难题

要讨论数值和字符处理函数,让我们首先考虑一个数据处理问题。一组学生参加了数学、科 学和英语考试。为了给所有学生确定一个单一的成绩衡量指标,需要将这些科目的成绩组合起来。 另外,你还想将前20%的学生评定为A,接下来20%的学生评定为B,依次类推。后,你希望按 字母顺序对学生排序。数据如表5-1所示。


image.png

5.2 数值和字符处理函数

本小节介绍数据处理的基石函数,包括数值(数学,统计和概率)函数和字符处理函数。

5.2.1 数字函数

image.png

image.png

5.2.2 统计函数

image.png

image.png

数据的标准化
默认情况下,函数scale()对矩阵或数据框的指定列进行均值为0,标准差为1的标准化。

> newdata <- scale(mydata)

5.2.3 概率函数

image.png

正态分布函数


image.png

1.设定随机数种子

在每次生成伪随机数的时候,函数都会使用一个不同的种子,因此也会产生不同的结果。你可以通过函数set.seed()显式指定这个种子,让结果可以重现(reproducible),也就是别人可以重复你的代码。下面的代码给出了一个示例。这里的函数runif()用来生成0到1区间上服从均匀分布的伪随机数。

> runif(5) 
[1] 0.8725344 0.3962501 0.6826534 0.3667821 0.9255909 
> runif(5) 
[1] 0.4273903 0.2641101 0.3550058 0.3233044 0.6584988 
> set.seed(1234) 
> runif(5) 
[1] 0.1137034 0.6222994 0.6092747 0.6233794 0.8609154 
> set.seed(1234) 
> runif(5) 
[1] 0.1137034 0.6222994 0.6092747 0.6233794 0.8609154 

2. 生成多元正态数据

在模拟研究和蒙特卡洛方法中,你经常需要获取来自给定均值向量和协方差阵的多元正态分 布的数据。MASS包中的mvrnorm()函数可以让这个问题变得很容易。其调用格式为:

mvrnorm(n, mean, sigma)

其中n是你想要的样本大小,mean为均值向量,而sigma是方差-协方差矩阵(或相关矩阵)。


image.png

5.2.4 字符处理函数

image.png

image.png

函数grep()、sub()和strsplit()能够搜索某个文本字符串(fixed=TRUE)或 某个正则表达式(fixed=FALSE,默认值为FALSE)。
正则表达式举例:

^[hc]?at 

可以匹配任意以0个或1个h或c开头,后接at的字符串。

5.2.5 其他实用函数

image.png

5.2.6 将函数应用于矩阵和数据框

> a <- 5 > sqrt(a)  
[1] 2.236068 
> b <- c(1.243, 5.654, 2.99) 
> round(b) #将b舍入为指定位的小数
[1] 1 6 3 
> c <- matrix(runif(12), nrow=3) 
> c       
      [,1]  [,2]  [,3]  [,4] 
[1,] 0.4205 0.355 0.699 0.323 
[2,] 0.0270 0.601 0.181 0.926
[3,] 0.6682 0.319 0.599 0.215 
> log(c)        
     [,1]   [,2]   [,3]   [,4] 
[1,] -0.866 -1.036 -0.358 -1.130 
[2,] -3.614 -0.508 -1.711 -0.077 
[3,] -0.403 -1.144 -0.513 -1.538 
> mean(c) 
[1] 0.444

上述代码框的最后一行代码,函数mean()求的是矩阵中全部12个元素的均值,如果想求的是各行或各列的均值,应该用apply()函数,她可以将将一个任意函数“应用”到矩阵、数组、数据框的任何维 度上。apply()函数的使用格式为:

apply(x, MARGIN, FUN, ...) 

x为数据对象,MARGIN是维度的下标,FUN是由你指定的函数,而...则包括了任何想传 递给FUN的参数。在矩阵或数据框中,MARGIN=1表示行,MARGIN=2表示列。
apply()可把函数应用到数组的某个维度上,而lapply()sapply()则可将函数 应用到列表(list)上.

5.3 数据处理难题的一套解决方案

5.1节中提出的问题是:将学生的各科考试成绩组合为单一的成绩衡量指标,基于相对名次 (前20%、下20%、等等)给出从A到F的评分,根据学生姓氏和名字的首字母对花名册进行排序。
步骤1:

options(digits=2)限定了输出小数点后数字的 位数,并且让输出更容易阅读。

> options(digits=2) 
> Student <- c("John Davis", "Angela Williams", "Bullwinkle Moose", "David Jones", "Janice Markhammer", "Cheryl Cushing",  "Reuven Ytzrhak", "Greg Knox", "Joel England", "Mary Rayburn") 
> Math <- c(502, 600, 412, 358, 495, 512, 410, 625, 573, 522) 
> 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) 

步骤2 由于数学、科学和英语考试的分值不同(均值和标准差相去甚远),在组合之前需 要先让它们变得可以比较。一种方法是将变量进行标准化,这样每科考试的成绩就都是用单位 标准差来表示,而不是以原始的尺度来表示了。这个过程可以使用scale()函数来实现:

> z <- scale(roster[,2:4]) 

步骤3 然后,可以通过函数mean()来计算各行的均值以获得综合得分,并使用函数 cbind()将其添加到花名册中:

> score <- apply(z, 1, mean) 
> roster <- cbind(roster, score) 

步骤4 函数quantile()给出了学生综合得分的百分位数。可以看到,成绩为A的分界点为 0.74,B的分界点为0.44,等等。

> y <- quantile(score, c(.8,.6,.4,.2))
> y    
80%   60%   40%   20%  
0.74  0.44 -0.36 -0.89  

步骤5 通过使用逻辑运算符,你可以将学生的百分位数排名重编码为一个新的类别型成绩 变量。下面在数据框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" 

步骤6 你将使用函数strsplit()以空格为界把学生姓名拆分为姓氏和名字。把 strsplit()应用到一个字符串组成的向量上会返回一个列表:

> name <- strsplit((roster$Student), " ") 

步骤7 你可以使用函数sapply()提取列表中每个成分的第一个元素,放入一个储存名字 的向量Firstname,并提取每个成分的第二个元素,放入一个储存姓氏的向量Lastname。"[" 是一个可以提取某个对象的一部分的函数——在这里它是用来提取列表name各成分中的第一 个或第二个元素的。你将使用cbind()把它们添加到花名册中。由于已经不再需要student变 量,可以将其丢弃(在下标中使用–1)。

> Lastname <- sapply(name, "[", 2) 
> Firstname <- sapply(name, "[", 1) 
> roster <- cbind(Firstname,Lastname, roster[,-1]) 

步骤8 后,可以使用函数order()依姓氏和名字对数据集进行排序:

> roster <- roster[order(Lastname,Firstname),] 
> roster 
    Firstname   Lastname Math Science English score grade
6      Cheryl    Cushing  512      85      28  0.35     C
1        John      Davis  502      95      25  0.56     B
9        Joel    England  573      89      27  0.70     B
4       David      Jones  358      82      15 -1.16     F
8        Greg       Knox  625      95      30  1.34     A
5      Janice Markhammer  495      75      20 -0.63     D
3  Bullwinkle      Moose  412      80      18 -0.86     D
10       Mary    Rayburn  522      86      18 -0.18     C
2      Angela   Williams  600      99      22  0.92     A
7      Reuven    Ytzrhak  410      80      15 -1.05     F

5.4 控制流

在正常情况下,R程序中的语句是从上至下顺序执行的。但有时你可能希望重复执行某些语 句,仅在满足特定条件的情况下执行另外的语句。这就是控制流结构发挥作用的地方了。
R拥有一般现代编程语言中都有的标准控制结构。首先你将看到用于条件执行的结构,接下 来是用于循环执行的结构。
为了理解贯穿本节的语法示例,请牢记以下概念:
语句(statement)是一条单独的R语句或一组复合语句(包含在花括号{ }中的一组R 语句,使用分号分隔);
条件(cond)是一条终被解析为真(TRUE)或假(FALSE)的表达式;
表达式(expr)是一条数值或字符串的求值语句;
序列(seq)是一个数值或字符串序列。
在讨论过控制流的构造后,我们将学习如何编写函数。

5.4.1 重复和循环

循环结构重复地执行一个或一系列语句,直到某个条件不为真为止。循环结构包括for和 while结构。
1. for结构
for循环重复地执行一个语句,直到某个变量的值不再包含在序列seq中为止。语法为:
for (var in seq) statement
在下例中:

for (i in 1:10)  print("Hello") 

单词Hello被输出了10次。
2. while结构
while循环重复地执行一个语句,直到条件不为真为止。语法为:
while (cond) statement
作为第二个例子,代码:

i <- 10 while (i > 0) {print("Hello"); i <- i - 1} 

又将单词Hello输出了10次。请确保括号内while的条件语句能够改变,即让它在某个时刻不再为 真——否则循环将永不停止!
在上例中,语句:
i <- i – 1 在每步循环中为对象i减去1,这样在十次循环过后,它就不再大于0了。反之,如果在每步循环 都加1的话,R将不停地打招呼。这也是while循环可能较其他循环结构更危险的原因。 在处理大数据集中的行和列时,R中的循环可能比较低效费时。只要可能,好联用R中的 内建数值/字符处理函数和apply族函数。

5.4.2 条件执行

在条件执行结构中,一条或一组语句仅在满足一个指定条件时执行。条件执行结构包括 if-else、ifelse和switch。
1. if-else结构
控制结构if-else在某个给定条件为真时执行语句。也可以同时在条件为假时执行另外的语 句。语法为:

if (cond) statement if (cond) statement1 else statement2 

示例如下:

if (is.character(grade)) grade <- as.factor(grade)  
if (!is.factor(grade)) grade <- as.factor(grade) else print("Grade already     is a factor") 

在第一个实例中,如果grade是一个字符向量,它就会被转换为一个因子。在第二个实例中, 两个语句择其一执行。如果grade不是一个因子(注意符号!),它就会被转换为一个因子。如果 它是一个因子,就会输出一段信息。
2. ifelse结构
ifelse结构是if-else结构比较紧凑的向量化版本,其语法为:

ifelse(cond, statement1, statement2) 

若cond为TRUE,则执行第一个语句;若cond为FALSE,则执行第二个语句。示例如下:

ifelse(score > 0.5, print("Passed"), print("Failed")) 
outcome <- ifelse (score > 0.5, "Passed", "Failed") 

在程序的行为是二元时,或者希望结构的输入和输出均为向量时,请使用ifelse。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容