第5章工欲善其事、必先利其器
代码,是延伸我们思想最好的工具。
第6章基础编程——用别人的包和函数讲述自己的故事
6.1编程环境
1.R语言的三段论
大前提:计算机语言程序=算法+数据结构
小前提:R语言不过是计算机语言的一种
结论:R语言约等于基础编程+数据对象
2.运行机制
RStudio=记事本+R Console
6.2Mini案例
学生文理分科小案例(还有问题)
R仅有的命令形式是返回结果的函数和表达式
赋值是一种常见的操作:对象的读取、转换、模型的建立等
赋值给新的对象,往往也意味着数据的流转:读取、转换、探索、建模、评估等操作。
6.3站在巨人的肩膀上
1.编程的法则:
R编程=用别人的包和函数讲述自己的故事
2.如何搜索包
①上百度
②逛论坛,找答案,[r]搜索
https://stackoverflow.com/questions/tagged/r
③sos,扩展包,安装sos包,利用findFn()函数搜索包
④Task Views
⑤专注于某个领域,慢慢积累
3.利用好帮助文档,如?c
6.4控制流
结构化编程:任何简单或者复杂的逻辑都可以由顺序、分支和循环这三种基本结构组合而成。
1.顺序结构
> yw <- c(94,87,92,91,85,92)
> sx <- c(82,94,79,84,92,82)
> wy <- c(96,89,86,96,82,85)
> ysw <- yw+sx+wy
> ysw
[1] 272 270 257 271 259 259
> (yw <- yw+2)
> (mean_score <- mean(yw))#求语文平均分
[1] 92.16667
> sd(yw)#求语文成绩标准差
[1] 3.430258
> c(sd(yw),sd(sx),sd(wy))
[1] 3.430258 6.058052 5.865151
> show(yw)
[1] 96 89 94 93 87 94
> show(sx)#显示数学成绩
[1] 82 94 79 84 92 82
> yw >= 90#向量化操作:逻辑判断
[1] TRUE FALSE TRUE TRUE FALSE TRUE
> yw >= 85&sx >=85#向量化操作:逻辑判断
[1] FALSE TRUE FALSE FALSE TRUE FALSE
> yw >=95 | sx >=95#向量化操作:逻辑判断
[1] TRUE FALSE FALSE FALSE FALSE FALSE
2.分支结构
条件表达式根据条件而执行不同的代码
if(条件){
cons.expr
}else{
alt.expr
}
注意:条件为一个标量的真或者假值,else子句如果存在的话,必须和}在同一行。else不能单起一行
> min_score <- min(yw)#语文最低成绩为87
if(min_score>=90){
message("语文成绩全部为优") //控制台输出
}else if(min_score>=80){
message("语文成绩至少为良")
}else{
message("并非所有同学语文成绩均为优良")
}
> ifelse(yw >= 90,"优",ifelse(yw >= 88,"较好","一般"))
[1] "优" "较好" "优" "优" "一般" "优"
3.循环结构 for while repeat
两种语句用于控制循环:
break 语句可以从当前运行的循环里面跳出来
next 语句会导致控制立即返回到循环的起点,next后面的语句不会被执行
实例:斐波那契数列
n_fib <- 16
fib <- numeric(n_fib)
fib[1:2] <- c(1,1)
for(i in 3:n_fib){
fib[i] <- fib[i-1]+fib[i-2]
show(fib[i])
}
fib
> fib
[1] 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
求1000以内的斐波那契数列:
#不知道循环多少次,仅知道终止条件,通过while来实现
fib <- c(1,1)
while(sum(tail(fib,2))<1000){
fib <- c(fib,sum(tail(fib,2)))
}
fib
#也可以通过repeat来无条件循环,直到满足某个条件时break
fib <- c(1,1)
repeat{ //repeat==while(T)
if(sum(tail(fib,2))>=1000){
break
}
fib <- c(fib,sum(tail(fib,2)))
}
fib
另一个例子:抽取幸运数字52
time_count <- 0
repeat{
my_number <- sample(100,1)#从1到100里面抽取一个数字
time_count <- time_count+1
if(my_number==52){
message("Hahaha,I finally got \'52\' after",time_count,"times")
break
}else {
message(time_count,":Not lucky enough [",my_number, "]")
}
}
4.再说向量化:尽量不要使用显式循环,能向量化的运算的,尽量向量化,运算时间大大减少。
只要串行模式不是必须的,采用并行的方式。
R里面的并行作业:
向量化函数:sqrt(),sin(),round(),as.numeric(),cut(),weekdays(),+,-,*,/,&,|,%in%.....
6.5函数(1)
事不过三
1.编写函数
fun_name <- function(arg1,arg2=default1,...){ #注释 表达式(循环/判别/.....) return(返回值) }
ps:R里面一切都是对象,对象通过赋值来产生,函数也不例外。
函数声明关键字是function,function返回值就是函数
参数列表是以逗号分隔,函数主体可以是任何合法的R表达式
若无return语句,最后一个表达式的值作为返回值
以function_name(arg1,arg2,....)的形式调用函数
#摄氏度到华氏度的转换
ce2fa <- function(ce){#参数ce为输入
fa <- 1.8*ce+32#对输入进行处理
return(fa)#输出相应的值
}
ce2fa(0)#0摄氏度相当于32华氏度
[1] 32
ce2fa(0:10)
[1] 32.0 33.8 35.6 37.4 39.2 41.0 42.8 44.6 46.4 48.2 50.0
#注意位置参数和名义参数
frm <- function(name,frm="BUPT"){
cat(name,"is frm",frm) //显示
}
frm("axb")
axb is frm BUPT
frm("axb","BJTU") //位置参数
axb is frm BJTU
frm(frm="BJTU",name="axb")//名义参数
axb is frm BJTU
2.熟而不觉的函数:作为函数的二元操作符
+,-,*,/其实都是函数
%in%运算符:左侧的每个元素是否在右侧的集合之中
c(1,3,9) %in% 1:3
\'%in%\'(c(1,3,9),1:3)
[1] TRUE TRUE FALSE
#自己定义二元操作符函数:a,b为直角边,c为斜边
"%ab2c" <- function(a,b){
sqrt(sum(a^2,b^2))
}
"%ab2c%"(3,4)
#看完%ab2c%之后,对下面的符号,也就觉得不过如此了
library(purrr)
x <- c(17,28,17,12,15,12,49)
x %>%
unique() %>% #管道操作符也是一个二元操作符,函数而已
sort()
[1] 12 15 17 28 49
#等价于下面的代码,不过是更加简洁优雅
x <- c(17,28,17,12,15,12,49)
x2 <- unique(x) #剔除重复的数目
x3 <- sort(x2)
x3
[1] 12 15 17 28 49
#定义二元操作符的时候,必须用双引号括起来
5+2
"+" <- function(x,y){
x*y
}
5 + 2
[1] 10
rm("+")#消除恶作剧的+运算
5+2
[1] 7
ps:特殊函数的帮助文档
?“+” #双引号
?‘+’#单引号
?·+·#反单引号
6.6函数(2)
1.不一样的plot
x <- seq(1,100,by=10)
y <- 2*x+10
xy <- cbind(x,y)
class(xy) #矩阵
[1] "matrix" "array"
plot(xy,
xlim = c(1,100),
ylim = c(0,230),
type = "o",col = "red"
)
x <- seq(1,100,by=10)
y <- 2*x+10
my_model <- lm(y~x) #拟合一个线性模型
class(my_model) #线性模型
[1] "lm"
op <- par(mfrow=c(1,1))
plot(my_model)
par(op)
多态的问题:针对不同的对象有不同的行为,泛型函数
2.泛型函数:见什么人说什么话,到什么山上唱什么歌
定义和调用的过程
#编写泛型函数
interface <- function(x,y){ #接口函数
message("Singal interface")
UseMethod("particular",y)#参照第二个参数的类别来进行分发
}
particular.classA <- function(x,y){#分发函数
message("Different behavior:classA")
}
particular.classB <- function(x,y){#分发函数
message("Different behavior:classB")
}
particular.default <- function(x,y){#分发函数
message("Different behavior:default")
}
x <- 1:10
y <- 1:20
class(y) <- "classA"#给A贴上标签-classA
interface(x,y)
Singal interface
Different behavior:classA
类标签不一样的时候,接口是一样的
class(y) <- NULL
interface(x,y)
Singal interface
Different behavior:default
重新审视+:
> methods("+")
[1] +.Date +.glue* +.POSIXt +.vctrs_vctr*
see \'?methods\' for accessing help and source code
> library(ggplot2)
> methods("+")
[1] +.Date +.gg* +.glue* +.POSIXt
[5] +.vctrs_vctr*
see \'?methods\' for accessing help and source code
定义自己的+
"+.onlyFirst" <- function(a,b){
return(a[1]+b[1])
}
a <- 1:5
a+6:10
1] 7 9 11 13 15
class(a) <- "onlyFirst"#给a贴上一个类标签onlyFirst
a+6:10
[1] 7
3.递归:层层递进,逐层回归
老和尚讲故事:
rep(x, …):将vector x的值循环n遍
old_monk_story <- function(depth=1){
message(rep(" ",depth),"400 years ago(",2020-400*depth,"),monk[",depth,"]is
telling the story:")
if(2020-400*(depth+1)>=66){#据说佛教公元66年传入中国
old_monk_story(depth+1)
}
message(rep(" ",depth),"monk [",depth,"]finshed his story")
}
old_monk_story()
400 years ago(1620),monk[1]is
telling the story:
400 years ago(1220),monk[2]is
telling the story:
400 years ago(820),monk[3]is
telling the story:
400 years ago(420),monk[4]is
telling the story:
monk [4]finshed his story
monk [3]finshed his story
monk [2]finshed his story
monk [1]finshed his story
重新审视斐波那契数列
fib <- function(n){
if(n==1){
return(1)
}else{
return(c(fib(n-1),sum(tail(fib(n-1),n=2))))
}
}
fib(10)
[1] 1 1 2 3 5 8 13 21 34 55
错题整理:
1.对于特殊的函数if或者+等,通过helo()或是单引号、双引号、反单引号查找帮助文档
2.repeat循环体中必然有一条break语句,next语句只是中断本轮循环跳转至下一轮循环。若repeat语句中仅有next而无break,依然是死循环。
第7章数据对象——面向数据对象学习R语言
7.1向量与因子(1)
1.数据对象:
向量/因子
矩阵/数组
列表/数据框
2.创建向量
#创建向量最常见的方式c(),combine
#字符型向量
xm <- c("周","xie","gao")
Xb <- c("女","男","男")
#数值型向量
yw <- c(94,92,98)
#逻辑型向量
xb2 <- c(R,T,F)
#不能有混合类型
my_pi <- c(3,".",1,4,1,5,9,2,6)
my_pi
[1] "3" "." "1" "4" "1" "5" "9" "2" "6"
#材质不一样时强制转换
my_pi <- c(3,T,4,T,5,9,2,6)
my_pi
[1] 3 1 4 1 5 9 2 6
c(1,2,c(4,3),c(1,0))#不存在包含向量的向量,一律拆包
[1] 1 2 4 3 1 0
c(1,2,4,3,1,0
[1] 1 2 4 3 1 0
> (x1 <- vector("numeric",8))#事先知道长度和类型 ,默认值是0
[1] 0 0 0 0 0 0 0 0
> (x2 <- numeric(8))
[1] 0 0 0 0 0 0 0 0
> (x3 <- character(8))
[1] "" "" "" "" "" "" "" ""
> (x4 <- vector(len=8))
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
> (x5 <- logical(8))
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
> #规则数列
> #等差数列
> seq(from=1,to=10,by=2)
[1] 1 3 5 7 9
> seq(from=20,to=1,by=-2)
[1] 20 18 16 14 12 10 8 6 4 2
> seq(from=1,to=20,length=10)#10个数,10个端点
[1] 1.000000 3.111111 5.222222 7.333333 9.444444 11.555556
[7] 13.666667 15.777778 17.888889 20.000000
> 1:10#创建from:10,步长为1的等差数列
[1] 1 2 3 4 5 6 7 8 9 10
> pi:1
[1] 3.141593 2.141593 1.141593
> #注意运算符的优先级
> 1:10-1#长度为10,:的优先级比-高
[1] 0 1 2 3 4 5 6 7 8 9
> 1:(10-1)#长度为9
[1] 1 2 3 4 5 6 7 8 9
> #不要有记忆的负担,在R里,不要吝啬()和{}的使用
创建向量:随机数列
> #产生随机数
> sample(10)#随机抽样
[1] 9 3 8 1 5 2 10 4 7 6
> sample(c("b","u","p","t","a","x","b"))#随机抽样
[1] "t" "a" "u" "b" "p" "x" "b"
> set.seed(2012)#设定随机数种子,设定随机数结果固定的
> sample(10)#结果应该是一致的,reproduction research
[1] 4 8 6 2 3 1 9 7 10 5
> (train_idx <- sample(1:10,7))
[1] 3 5 6 10 1 7 2
> #有放回的抽样
> re_sample <- sample(1:100,100,replace = T)
> unique_re_sample <- unique(re_sample) #去掉重复的
> length(unique_re_sample)#有放回的抽样,有约36.8%的数不被抽
[1] 63
3.访问向量的子集,向量的下标,向量的子集通过[]来指定
第一种方法:采用1~n的正整数来指定,n为向量的长度
> yw <- c(94,87,92,91,85,92)
> yw[c(2,5)]
[1] 87 85
> yw[c(2,5)]-90
[1] -3 -5
> yw[c(2,5)] <- yw[c(2,5)]+6
> yw
[1] 94 93 92 91 91 92
> yw[] <- mean(yw)#每一个元素都被赋值
> yw
[1] 92.16667
> yw <- mean(yw)
> yw
[1] 92.16667
>
> xm <- c("zhou","tang","xie","gao")
> xm[c(1,3,3,2)]
[1] "zhou" "xie" "xie" "tang"
子集不子,下标可重复,顺序可变
方法二:采用负整数,反向选出某些元素
> yw <- c(94,87,92,91,85,92)
> yw[-c(2,5)]
[1] 94 92 91 92
> which(yw<90) //输出的是下标
[1] 2 5
> idx <- which(yw<90)
> yw[-idx]#避免了硬代码(可变的),增强了代码的可维护性
[1] 94 92 91 92
方法三:逻辑下标
> xm <- c("zhou","tang","shu","weng","qi","zhan")
> yw <- c(94,87,92,91,85,92)
> yw<90
[1] FALSE TRUE FALSE FALSE TRUE FALSE
> yw[yw<90]
[1] 87 85
> xm[yw<90]
[1] "tang" "qi"
R为何智能的识别出了语文成绩小于90分(yw<90)的同学呢?
方法四:通过元素名称访问相应的子集
> xm <- c("zhou","tang","shu","weng","qi","zhan")
> yw <- c(94,87,92,91,85,92)
> names(yw) <- xm #取名
> yw
zhou tang shu weng qi zhan
94 87 92 91 85 92
> yw[c("tang","qi")]
tang qi
87 85
4.向量的基本操作
向量排序:
#向量排序 数值向量,默认从低到高,若想从高到低的话
fen_shu_xian2016 <- c(中科大=671,中央民族大学=625,北大=678,人大=670,
清华=680,北交=640,北京科技大=635,北京化工大=620,北邮=646,中农=634,北林=621)
sort(fen_shu_xian2016)
北京化工大 北林 中央民族大学 中农 北京科技大
620 621 625 634 635
北交 北邮 人大 中科大 北大
640 646 670 671 678
清华
680
order(fen_shu_xian2016,decreasing = T) #返回的是下标
[1] 5 3 1 4 9 6 7 10 2 11 8
> fen_shu_xian2016[order(fen_shu_xian2016,decreasing = T)]#把下标交给
清华 北大 中科大 人大 北邮
680 678 671 670 646
北交 北京科技大 中农 中央民族大学 北林
640 635 634 625 621
北京化工大
620
向量逆序排序:
> yw <- c(94,87,92,91,85,92)
> rev(yw)
[1] 92 85 91 92 87 94
> yw[6]#可以用来取最后一个元素,但是这种硬代码很难维护
[1] 92
> yw[length(yw)]#基本可行的方法
[1] 92
> tail(yw,n=1)#更好的选择,推荐
[1] 92
> rev(tail(yw,n=3))#等价于head(rev(yw),n=3)
[1] 92 85 91
数值向量运算:(从数学角度来看)
#原点
p0 <- c(x=0,y=0)
#向量1
p1 <- c(x=1,y=2)
#向量2
p2 <- c(x=2,y=3)
#求和
p3 <- p1+p2
#数乘
p4 <- 1.5*p3
#内积:表示同心同向性
sum(p1*p2)
> #向量的内积
> set.seed(2012)#括号内数值任意即可
> x <- rnorm(100)#生成随机数的数列,服从正太分布
> y <- rnorm(100)
> #求向量的内积
> sum(x*y)
[1] -11.1336
> sum(sort(x),sort(y))
[1] -20.56163
> sum(sort(x),sort(y,decreasing = T))
[1] -20.56163
7.2向量与因子(2)
1.变量分类
前两种无序因子和有序因子可以用因子来存储;
2.向量与因子的区别和联系:
向量用于存储数值变量(定距定比),因子用于存储类别变量(定类定序)
作为类别变量,只有有限个取值(类别),称为水平levels,取值水平往往远远少于观测对象(记录)的个数
在分组统计中,因子常用来作分组变量;分类问题均要求因变量为因子;在其他一些算法建模过程中,也要求其变量为因子(如arules::apriori())
因子也是也是更有效的存储方式:存储为整型向量,只不过每一个1~levels的正整数代表了相应的类别
3.因子的创建
方法一:基于向量
> xb <- c("女","男","男","女","男","女")
> xb
[1] "女" "男" "男" "女" "男" "女"
> typeof(xb)
[1] "character"
> xb <- factor(xb)
> xb <- factor(xb)
> xb
[1] 女 男 男 女 男 女
Levels: 男 女因子的基本操作
> xb[-c(2:3,6)]
[1] 女 女 男
Levels: 男 女
> xb[1] <- "男"
> xb
[1] 男 男 男 女 男 女
Levels: 男 女
> xb=="男"
[1] TRUE TRUE TRUE FALSE TRUE FALSE
> nlevels(xb)#取值水平的个数
[1] 2
> levels(xb)#取值水平
[1] "男" "女"
> typeof(xb)
[1] "integer"#内部实际存储为一个整型的向量
> as.numeric(xb)
[1] 1 1 1 2 1 2
> as.character(xb)
[1] "男" "男" "男" "女" "男" "女"
对于因子而言,表面上看是字符,实际上在内存里面是一个整型的向量。
> number_factors <- factor(c(10,20,20,20,10))
> mean(number_factors)
[1] NA
表面上看只是字符
> as.numeric(number_factors)#使用数值向量进行创建的时候,“10”当成字符来看待
[1] 1 2 2 2 1
> mean(as.numeric(number_factors))
[1] 1.6
> mean(as.numeric(as.character(number_factors)))
[1] 16
> mean(as.numeric(levels(number_factors)[number_factors]))
[1] 16
> #有序因子
> score <- factor(c("优","良","优","优","良","优"),ordered = T)
> score[1]>score[2]#怎么识别出来的呢?
[1] TRUE
> days <- factor(c("周一","周三","周二","周二"),ordered = T)
> days[3]<days[2]
[1] TRUE
> days[1]<days[2]
[1] FALSE
> days
[1] 周一 周三 周二 周二
Levels: 周二 < 周三 < 周一 #其实并没有那么智能,只是内部编码问题而已,按照字母顺序
#规定好levels,给定顺序
> days <- factor(c("周一","周三","周二","周二"),ordered = T,levels = c("周一","周二","周三"))
> days
[1] 周一 周三 周二 周二
Levels: 周一 < 周二 < 周三
> days[1]<days[3]
[1] TRUE
方法二:基于数值变量使用cut()进行分箱,进行离散化处理。
> #实战才是王道:数据分箱
> #百分制成绩变为五分制成绩
> yw <- c(94,87,92,91,85,92)
> #数据分箱
> yw5 <- cut(yw,breaks=c(0,(6:10)*10))#挖坑的过程,后面0,60,70,80,90,100这几个端点
> yw5
[1] (90,100] (80,90] (90,100] (90,100] (80,90] (90,100]
Levels: (0,60] (60,70] (70,80] (80,90] (90,100] #左开右闭,0没有取到
改进:
> #数据分箱+闭区间
> yw5 <- cut(yw,breaks=c(0,(6:10)*10),include.lowest = T)#挖坑的过程,后面0,60,70,80,90,100这几个端点
> yw5
[1] (90,100] (80,90] (90,100] (90,100] (80,90] (90,100]
Levels: [0,60] (60,70] (70,80] (80,90] (90,100]
问题:60划分区间不对
> #数据分箱+闭区间+左闭右开
> yw5 <- cut(yw,breaks=c(0,(6:10)*10),include.lowest = T,right=F)
> yw5
[1] [90,100] [80,90) [90,100] [90,100] [80,90) [90,100]
Levels: [0,60) [60,70) [70,80) [80,90) [90,100]
进一步改进:
> #数据分箱+闭区间+左闭右开+有序因子
> yw5 <- cut(yw,breaks=c(0,(6:10)*10),include.lowest = T,right=F,ordered_result = T)
> yw5
[1] [90,100] [80,90) [90,100] [90,100] [80,90) [90,100]
Levels: [0,60) < [60,70) < [70,80) < [80,90) < [90,100]
> #数据分箱+闭区间+左闭右开+有序因子+标签
> yw5 <- cut(yw,breaks=c(0,(6:10)*10),include.lowest = T,right=F,ordered_result = T,
+ labels = c("不及格","及格","中","良","优"))
> yw5
[1] 优 良 优 优 良 优
Levels: 不及格 < 及格 < 中 < 良 < 优
7.3矩阵与数组(1)
1.矩阵的创建:
#单变量观测值可以用向量或因子存储
#假设对观测对象的多个属性同时进行记录(多变量)
#若这些向量是同质的,宜采用矩阵作为一个整体进行存储
#依然以学生成绩这份数据为例
xm <- c("周莉","唐海明","舒江辉","翁可","奇强","詹蓉")
yw <- c(94,87,92,91,85,92)
sx <- c(82,94,79,84,92,82)
wy <- c(96,89,86,96,82,85)
#语文、数学、外语三科成绩作为一个整体
ysw <- matrix(c(94,87,92,91,85,92,
82,94,79,84,92,82,
96,89,86,96,82,85),ncol = 3)#分成3列,长度为18的数值向量
#矩阵在创建的时候案列优先进行填充
colnames(ysw) <- c("yw","sx","wy")
row.names(ysw) <- xm#给行或者列命名
View(ysw)
#假设数据本身就是站着的
ysw <- matrix(
c(94,82,96,
87,94,89,
92,79,86,
91,84,96,
85,92,82,
92,82,85),
byrow = TRUE,#注意byrow=参数的设置,默认是F
ncol = 3)
colnames(ysw) <- c("yw","sx","wy")
row.names(ysw) <- xm
View(ysw)
矩阵的基本性质:
> colnames(ysw)
[1] "yw" "sx" "wy"
> row.names(ysw)
[1] "周莉" "唐海明" "舒江辉" "翁可" "奇强" "詹蓉"
> nrow(ysw)#行数
[1] 6
> ncol(ysw)#列数
[1] 3
> dim(ysw)#行数和列数
[1] 6 3
> dimnames(ysw)#行列名称
[[1]]
[1] "周莉" "唐海明" "舒江辉" "翁可" "奇强" "詹蓉"
[[2]]
[1] "yw" "sx" "wy"
#子集的访问仍然是通过[]
#由于矩阵是二维的,需要\',\'来分别指定行和列
ysw[1,]#第一个同学语文、数学、外语得分
ysw["周莉",]#同上
yw sx wy
94 82 96
ysw[,1]#语文成绩
ysw[,"yw"]#同上
周莉 唐海明 舒江辉 翁可 奇强 詹蓉
94 87 92 91 85 92
> ysw["周莉",2:3]
sx wy
82 96
> ysw[1,c("sx","wy")]
sx wy
82 96
> ysw[1,-1]
sx wy
82 96
行列重排:
> #列重新排序
> ysw[,c("sx","yw","wy")]
sx yw wy
周莉 82 94 96
唐海明 94 87 89
舒江辉 79 92 86
翁可 84 91 96
奇强 92 85 82
詹蓉 82 92 85
> ysw[,c(2,1,3)]
sx yw wy
周莉 82 94 96
唐海明 94 87 89
舒江辉 79 92 86
翁可 84 91 96
奇强 92 85 82
詹蓉 82 92 85
> #行进行排序:按照数学成绩进行排序
> (order_sx <- order(ysw[,"sx"],decreasing = T))
[1] 2 5 4 1 6 3
> ysw[order_sx,]
yw sx wy
唐海明 87 94 89
奇强 85 92 82
翁可 91 84 96
周莉 94 82 96
詹蓉 92 82 85
舒江辉 92 79 86
#矩阵合并
#观测到新的记录
ysw1 <- matrix(c(94,87,92,91,85,92,
82,94,79,84,92,82,
96,89,86,96,82,85),ncol = 3,
dimnames = list(
c("周莉","唐海明","舒江辉","翁可","奇强","詹蓉"),
c("yw","sx","wy")
))
ysw2 <- matrix(
c(88,81,72,89,86,87),
ncol = 3,
dimnames = list(
c("穆伶俐","易伟杰"),
c("yw","sx","wy")
)
)
#叠罗汉一样
ysw <- rbind(ysw1,ysw2)
View(ysw)
#新增列
zzls <- matrix(
c(97,97,
95,94,
98,95,
93,97,
93,87,
91,90,
94,87,
97,94),
ncol = 2,byrow = T,
dimnames = list(
c("周莉","唐海明","舒江辉","翁可","奇强","詹蓉","穆伶俐","易伟杰"),
c("zz","ls")
)
)
cjb <- cbind(ysw,zzls)#按列进行合并
View(cjb)
其他一些基本操作:
> rowSums(cjb)#每个同学的总成绩
周莉 唐海明 舒江辉 翁可 奇强 詹蓉 穆伶俐 易伟杰
466 459 450 461 439 440 427 448
> colMeans(cjb)#按列求平均值,每门课的平均分
yw sx wy zz ls
88.750 84.250 88.375 94.750 92.625
> #更一般的方法
> apply(cjb,1,sum)#第二个参数表示作用的要么是行,要么是列
周莉 唐海明 舒江辉 翁可 奇强 詹蓉 穆伶俐 易伟杰
466 459 450 461 439 440 427 448
> apply(cjb,2,mean)
yw sx wy zz ls
88.750 84.250 88.375 94.750 92.625
> round(apply(cjb,2,sd),digits = 2)#sd标准差
yw sx wy zz ls
4.33 7.23 5.10 2.43 4.10
> #可以自定义函数
> coefficient_of_variation <- function(x){
+ sd(x)/mean(x)
+
+ }
> apply(cjb,2,coefficient_of_variation)
yw sx wy zz ls
0.04883661 0.08576790 0.05767772 0.02569779 0.04430305
> #当然,也可以采用匿名函数
> apply(cjb, 2, function(x){
+ sd(x)/mean(x)
+ })
yw sx wy zz ls
0.04883661 0.08576790 0.05767772 0.02569779 0.04430305
总结:apply代表了一种数据处理模式
split-apply-combine模式,先分组,然后对每一个组进行操作,然后将操作结果进行combine在一起
apply函数族,以及tidyverse包
7.4矩阵和数组(2)
1.矩阵的运算,可以通过solve(A,b)
解以下方程组:
#定义系数矩阵
A <- matrix(
c(1,2,3,
2,2,5,
3,5,1),
ncol = 3,
byrow = T#按行排列
)
b <- 1:3
solve(A,b)
[1] 1 0 0
> #可以利用solve函数求逆矩阵
> diag(3)#生成单位矩阵
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 1 0
[3,] 0 0 1
> solve(A,diag(3))
[,1] [,2] [,3]
[1,] -1.5333333 0.86666667 0.26666667
[2,] 0.8666667 -0.53333333 0.06666667
[3,] 0.2666667 0.06666667 -0.13333333
> solve(A)#默认b是单位矩阵
[,1] [,2] [,3]
[1,] -1.5333333 0.86666667 0.26666667
[2,] 0.8666667 -0.53333333 0.06666667
[3,] 0.2666667 0.06666667 -0.13333333
> solve(A) %*% A #A的逆乘以A
[,1] [,2] [,3]
[1,] 1.000000e+00 8.881784e-16 1.054712e-15
[2,] -4.440892e-16 1.000000e+00 -7.077672e-16
[3,] -5.551115e-17 -1.110223e-16 1.000000e+00
> sqrt(2)^2==2
[1] FALSE
#以上两个例子原因都是一样的,涉及到R存储的有限位数,根号2是一个无理数,有无限位,但在存储的时候只能存储一部分,所以并不是完全等于2
> dplyr::near(sqrt(2)^2,2)#dplyer是一个包
[1] TRUE
> all(dplyr::near(solve(A) %*% A,diag(3)))
[1] TRUE
2.数组
数组是矩阵的扩展,矩阵是二位数组,以图像处理为例,简述三维数组的操作。
#数组
#读入一个彩色jpg文件,在R里面就是一个数组
> jpg_url <- "https://raw.githubusercontent.com/byaxb/RDataAnalytics/master/data/presidents.jpg"
> download.file(jpg_url,"presidents.jpg",mode = "wb")
试开URL’https://raw.githubusercontent.com/byaxb/RDataAnalytics/master/data/presidents.jpg\'
Error in download.file(jpg_url, "presidents.jpg", mode = "wb") :
无法打开URL\'https://raw.githubusercontent.com/byaxb/RDataAnalytics/master/data/presidents.jpg\'
此外: Warning message:
In download.file(jpg_url, "presidents.jpg", mode = "wb") :
InternetOpenUrl失败:’无法与服务器建立连接\'
> library(imager)
载入需要的程辑包:magrittr
载入程辑包:‘imager’
The following object is masked from ‘package:magrittr’:
add
The following objects are masked from ‘package:stats’:
convolve, spectrum
The following object is masked from ‘package:graphics’:
frame
The following object is masked from ‘package:base’:
save.image
> presidents <- load.image("presidents.jpg")
Error in wrap.url(file, load.image.internal) : File not found
> str(presidents)
\'cimg\' num [1:482, 1:345, 1, 1:3] 0.984 0.961 0.918 0.902 0.902 ...#z轴3个二维数组
#图像与数组,将第2,3个图层赋值为0
presidents[,,2] <- 0
presidents[,,3] <- 0
plot(presidents)
#只看绿色图层
presidents[,,1] <- 0
presidents[,,3] <- 0
plot(presidents)
#调色,都是对数组的操作
#黄色
presidents[,,3] <- 0
plot(presidents)
#加上马赛克,加一个噪声模糊处理
area_coor_x <- 350:449#100
area_coor_y <- 110:259#150
array_dim <- c(length(area_coor_x),length(area_coor_y),3)
array_data <- runif(prod(array_dim))#prod()表示相乘生成噪声,runif()表示均匀分布
randow_noise <- array(dim = array_dim,data = array_data)
presidents[area_coor_x,area_coor_y,] <- (1-0.6)*presidents[area_coor_x,area_coor_y,]+
0.6*randow_noise
plot(presidents)
7.5列表与数据框(1)
定义:列表是对象的有序集合,包含的对象又称为它的分量
列表是最为灵活,最具有包容性
对所包含的对象没有限制,可以是不同的类型、不同的长度
> #北京邮电大学下设以下学院
> xue_yuan <- c("信息与通信学院","电子工程学院","计算机学院","自动化学院","软件学院","数字媒体与设计艺术学院","现代邮政学院","网络空间安全学院","光电信息学院","理学院","经济管理学院",
+ "马克思主义学院","国际学院","网络教育学院","继续教育学院","民族教育学院")
> #拥有以下基地
> ji_di <- c(国家重点实验室=2,国家工程实验室=2,部级实验室=9)
> xiao_qu <- c("西土城路校区","沙河校区","宏福校区")#校区分布
> xue_sheng <- c(全日制=30000,非全日制=4500)#学生数量
> #变成一个整体,集合在一起
> bupt <- list(xue_yuan=xue_yuan,
+ xiao_qu=xiao_qu,
+ ji_di=ji_di,
+ xue_sheng=xue_sheng)
> #查看一些属性
> length(bupt)
[1] 4
> names(bupt)
[1] "xue_yuan" "xiao_qu" "ji_di" "xue_sheng"
> typeof(bupt)
[1] "list"
一些基本操作
> #访问列表子集¥
> bupt$xue_sheng
全日制 非全日制
30000 4500
> bupt$xue_sheng["全日制"]
全日制
30000
> sum(bupt$xue_sheng)
[1] 34500
> #通过[]来访问子集
> bupt[4]#提取的还是列表的形式
$xue_sheng
全日制 非全日制
30000 4500
> typeof(bupt[4])#单个[]看到的依然是包装箱
[1] "list"
> bupt[[4]] #双层[]才进入包装箱内部,看到组成部分
全日制 非全日制
30000 4500
> typeof(bupt[[4]])
[1] "double"
> sum(bupt[4])
Error in sum(bupt[4]) : \'type\'(list)参数不对
> sum(bupt[[4]])#正确的打开方式
[1] 34500
> bupt["xue_sheng"]
$xue_sheng
全日制 非全日制
30000 4500
————————————————————————————————————————————————————————————————————————————————————
> bupt[["bupt"]]
NULL
> sum(bupt[4])
Error in sum(bupt[4]) : \'type\'(list)参数不对
> sum(bupt[[4]])#正确的打开方式
[1] 34500
> bupt["xue_sheng"]
$xue_sheng
全日制 非全日制
30000 4500
> bupt[["xue_sheng"]]
全日制 非全日制
30000 4500
请发表评论