732A99 Block 1 · R cheatsheet
为 Fan Wenlin 整理,2026-11-10(瑞典时间)。正文中文,R 名称和术语保留英文。 来源和标记: 📌 = Lisam slides(文件名 + PDF 页码;slides 在 Lisam 上,这里只给出处,不附文件); 📝 = 课程公开 R tutorials:Tut1、Tut2(Ex = Exercise 编号); ⚠️ = slides 和 tutorials 里都没有,是包的标准用法,具体以 lab 说明为准。 代码里的
data、train、y等都是占位名。
1. 课程约定(先看这一节)
1.1 set.seed(12345)
slides 原话:"Use set.seed(12345) in the labs to get identical results" 📌 Lecture 1a block 1.pdf p.26、Lecture 2a block 1.pdf p.20、Lecture 1c block 1.pdf p.25
set.seed(12345) # 函数名 set.seed,数字是五位 12345
- 小提醒:你记的是
seed.set(123456),正确写法是set.seed(先 set 后 seed),数字是12345(1 到 5,五位)。seed.set()会直接报错could not find function;但数字写错不会报错,只是结果和别人对不上,所以更要留意数字。 - 如果某道题明确指定了别的 seed,就按题目来。比如 Tut1 Prob. Ex1 写的是 "use seed 123",答案就用
set.seed(123)📝 Tut1 Prob. Ex1。 - 什么时候调用: 在每一个用到随机数的调用之前紧挨着调用一次:
| 情况 | 要不要 set.seed(12345) |
来源 |
|---|---|---|
sample() 划分数据 |
要,每次 sample 前都调用一次(三段划分里调用两次) |
📌 Lecture 1a block 1.pdf p.26 |
cv.tree()(随机分 fold) |
要,slides 在 cv.tree 前又调用了一次 |
📌 Lecture 2b block 1.pdf p.26 |
cv.glmnet()(随机分 fold) |
要 | ⚠️ 原理同上 |
cvFit()(foldType="random" 时) |
要,或者传 seed= 参数 |
⚠️(slides 用的是 consecutive,不需要随机数)📌 Lecture 2a block 1.pdf p.34 |
rnorm/runif/... 模拟数据 |
要 | 📌 Lecture 1c block 1.pdf p.25 |
neuralnet() 初始权重、fastICA() 初始矩阵、kmeans() |
要 | ⚠️ |
lm、glm、tree(不剪枝)、prcomp、glmnet(固定 λ)、optim |
不需要(确定性算法) |
- 坑: 先
set.seed再中间插一句别的随机调用(比如先sample了一下看看数据),后面的结果就全变了。所以要"紧挨着"。另外,R 3.6.0 起sample()的默认算法改了,非常老的 R 版本得到的划分会不一样。
1.2 数据划分(照抄 slides 的写法)
train/test = 70/30 📌 Lecture 1a block 1.pdf p.26、Lecture 2a block 1.pdf p.20
n=dim(data)[1]
set.seed(12345)
id=sample(1:n, floor(n*0.7))
train=data[id,]
test=data[-id,]
train/valid/test = 40/30/30 📌 Lecture 1a block 1.pdf p.26、Lecture 2a block 1.pdf p.20
n=dim(data)[1]
set.seed(12345)
id=sample(1:n, floor(n*0.4))
train=data[id,]
id1=setdiff(1:n, id)
set.seed(12345)
id2=sample(id1, floor(n*0.3))
valid=data[id2,]
id3=setdiff(id1,id2)
test=data[id3,]
- 50/50 划分的写法一样,只是比例换成
0.5。1c 用dim(data)[1],1d 用nrow(data),两者等价 📌 Lecture 1c block 1.pdf p.31、Lecture 1d block 1.pdf p.16。 - 坑 1: 第二次
sample前也要set.seed(12345),漏掉的话 valid/test 就和标准答案对不上。 - 坑 2: 第二次是
sample(id1, ...),从剩下的下标里抽,不是sample(1:n, ...)。valid 的大小是floor(n*0.3),按总 n 计算。 - 坑 3:
id1只有一个元素时,sample(id1, k)会被当成sample(1:id1, k)。真实数据集一般碰不到。 - 坑 4:
data[id,]的逗号不能漏;data[id]取的是列。
1.3 误差函数与 confusion matrix
📌 误差定义见 Lecture 1a block 1.pdf p.27;table 和 diag 见 Lecture 1c block 1.pdf p.16;missclass 函数见 Lecture 1c block 1.pdf p.31
mse = function(y, yhat) mean((y - yhat)^2)
missclass=function(X,X1){ # slides 原样
n=length(X)
return(1-sum(diag(table(X,X1)))/n)
}
cm = table(test$y, pred) # 行 = 真实值,列 = 预测值
# cross-entropy(p 是 n×M 的概率矩阵,列顺序和 levels(y) 一致)
ce = -sum(log(pmax(p[cbind(1:n, as.integer(y))], 1e-15))) # pmax 防止 log(0) = -Inf
- 坑: 如果某个类从来没被预测到,
table会少一列,变成非方阵,diag就会算错。稳妥写法是pred=factor(pred, levels=levels(y)),或者直接用mean(y != pred)。 - TPR、FPR、precision、recall(把第 1 行和第 1 列当 positive)📝 Tut2 Ex4
tab=table(y, pred); TP=tab[1,1]; FN=tab[1,2]; FP=tab[2,1]; TN=tab[2,2]
TPR=TP/(TP+FN); FPR=FP/(FP+TN); prec=TP/(TP+FP)
- ROC 曲线:对一串阈值
r重复上面的计算,再用plot(FPR, TPR, type="l")画出来。slides 的分类评估部分讲了原理 📌 Lecture 2a block 1.pdf p.35–39。
1.4 Scaling:只在 train 上 fit
📌 Lecture 1d block 1.pdf p.15–16、Lecture 2d block 1.pdf p.17;📝 Tut1 Prob. Ex8
library(caret)
scaler=preProcess(train) # 默认 method=c("center","scale")
trainS=predict(scaler,train)
validS=predict(scaler,valid) # 用 train 的均值和方差
testS=predict(scaler,test)
- slides 原话:"Same transformation on train, valid and test data – Never scale these separately" 📌 Lecture 1d block 1.pdf p.15
- 坑 1:
preProcess只处理 numeric 列,factor 和 character 列会原样保留。如果 response 也是 numeric,它也会被标准化。slides 1d 的例子就把Price一起标准化了 📌 Lecture 1d block 1.pdf p.16,所以预测值也在标准化之后的尺度上。需要原尺度时,要么在preProcess之前把 response 列去掉,要么自己做反变换。 - 坑 2: 2d 的例子先在全部数据上
preProcess,再取 covariates 📌 Lecture 2d block 1.pdf p.17。那只是为了演示 glmnet 的路径图;lab 里有 train/test 时,要按 1d 的规则只用 train 来 fit。 - 不用 caret 的写法:
scale(train)会把中心和尺度存在attr(, "scaled:center")和attr(, "scaled:scale")里,然后对 test 用scale(test, center=..., scale=...)。
2. 课程里用到的函数和包
2.1 lm:线性回归
📌 Lecture 1c block 1.pdf p.26、Lecture 1d block 1.pdf p.11–14、Lecture 1d block 1.pdf p.16;📝 Tut1 Prob. Ex6
fit=lm(Price~Year+Mileage+Equipment, data=train) # 也可以写 y~. 表示用所有其他列
summary(fit); coef(fit); confint(fit, level=0.95)
fitted(fit); residuals(fit)
pred=predict(fit, newdata=test)
ci=predict(fit, newdata=test, interval="confidence") # 列名 fit/lwr/upr
pi=predict(fit, newdata=test, interval="prediction")
mean((test$Price-pred)^2) # test MSE
- 关键参数:
formula、data、subset、weights📌 Lecture 1d block 1.pdf p.11。查帮助用?predict.lm,即"函数名.类名"📌 Lecture 1d block 1.pdf p.11、Lecture 1c block 1.pdf p.26。 - 坑 1: 不写
newdata,predict返回的是训练集上的拟合值。 - 坑 2:
newdata的列名必须和 formula 里的一样。 - 坑 3:
interval="confidence"是均值的区间,"prediction"是新观测的区间,后者更宽。 - 手算 OLS:
solve(t(X)%*%X, t(X)%*%y)。要记得给X加一列 1 作为 intercept 📝 Tut1 Ex8(Basic manipulation)📌 Lecture 1d block 1.pdf p.9。 - slides 画置信带时用了
attach(mydata)和detach📌 Lecture 1d block 1.pdf p.14。这样容易和全局变量混淆,建议改成mydata$Year。
2.2 glm:logistic regression;nnet::multinom:多类
📌 Lecture 1d block 1.pdf p.33;📝 Tut1 Prob. Ex9、Tut2 Ex2
m=glm(y~., data=train, family="binomial") # y 必须是两类的 factor(或 0/1)
p=predict(m, newdata=test, type="response") # 概率,对应 levels(y)[2]
pred=ifelse(p>0.5, levels(train$y)[2], levels(train$y)[1])
table(test$y, pred)
library(nnet) # 多于两类时
mm=multinom(y~., data=train)
predict(mm, newdata=test, type="class") # 或 type="probs"
- 坑 1:
predict.glm默认type="link",返回的是 \(\theta^Tx\)(log-odds),不是概率。要概率必须写type="response"📌 Lecture 1d block 1.pdf p.33。 - 坑 2: 返回的是
levels(y)里第二个类的概率,比如 crabs 的"F","M"得到的是 P(M) 📝 Tut2 Ex2。factor 的 levels 默认按字母排序。 - 坑 3: 如果 y 是 character,要先
as.factor()。R ≥ 4.0 的read.csv不会自动把字符列转成 factor。 - 阈值 r 和 loss matrix: 阈值不一定是 0.5 📌 Lecture 1d block 1.pdf p.28–29。按 Tut2 Ex2 的 loss matrix 写判决:
ifelse(pF/pM > 3/2, "F", "M")。多类时的写法:Losses=Probs%*%L; apply(Losses,1,which.min)📝 Tut2 Ex2。
2.3 optim:数值优化(MLE、自定义 loss)
📌 Lecture 1d block 1.pdf p.34、Lecture 2d block 1.pdf p.32–33;📝 Tut1 Prob. Ex11、Tut2 Ex10
df=data.frame(x1=1,x2=2)
mylikelihood<-function(x){ # 参数打包成一个向量 x
x1=x[1]; x2=x[2]
return((x1-df$x1)^2+(x2-df$x2)^2)
}
res=optim(c(0,0), fn=mylikelihood, method="BFGS")
res$par; res$value; res$counts; res$convergence # convergence 为 0 表示收敛
- 关键参数:
par(初值)、fn、gr(梯度,可选;不给就用数值差分)、method("Nelder-Mead" 是默认值,还有 "BFGS"、"CG"、"L-BFGS-B"、"Brent")、control=list(maxit=..., fnscale=-1)📌 Lecture 2d block 1.pdf p.32。 - 坑 1:
optim默认做最小化。最大化 log-likelihood 时,要么传 minus log-likelihood(📝 Tut1 Prob. Ex5),要么设control=list(fnscale=-1)。 - 坑 2: 1 维问题用默认的 Nelder-Mead 会给 warning,改用
"BFGS",或者用"Brent"并给出lower/upper。 - 坑 3:
fn只能接收一个向量参数。像 Tut1 那样写成function(w, w0)的,要包一层:function(p) loglik(p[1], p[2])。 - 记录迭代过程(slides 的 workaround,lab 里画 trace 或者做 early stopping 会用到)📌 Lecture 2d block 1.pdf p.33
Fs=list(); Params=list(); k=0
myf<- function(x){
f=(x[1]-2)^4+(x[2]-4)^4
.GlobalEnv$k= .GlobalEnv$k+1
.GlobalEnv$Fs[[k]]=f
.GlobalEnv$Params[[k]]=x
return(f)
}
myGrad <-function(x) c(4*(x[1]-2)^3, 4*(x[2]-4)^3)
res<-optim(c(0,0), fn=myf, gr=myGrad, method="BFGS")
plot(log(as.numeric(Fs)), type="l", main="Function iterations")
- 坑: 每次重跑之前都要把
k=0、Fs=list()重置,否则会接着上次的记录累加。另外 BFGS 做线搜索时也会调用fn,所以记下的是"函数调用次数",不是迭代次数。early stopping 的例子里,同样在fn里顺便记下 test error 📝 Tut2 Ex10、📌 Lecture 2d block 1.pdf p.34。
2.4 kknn:k-NN
slides 只讲 k-NN 的原理 📌 Lecture 1a block 1.pdf p.15–20,R 用法来自 📝 Tut1 Prob. Ex10
library(kknn)
m=kknn(as.factor(y)~., train=train, test=test, k=10, kernel="rectangular")
pred=m$fitted.values # 预测的类
prob=m$prob # 每个类的概率(n_test × 类数)
table(test$y, pred)
- 关键参数:
k(默认 7)、kernel(默认 "optimal",标准 k-NN 用"rectangular")、distance(Minkowski 距离的 p,默认 2)、scale(默认 TRUE,会按 train 的标准差缩放)。 - 坑 1:
kknn没有 "fit 之后再 predict" 这一步:每次都要同时传train和test。想看训练误差,就把test=train也传进去 📝 Tut1 Prob. Ex10。 - 坑 2: 不写
kernel="rectangular"就不是教科书上的多数投票。 - 坑 3: y 要先转成 factor,否则做的是 kNN regression。
- 选 k:在 valid 上对
k in 1:30循环,画出 train 和 valid 的误差曲线,用 misclassification 或 cross-entropy 都可以 📌 Lecture 1a block 1.pdf p.21–25;k-NN 前要 scale 📌 Lecture 1a block 1.pdf p.20。
2.5 cvTools:K-fold CV 选模型
📌 Lecture 2a block 1.pdf p.34
library(cvTools)
fit1=lm(V9~V3+V4+V5+V6+V7+V8, data=data)
f1=cvFit(fit1, y=data$V9, data=data, K=10, foldType="consecutive")
# f2、f3 类似
res=cvSelect(f1,f2,f3); plot(res)
- 关键参数:
K(默认 5)、foldType("random" 默认、"consecutive"、"interleaved")、R(重复次数)、seed、cost(默认rmspe,即 root MSE)。 - 坑: 默认
foldType="random",这时不设 seed 每次结果都不同。slides 用的"consecutive"是按行顺序切的,如果数据本身按某种顺序排列,就会有偏差。 - 自己写 CV 也只有几行:
folds=sample(rep(1:K, length.out=n)),然后对i in 1:K依次拟合和预测 📌 Lecture 2a block 1.pdf p.21。
2.6 tree:决策树和 pruning
📌 Lecture 2b block 1.pdf p.23–28;📝 Tut2 Ex3–6
library(tree)
fit=tree(class~., data=train) # 分类树要求 class 是 factor
plot(fit); text(fit, pretty=0)
fit; summary(fit) # 叶子数、用到的变量、misclass rate
Yfit=predict(fit, newdata=valid, type="class")
table(valid$class,Yfit)
- 关键参数:
split=c("deviance","gini");control=tree.control(nobs=nrow(train), mincut=5, minsize=10, mindev=0.01),可以控制叶子大小 📌 Lecture 2b block 1.pdf p.23–24,例如minsize=40📝 Tut2 Ex3。 predict的type:"vector"(默认,分类时返回概率矩阵)、"class"、"tree"(返回一个树对象,可以用deviance()算 valid 上的 deviance)📌 Lecture 2b block 1.pdf p.27。- 选叶子数:用 CV 📌 Lecture 2b block 1.pdf p.26
set.seed(12345)
cv.res=cv.tree(fit)
plot(cv.res$size, cv.res$dev, type="b", col="red")
best=cv.res$size[which.min(cv.res$dev)] # 📝 Tut2 Ex6
- 选叶子数:用 train/valid(slides 的循环)📌 Lecture 2b block 1.pdf p.27–28
trainScore=rep(0,9); testScore=rep(0,9)
for(i in 2:9) {
prunedTree=prune.tree(fit,best=i)
pred=predict(prunedTree, newdata=valid, type="tree")
trainScore[i]=deviance(prunedTree)
testScore[i]=deviance(pred)
}
plot(2:9, trainScore[2:9], type="b", col="red", ylim=c(0,250))
points(2:9, testScore[2:9], type="b", col="blue")
finalTree=prune.tree(fit, best=5)
- 坑 1: response 是 numeric 时,
tree会建回归树,而且不报错。response 是 character 时,只给一个 "NAs introduced by coercion" 的 warning,然后返回只有根节点的树(singlenode)。分类前务必as.factor()。 - 坑 2:
trainScore[1]一直是 0,所以画图时要从 2 开始,slides 用的是2:9。 - 坑 3:
prune.tree(best=i)在剪枝序列里没有恰好 i 个叶子的子树时,会悄悄返回比 i 大的下一个子树,不会报错,也没有 warning。用summary(prunedTree)$size确认实际叶子数。 - 坑 4: 训练集和验证集大小不同,直接比较 deviance 不公平。需要比较时可以除以 n。
- 坑 5:
cv.tree默认K=10,按 deviance 剪枝。想按误分类率剪,用cv.tree(fit, FUN=prune.misclass)⚠️。 - 换一个 loss matrix 或阈值时,用
predict(fit, newdata)得到概率矩阵后,自己写ifelse判决 📝 Tut2 Ex4。
2.7 prcomp / princomp:PCA
📌 Lecture 2c block 1.pdf p.22–24;📝 Tut2 Ex7
data1=mydata; data1$Fat=c() # 去掉 response 列
res=prcomp(data1) # 默认 center=TRUE, scale.=FALSE
lambda=res$sdev^2 # eigenvalues
sprintf("%2.3f",lambda/sum(lambda)*100) # 每个 PC 解释的方差(%)
cumsum(lambda)/sum(lambda) # 累计比例,用来决定要几个 PC
screeplot(res); biplot(res)
U=res$rotation # loadings(p×p,每列是一个 PC)
plot(res$x[,1], res$x[,2]) # scores:数据在 PC1、PC2 上的坐标
plot(U[,1], main="Traceplot, PC1") # 哪些原始变量对 PC1 贡献大
- 坑 1:
prcomp默认不做 scale。变量单位不同时要写prcomp(X, scale.=TRUE),或者先scale()。slides 的 tecator 光谱数据单位相同,所以没有 scale;要不要 scale 见 📌 Lecture 2c block 1.pdf p.17。 - 坑 2: 每个 PC 的符号不唯一,和别人比较时 loadings 可能整体差一个负号,这是正常的。
- 坑 3: 用
res$x和res$rotation;princomp对应的是$scores和$loadings。princomp的协方差用 n 作除数,prcomp用 n−1,所以数值会略有不同 📝 Tut2 Ex7。 - 用前 q 个 PC 重构数据:
Z=res$x[,1:q]; Xhat=Z%*%t(U[,1:q]),再把每列的均值加回去 📝 Tut2 Ex7 📌 Lecture 2c block 1.pdf p.20。 - 手算 PCA:
e=eigen(cov(scale(X, scale=FALSE))),e$values是特征值,e$vectors是特征向量 📌 Lecture 2c block 1.pdf p.9–10。
2.8 glmnet / cv.glmnet:ridge 和 LASSO
📌 Lecture 2d block 1.pdf p.17–22;📝 Tut2 Ex8–9
library(glmnet)
x=as.matrix(train[,1:6]); y=train[,7]
model0=glmnet(x, y, alpha=0, family="gaussian") # alpha=0:ridge;alpha=1:LASSO
plot(model0, xvar="lambda", label=TRUE) # 系数路径
set.seed(12345)
model=cv.glmnet(x, y, alpha=1, family="gaussian")
model$lambda.min; plot(model)
coef(model, s="lambda.min")
ynew=predict(model, newx=as.matrix(test[,1:6]), s="lambda.min", type="response")
- 关键参数:
alpha(📌 Lecture 2d block 1.pdf p.17、Lecture 2d block 1.pdf p.22)、family("gaussian"、"binomial"、"multinomial"、"poisson")、lambda(可以自己给一串值,例如 slides 的seq(0,1,0.001)📌 Lecture 2d block 1.pdf p.19)、nfolds(默认 10)、standardize(默认 TRUE)。 - 坑 1:
x必须是 matrix,所以要as.matrix(...),不能直接传 data.frame。有 factor 变量时,先用model.matrix(~.,data)[,-1]展开。 - 坑 2:
predict和coef作用在 cv.glmnet 对象上时,默认s="lambda.1se",不是lambda.min。slides p.19 的predict没写s,所以用的是 1se 📌 Lecture 2d block 1.pdf p.19。想用最优 λ 就显式写s="lambda.min"。 - 坑 3:
cv.glmnet的 fold 是随机分的,要先set.seed。 - 坑 4: glmnet 的目标函数是 \(\frac{1}{2n}\text{RSS}+\lambda[\frac{1-\alpha}{2}\|\theta\|_2^2+\alpha\|\theta\|_1]\),它的 λ 和 slides、教科书里的 λ 差一个常数因子,不要直接对比数值。
- 选出了几个变量:
sum(coef(model, s="lambda.min")[-1] != 0)📝 Tut2 Ex8 📌 Lecture 2d block 1.pdf p.22。 - 分类:
family="binomial",配合predict(..., type="class")。
3. ⚠️ slides 和公开 tutorials 都没有给 R 代码的部分
Topic 3 的 3a–3d slides(kernel、SVM、NN)里完全没有 R 代码,2c 讲 ICA 也没有给代码 📌 Lecture 2c block 1.pdf p.26–28。下面是这些包的标准写法,lab 真正要求用哪个包、哪些参数,以 lab 说明为准。
3.1 kernel 方法手写(3a)
📌 Lecture3aBlock12021.pdf p.19–26,slides 9–10/15
gauss=function(u) exp(-u^2) # 也可以换成别的 kernel
kreg=function(x0, x, y, h) { # Nadaraya–Watson(1 维)
w=gauss((x-x0)/h); sum(w*y)/sum(w)
}
yhat=sapply(xgrid, kreg, x=train$x, y=train$y, h=0.5)
K=exp(-as.matrix(dist(X))^2/(2*s^2)) # Gaussian Gram matrix
- 坑: 多维时要先把各变量 scale 到同一尺度,再计算距离。h 太小会 overfit,太大会 underfit,用 validation 来选 📌 Lecture3aBlock12021.pdf p.19–22,slide 9/15。
3.2 kernlab::ksvm:SVM 和 SVR(3b)
library(kernlab)
m=ksvm(y~., data=train, type="C-svc", kernel="rbfdot", kpar=list(sigma=0.05), C=1, scaled=TRUE)
pred=predict(m, newdata=test) # 分类结果
m@nSV; alphaindex(m) # support vector 数量和下标
r=ksvm(y~., data=train, type="eps-svr", epsilon=0.1, C=1) # SVR
- 坑 1:
rbfdot的定义是 \(\exp(-\sigma\|x-x'\|^2)\),这里的sigma不是标准差。 - 坑 2: 默认
kpar="automatic"时会用随机抽样来估计 sigma,要先set.seed,或者直接给定 sigma。 - 坑 3: 分类时 y 必须是 factor,否则
ksvm会按回归来做。 - C 相当于 slides 里的 \(1/(2n\lambda)\):C 越大,正则化越弱 📌 Lecture3bBlock12021.pdf p.14–22,slides 7–10/11。
3.3 neuralnet:MLP(3c)
library(neuralnet)
set.seed(12345) # 初始权重是随机的
nn=neuralnet(y~x1+x2, data=train, hidden=c(10), act.fct="logistic", linear.output=TRUE)
plot(nn); pred=predict(nn, newdata=test) # 也可以用 compute(nn, test)$net.result
- 关键参数:
hidden(每层的单元数)、act.fct、linear.output(回归用 TRUE,分类用 FALSE)、threshold(默认 0.01)、stepmax(默认 1e5)、startweights。 - 坑 1: 出现 "did not converge" 时,可以调大
stepmax或threshold,或者先 scale 输入。 - 坑 2: 自定义的
act.fct必须能被符号求导(neuralnet 1.44 用的是Deriv包)。实测function(x) max(0,x)和pmax(0,x)都会报错,而function(x) ifelse(x>0,x,0)和 softplusfunction(x) log(1+exp(x))都能运行。 - 坑 3: 旧版本不支持
y~.,稳妥起见把变量写全。
3.4 fastICA:ICA(2c)
library(fastICA)
set.seed(12345) # 初始化 W 用了随机数
ica=fastICA(X, n.comp=2) # 默认 fun="logcosh"
ica$S # 估计出的独立成分
ica$A; ica$W; ica$K # mixing、unmixing、pre-whitening 矩阵
- 坑: ICA 的成分顺序和符号都不唯一 📌 Lecture 2c block 1.pdf p.28。
4. 通用 R 基础(lab 常用)
4.1 帮助、赋值、向量
📌 Lecture 1c block 1.pdf p.5–9
?lm; args(glm); example(sample) # 查帮助
a<-3; a=3 # 赋值:<- 和 = 都可以
x=c(1,3); y=numeric(10); s=seq(0,1,by=0.1); 1:10
length(x); sum(x); which.max(x); order(x); rev(sort(x))
- R 区分大小写,下标从 1 开始,
x[-1]是"去掉第一个元素",不是取最后一个。
4.2 matrix 和线性代数
📌 Lecture 1c block 1.pdf p.10–15
A=matrix(1:6, nrow=2) # 按列填充;要按行填就加 byrow=TRUE
t(A); A%*%B; solve(A); solve(A,b); diag(A); crossprod(X) # crossprod(X) = t(X)%*%X
dim(A); nrow(A); ncol(A); colMeans(A); rowSums(A)
cbind(1, X) # 加一列 intercept
- 坑:
A*B是逐元素乘法,矩阵乘法要写%*%。取单列时,用X[, j, drop=FALSE]保持 matrix 形状 📝 Tut1 Ex8。
4.3 data.frame、索引、factor
📌 Lecture 1c block 1.pdf p.17–22;📝 Tut1 Basic manipulation Ex1–9
df=data.frame(X=c(1,2), Y=c("M","F"))
df$Y; df[ ,"Y"]; df[1, ]; df[df$X>1 & df$Y=="M", 2:3]
df$new=log(df$X); df$X=c() # 新增一列 / 删除一列
colnames(df)[1]="ID"; str(df); summary(df); head(df)
df$Y=as.factor(df$Y); levels(df$Y)
as.numeric(as.character(f)) # factor → 数字,必须先转 character
X=as.matrix(df[, -7]) # 去掉第 7 列,再转成 matrix
- 坑: 直接
as.numeric(factor)得到的是 level 的编号,不是原来的值 📌 Lecture 1c block 1.pdf p.22。
4.4 读写 CSV
📌 Lecture 1c block 1.pdf p.21;📝 Tut1 Data Ex1–4
d=read.csv("file.csv") # 逗号分隔,小数点用 .
d=read.csv2("file.csv") # 分号分隔,小数点用 ,(瑞典 Excel 常见)
d=read.csv("machine.csv", header=FALSE) # 没有表头时,列名是 V1, V2, ... 📌 <span class="cite">Lecture 2a block 1.pdf p.34</span>
library(readxl); d=read_excel("tecator.xls") # 读 Excel
write.csv(d, "out.csv", row.names=FALSE)
- 坑 1: 读进来的所有列都变成 character,或者数字明显不对,多半是该用
read.csv2(或反过来)。slides 1d 和 2c 用的就是read.csv2📌 Lecture 1d block 1.pdf p.12、Lecture 2c block 1.pdf p.22。 - 坑 2: 先
setwd(),或者在 RStudio 里设置工作目录(Session → Set Working Directory)📌 Lecture 1c block 1.pdf p.21。
4.5 apply 家族、循环、函数
📌 Lecture 1c block 1.pdf p.15、Lecture 1c block 1.pdf p.23–27;📝 Tut1 Ex7、Ex10
apply(M, 1, function(r) sum(r^2)) # 1 = 按行,2 = 按列
sapply(1:30, function(k) err(k)) # 返回 vector
lapply(lst, f) # 返回 list
for (i in 1:10) { ... }; while (cond) { ... }
if (x==3) { ... } else { ... }
f=function(a, b=2){ a+b } # 最后一个表达式的值就是返回值
- 用字符串拼 formula:
lm(as.formula(paste0("Fat~Channel", i)), data=d)📝 Tut1 Ex10。
4.6 画图
📌 Lecture 1c block 1.pdf p.28–30
plot(x, y, type="p", col="blue", main="title", xlab="x", ylab="y", ylim=c(0,1))
points(x, y2, col="red"); lines(x, fit, lty="dotted") # 往已有的图上加
hist(x); barplot(v, names.arg=nm, horiz=TRUE, las=1)
legend("topright", legend=c("train","valid"), col=c("red","blue"), lty=1)
par(mfrow=c(1,2)) # 一页并排放两张图
- 坑:
points和lines会沿用第一次plot设定的坐标范围,所以第一次plot时就要用ylim留够空间 📌 Lecture 2b block 1.pdf p.27。 - 回归画线之前要先对 x 排序:
o=order(x); lines(x[o], fit[o])。
4.7 随机数和分布
📌 Lecture 1c block 1.pdf p.25;📝 Tut1 Prob. Ex1–4
rnorm(5, mean=5, sd=0.1); runif(3); sample(n, 5, replace=FALSE)
dnorm(0); pnorm(1.96); qnorm(0.975) # d = 密度, p = CDF, q = 分位数, r = 抽样
4.8 dplyr(1c 推荐学)
📌 Lecture 1c block 1.pdf p.32;📝 Tut1 dplyr Ex1–9
library(dplyr)
d %>% select(X2002:X2020) %>% filter(sex=="boys") %>%
mutate(r=X2020/X2002) %>% group_by(region) %>% summarise(m=mean(r)) %>% arrange(m)
5. 交 lab 前的自查
- 写的是
set.seed(12345),每次sample、cv.*之前都调用了;三段划分里调用了两次 📌 Lecture 1a block 1.pdf p.26 - scaler 只在 train 上 fit,valid 和 test 只做
predict📌 Lecture 1d block 1.pdf p.15 - 分类问题里,y 已经转成 factor;
table(真实, 预测)是方阵 -
glm预测时写了type="response";cv.glmnet预测时写了s="lambda.min"(或者有意用 1se) - 训练误差和验证误差画在同一张图里,
ylim足够;图有标题、坐标轴名和图例 - 每个人都能解释自己的代码和背后的理论(课程考核要求,见 Examination 页)