Basic Graphics
par() # 做一些全局设定
inipar <- par(no.randonly = T) # save
par(inipar) # recovery
par(mfrow = c(2, 3)) # make a figure. 2 rows 3 cols
png('pic.png')
加
加,意味着自己无法成图,需要在前面有图的基础上绘制
# lines
lines(x = 1:6, y = 2:7, col = 'blue') # 需要加线的点对
abline(a = 3, b = 2, col = 'green') # b, k
abline(v = 0, h = 3) # 1
# text
text(x = 3, y = 2.5, label = 'y = 3')
- 斜率为 0 当然也能画,但是无穷就表示不了了。而且前者只能画一根,后者可以画好几根
plot
plot(x = -1:6, # x 取值
y = 2*(-1:6), # y 取值
type = 'o', # 样式
family = 'serif', # 文字衬线
xlim = c(-5, 7), # x axim limits
ylim = c(-5,14), # y axim
ylab = 'y----', # y label
xlab = '----x', # x label
main = 'plot e.g.' # title
)
plot(iris$Petal.Length)
plot(cos, 0, 2*pi)
plot(dnorm, -3, 3,
col = "#cc0000",
lwd = 5
)
plot(mtcars$wt, mtcars$mpg,
pch = 19, # Solid circle
cex = 1.5, # Make 150% size
col = "#cc0000",
main = "MPG as a Function of Weight of Cars",
xlab = "Weight (in 1000 pounds)",
ylab = "MPG")
不仅可以展示 dataset 中的信息,还可以画普通图像
它会根据内容自己给我们判断适合用什么样的图,包括最后的散点图
Histogram
hist(iris$Sepal.Length)
par(mfrow = c(3,1)) # 更改参数,让一页多图
# par = parameter
# c = concatenate
hist(iris$Petal.Width [iris$Species == "setosa"],
xlim = c(0, 3),
breaks = 9,
main = "Petal Width for Setosa",
xlab = "",
col = "red")
# 这样仅仅只是来一遍,类似的来三遍,就能出三个了
par(mfrow = c(1, 1)) # 复原
Mosaic plot
ggplot2
Overlaying plot
hist(lynx,
breaks = 14, # "Suggests" 14 bins
freq = FALSE, # Axis shows density, not freq.
col = "thistle1", # Color for histogram
main = "Histogram of Annual Canadian LynxTrappings, 1821-1934",
xlab = "Number of Lynx Trapped")
# Add a normal distribution
curve(dnorm(x, mean = mean(lynx), sd = sd(lynx)),
col = "thistle4", # Color of curve
lwd = 2, # Line width of 2 pixels
add = TRUE) # Superimpose on previous graph
# Add two kernel density estimators
lines(density(lynx), col = "blue", lwd = 2)
lines(density(lynx, adjust = 3), col = "purple", lwd = 2)
# Add a rug plot
rug(lynx, lwd = 2, col = "gray")
Overlaying Plot 就是将两个图重叠,你要说为什么,应该就是让
summary(iris$Species)
describe() # in 'psych' package
对当前内容的一点总结,后者比前者要详细一点
Example
set.seed(432)
d0 <- data.frame(rs1 = sample(letters[1:4], 100, replace = T),
rs2 = sample(LETTERS[21:22], 100, replace = T))
barplot(1:5, names.arg = letters[1:5])
barplot(table(d0$rs1), main = 'barplot') # table 可以用计数
boxplot(len ~ supp, data = ToothGrowth) # table 可以用计数
hist(rnorm(1000), breaks = 15) # 分箱
# hist with density
d1 <- rnorm(1000)
hist(d1, breaks = 100, freq = F, main = 'Histogram')
lines(density(d1), col = 'blue', lwd = 2)
# draw normal distribution
d2 <- seq(min(d1), max(d1), len = 10000)
lines(d2, dnorm(d2), col = 'red', lwd = 2)
Selecting Cases (Variables)
使用 []
中加入判断语句来 select,单逻辑运算符
根据表现形式,可以猜到一个 var 后面一个 []
应该会返回一个子表,那么可以利用新增变量来存储子表:i.setosa <- iris[iris$Species == "setosa", ]
。⚠️ 注意这里 ,
是必须的,为什么以后再说,说是什么只选了一行,没指定列,如果想要全部的列,就 blank 就好
没错,R 语言的变量命名与赋值有些不同:
- 大小写敏感
- 数字和符号不能开头 (有点不一样)
- 可以用
.
来连接词 (很不一样) - 使用
<-
来赋值
Data Formats
n1 <- 15 # Default as double
n1 # 注意到 R 语言的解释,有些独特性,所以这句话直接返回值
typeof(n1)
l2 <- F # logical
Vector 和 Matrix
Vector
基本运算
v1 <- c(1, 2, 3, 4, 5) # 也可以是别的数据类型
is.vector(v1) # TRUE
(v1 + c(1, 2)) # 1
rev(v1)
- 长度不匹配,会
warning
,但是可以过,对应迭代加/乘
命名 & 添加
# name & append
x <- 1:3
names(x) <- LETTERS[1:3] # 注意到。names 返回的是一个向量对象
x['A'] # 命名之后就像 map 一样可以索引了
append(x, runif(3), after = 2)
为向量元素赋值
# assign
z <- 1:5
z[7] <- 8; z
z <- NULL
z[c(1, 3, 5)] <- 1:3; z
z[-c(1, 3)] # 真的去掉不变 NA,会往前补
特殊方法
z <- c(1, 2, NA) # 缺省
is.na(z) # 逐个判断是否缺省
z[is.na(z)] <- 0 # 缺省置 0
向量排序
z <- sample(1:100, 10)
order(z) # 排序后下标
z[order(z)] # 按下标提取
sort(z) # 直接排序,与上一样
Matrix
# matrix
m1 <- matrix(c(T, T, F, F, T, F), nrow = 2) # Default byrow = F
m2 <- matrix(c("a", "b",
"c", "d"),
nrow = 2, byrow = T) # 1
m3 <- matrix(1:20, 4, 5) # 4 rows 5 cols
x <- matrix(runif(20), 4, 5)
nrow(x); ncol(x); dim(x) # 行列数,dim 返回 4 5 向量
x[c(2, 1), ] # 第二行摆在新一
x[, c(1, 3)]
x[2, 1] # located
x[x[ , 1] < 0.5, 1] # 第一列小于 .5 的
x[-2, -c(1, 3)] # 去掉第二行,第一列,第三列
x <- matrix(1:30, 5, 6)
y <- matrix(rnorm(20), 4, 5)
y %*% x # 矩阵乘法
apply(x, 1, mean) # rows mean. sum, prod
x <- matrix(1:12, nrow = 3,
dimnames = list(c("I", "II", "III"), # 用列表给矩阵行列名字
paste("X", 1:4, sep = "-")))
x <- rnorm(10)
all(x > 0); all(x != 0); any(x > 0) # 都...吗,有...吗
(1:10)[x > 0] # 2
x <- sample(1:7, 5, rep = T)
unique(x) # 去重
- 这里
byrow = T
才是我直观的生成样子,但是默认是F
- 所以说 R 语言没有理由啊,重载的东西太多了。x 中大于 0 的位置
Array
# array
# 1 through 24. rows cols tables
a1 <- array(1:24, c(4, 3, 2)) # 貌似没有 byrow 参数
Data Frame
一列一列为单位 (这也是为什么只有列可以指定因子,索引也只索引得出列)
也是多种数据,基本构建和 List 很像
# data frame
vNumeric <- c(1, 2, 3)
vCharacter <- c("a", "b", "c")
vLogical <- c(T, F, T)
dfa <- cbind(vNumeric, vCharacter, vLogical) # 1
df <- as.data.frame(cbind(vNumeric, vCharacter, vLogical)) # 2
df2 <- cbind.data.frame(vNumeric, vCharacter, vLogical) # 3
df$vNumeric # 4
x <- matrix(1:6, 2, 3)
df3 <- as.data.frame(x)
attributes(df3)
names(df3) <- c("TOYOTA","GM","HUNDA") # 这个有点奇怪
row.names(df3) <- c("2001","2002") # 这个是真能改
attach(df3); detach(df3) # using namespace
- 使用
cbind()
会让所有数据强制类型转换 - 意思是
cbind()
并不是会强制变咯?只是直接用会变?那么问题是发生在赋值过程的吗 - 我天,这两句话单独打印看看是一样的,但是用
$
出来看是不一样的!感受上还是使用cbind.data.frame()
好! $
貌似是专门用在 data frame 中的
List
内容可以是不同的
# list
o1 <- c(1, 2, 3)
o2 <- c("a", "b", "c", "d")
o3 <- c(T, F, T, T, F)
list1 <- list(o1 = o1, o2, o3) # 只有指定名称才能用 $ 和名称
list1$o1 # 深层索引
list1[['o1']]
list1[[1]]
list1['o1'] # 浅层列表索引
list1[1]
unlist(list1) # 将列表变为向量,带名称 (没名字的就没名字)
Type Conversions
coerce3 <- as.integer(5)
coerce4 <- c("1", "2", "3") # 虽然是三对引号,但是是 character
coerce5 <- as.numeric(c("1", "2", "3")) # 成三个 double 了
coerce6 <- matrix(1:9, nrow = 3)
coerce7 <- as.data.frame(matrix(1:9, nrow = 3))
# 虽然看起来一样,但是是不同的数据类型
⚠️ 注意,在整个语句外面加一个括号会同时在终端打印 (因为被视作一个表达式)
Factor
可以在构建的时候指定为 factor,也可以给已存在的变量重新赋值为 factor
如果指定 factor,它总会是 integer,但是会显示它的 label
注意到,我用 $
解引用的时候,并不是像 java 一样有“指针进去啦,外面改,里面也改”,R 语言里面不改,但是用同一个名字来解析。如果我真的是用临时变量,那就要用引号表示名字。$
和 [[]]
好像是对等的
Entering Data
x <- c(1, 2, 3) # 读作 get
assign("x", c(1, 2, 3)) # 名字纯以字符串的形式表示
:
, go through. 两边闭区间!?
, like man
seq() # means sequences
seq(10) # 1-10
seq(1, 10, .01) # seq(30, 0, by = -3)
seq(-1, 10, len = 100) # seq(-1, 10, length = 100)
seq(2, by = 3, length = 4)
c()
, means concatenate (or combine or collect).c(1:4, 6:7)
, skip 5scan()
. twice enter to exit
rep() # means repetition
rep(c(T, F), 5) # 并不是二维
rep(c(T, F), each = 5) # 是依次重复v
rep(3:5, 1:3) # 3 4 4 5 5 5
Importing Data
推荐使用 rio
package
View(rio_csv)
r_txt2 <- read.table("./mbb.txt", header = T, sep = "\t")
trends.csv <- read.csv("./mbb.csv", header = T)
rawdata <- read.table(file.choose(), header = T, sep = ",")
readxl
data1 <- read_excel(file.choose())
excel_sheets(file.choose()) # 返回工作簿中工作表的向量
# 批量读取
files <- list.files("./derectory/")
paths <- paste("./derectory/", files, sep = "") # 1
- 字符串操作,这就是所谓的基于向量运算!
Handling Data
dplyr
不太知道里头有些操作为什么要用这些,明明 data frame 也做得到啊。感觉就是还是图个方便,封装起来
library(dplyr)
t2 <- filter(ToothGrowth, nv %in% 1:50, nv2 == 'H') # and 1
summarize(ToothGrowth, len_max = max(len)) # 2
summarize(group_by(ToothGrowth, supp), len_max = max(len)) # 3
- 用
[]
在 data frame 也是可以做到的,无非稍微繁琐一点,不过细节是,每一行的标号结果不一样 - 新一个新的 data frame,
len_max
是自己指定名称 group_by
对 ToothGrowth 按 supp 分组,然后向量运算。参数多的时候就是划分的加细
# pipe
# 简单来讲就是把左边的送给右边做第一个参数
# 适合函数嵌套的时候使用
# left_joint. 以第一个参数为基准,第二个参数中根据 by 找可以连接的
df1 %>% left_joint(df2, by = c('c2' == 'c3'))
# right_joint.
# full_joint. 无基准,有的都有,有 by 的合并
# inner_joint. 无基准,没得都没
tidyr
列的分裂与合并
# 分裂
df4 <- df3 %>%
separate(col = c5, sep = '-', into = c('c7', 'c8'), remove = F) %>%
separate(col = c6, sep = '\\.', into = c('c9', 'c10'), remove = T)
# 合并
df4 <- df3 %>%
unite(col = 'c11', c('c7', 'c8'), sep = '-', remove = F) # 可能是新列所以字符串
长宽数据转换
# 宽数据 -> 长数据
df6 <- df5 %>% # 1
pivot_longer(cols = -c(1:2), names_to = 'varb', values_to = 'value')
# 长数据 -> 宽数据
df6 <- df5 %>% # 2
pivot_wider(names_from = c(area, varb), values_from = value)
- “长”我想意思就是把原本是列的东西变成值,所以一条数据会分裂成都个数据,数据量增加,变长
names_from
可以来源于多个数据 (利用划分的加细),然后座位新的列因子,值再来源于一个就行了
Hierarchical Clustering
Principal Components
Less is More. That is, less noise and fewer unhelpful variables in data = more meaning.
aka Dimensionality Reduction
Principal Components Analysis (PCA):
- Two variables.
- Regression(回归)
- Perpendicular distance
- Collapse
- Rotate
Went from 2D to 1D but maintained the most important information.
Regression
Out of many, one.
Function
oddcount <- function (v, s="Default") {
cnt <- 0
for(i in v) {
if(i %% 2 == 1) cnt <- cnt + 1
}
print(s)
(x <- 1)
}
oddcount(1:10)
函数可以没有 return
此时最后一个值为返回值。⚠️ R 里要加上括号才算返回值
Syntax
ifelse() # accelerate running speed