一道价值3199的R语言题
老板发来的R语言测试题目,让我一看就非常有胃口,如下:
http://www.bio-info-trainee.com/4458.html
他说,“如果你能独立完成这个题目,恭喜你,省了 3199 培训费,可以直接参加我们的单细胞线下培训啦”
(用三种方法做了的我灰常之开心)
首先看下题目开头的代码
set.seed(0.12345)n=26df=data.frame(LETTERS[1:n],rnorm(n),rnorm(n), rnorm(n),rnorm(n),rnorm(n))a=lapply(2:ncol(df), function(i){ x=df[,c(1,i)] x=x[x[,2]>0,] return(x)})a
## [[1]]## LETTERS.1.n. rnorm.n.## 1 A 1.2629543## 3 C 1.3297993## 4 D 1.2724293## 5 E 0.4146414## 10 J 2.4046534## 11 K 0.7635935## 17 Q 0.2522234## 19 S 0.4356833## 22 V 0.3773956## 23 W 0.1333364## 24 X 0.8041895## 26 Z 0.5036080## ## [[2]]## LETTERS.1.n. rnorm.n..1## 1 A 1.08576936## 4 D 0.04672617## 9 I 0.72675075## 10 J 1.15191175## 11 K 0.99216037## 13 M 1.23830410## 15 O 1.75790309## 16 P 0.56074609## 22 V 1.15653700## 23 W 0.83204713## 25 Y 0.26613736## ## [[3]]## LETTERS.1.n. rnorm.n..2## 1 A 2.44136463## 4 D 0.25014132## 5 E 0.61824329## 9 I 0.35872890## 14 N 0.24226348## 16 P 0.36594112## 17 Q 0.24841265## 18 R 0.06528818## 19 S 0.01915639## 20 T 0.25733838## 23 W 0.66413570## 24 X 1.10096910## 25 Y 0.14377148## ## [[4]]## LETTERS.1.n. rnorm.n..3## 4 D 1.25408311## 5 E 0.77214219## 9 I 0.99698686## 11 K 1.25601882## 12 L 0.64667439## 13 M 1.29931230## 15 O 0.00837096## 17 Q 0.59625902## 18 R 0.11971764## 20 T 1.45598840## 21 U 0.22901959## 22 V 0.99654393## 23 W 0.78185918## 26 Z 0.04658030## ## [[5]]## LETTERS.1.n. rnorm.n..4## 2 B 0.57671878## 4 D 1.62544730## 6 F 1.67829721## 9 I 0.02538287## 10 J 0.02747534## 12 L 1.05375086## 14 N 0.33561721## 15 O 0.49479577## 16 P 0.13805271## 18 R 0.19768426## 22 V 1.58009168## 23 W 1.49781876## 24 X 0.26264546
一个由数据框筛选非负数据而来的长短不一的列表。现在的需求是将列表a还原为整齐的矩阵,删除的负值用0替代,目标是这个样子:

<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;"></figcaption>
脑子里第一个想法:for循环套ifelse。
向量和list都有一个非常美妙的用法,是从《R数据科学》里学来的:先定义一个空的列表/向量,然后每次循环向其中添加一个元素。
这个方法非常好用,永远感谢哈德雷蜀黍。
观察一下操作对象:列表a,可以发现他的每个元素都是数据框,并且行名是原数据框df的行号,只是缺少了几个。
那么就可以用到那个神奇的符号%in%
,用来作为if
的判断条件。
刚好只是分两个条件,所以可以用ifelse
函数。
ta =list()m=vector()for (j in 1:length(a)){ p=a[[j]][2] for (i in 1:n){ m[i] <- ifelse(i %in% rownames(p),p[rownames(p)==as.character(i),],0) } ta[[j]] <- m}ta
## [[1]]## [1] 1.2629543 0.0000000 1.3297993 1.2724293 0.4146414 0.0000000 0.0000000## [8] 0.0000000 0.0000000 2.4046534 0.7635935 0.0000000 0.0000000 0.0000000## [15] 0.0000000 0.0000000 0.2522234 0.0000000 0.4356833 0.0000000 0.0000000## [22] 0.3773956 0.1333364 0.8041895 0.0000000 0.5036080## ## [[2]]## [1] 1.08576936 0.00000000 0.00000000 0.04672617 0.00000000 0.00000000## [7] 0.00000000 0.00000000 0.72675075 1.15191175 0.99216037 0.00000000## [13] 1.23830410 0.00000000 1.75790309 0.56074609 0.00000000 0.00000000## [19] 0.00000000 0.00000000 0.00000000 1.15653700 0.83204713 0.00000000## [25] 0.26613736 0.00000000## ## [[3]]## [1] 2.44136463 0.00000000 0.00000000 0.25014132 0.61824329 0.00000000## [7] 0.00000000 0.00000000 0.35872890 0.00000000 0.00000000 0.00000000## [13] 0.00000000 0.24226348 0.00000000 0.36594112 0.24841265 0.06528818## [19] 0.01915639 0.25733838 0.00000000 0.00000000 0.66413570 1.10096910## [25] 0.14377148 0.00000000## ## [[4]]## [1] 0.00000000 0.00000000 0.00000000 1.25408311 0.77214219 0.00000000## [7] 0.00000000 0.00000000 0.99698686 0.00000000 1.25601882 0.64667439## [13] 1.29931230 0.00000000 0.00837096 0.00000000 0.59625902 0.11971764## [19] 0.00000000 1.45598840 0.22901959 0.99654393 0.78185918 0.00000000## [25] 0.00000000 0.04658030## ## [[5]]## [1] 0.00000000 0.57671878 0.00000000 1.62544730 0.00000000 1.67829721## [7] 0.00000000 0.00000000 0.02538287 0.02747534 0.00000000 1.05375086## [13] 0.00000000 0.33561721 0.49479577 0.13805271 0.00000000 0.19768426## [19] 0.00000000 0.00000000 0.00000000 1.58009168 1.49781876 0.26264546## [25] 0.00000000 0.00000000
这个方法是最基础的,做完还需要将列表转换为矩阵。而且最后的列名很杂乱,需要删掉,行名应该是LETTERS
mx=as.matrix(data.frame(ta))colnames(mx)=NULLrownames(mx)=LETTERS
方法二,循环和sapply很配
apply
族的函数一直是非常高级的。列表变矩阵,我想起了sapply
。把刚才的代码写成函数,用sapply
即可一步到位。
sapply
的用法很简单,两个参数,一个是object也就是列表的名字;一个是函数名称。意为对列表中的每个元素进行同样的操作,所以写函数的时候需要以列表的元素(在这个栗子中是数据框)为单位来写。
pd=function(x){ p=x[2] for (i in 1:n){ m[i] <- ifelse(i %in% rownames(p),p[rownames(p)==as.character(i),],0) } print(m)}mt=sapply(a,pd)
## [1] 1.2629543 0.0000000 1.3297993 1.2724293 0.4146414 0.0000000 0.0000000## [8] 0.0000000 0.0000000 2.4046534 0.7635935 0.0000000 0.0000000 0.0000000## [15] 0.0000000 0.0000000 0.2522234 0.0000000 0.4356833 0.0000000 0.0000000## [22] 0.3773956 0.1333364 0.8041895 0.0000000 0.5036080## [1] 1.08576936 0.00000000 0.00000000 0.04672617 0.00000000 0.00000000## [7] 0.00000000 0.00000000 0.72675075 1.15191175 0.99216037 0.00000000## [13] 1.23830410 0.00000000 1.75790309 0.56074609 0.00000000 0.00000000## [19] 0.00000000 0.00000000 0.00000000 1.15653700 0.83204713 0.00000000## [25] 0.26613736 0.00000000## [1] 2.44136463 0.00000000 0.00000000 0.25014132 0.61824329 0.00000000## [7] 0.00000000 0.00000000 0.35872890 0.00000000 0.00000000 0.00000000## [13] 0.00000000 0.24226348 0.00000000 0.36594112 0.24841265 0.06528818## [19] 0.01915639 0.25733838 0.00000000 0.00000000 0.66413570 1.10096910## [25] 0.14377148 0.00000000## [1] 0.00000000 0.00000000 0.00000000 1.25408311 0.77214219 0.00000000## [7] 0.00000000 0.00000000 0.99698686 0.00000000 1.25601882 0.64667439## [13] 1.29931230 0.00000000 0.00837096 0.00000000 0.59625902 0.11971764## [19] 0.00000000 1.45598840 0.22901959 0.99654393 0.78185918 0.00000000## [25] 0.00000000 0.04658030## [1] 0.00000000 0.57671878 0.00000000 1.62544730 0.00000000 1.67829721## [7] 0.00000000 0.00000000 0.02538287 0.02747534 0.00000000 1.05375086## [13] 0.00000000 0.33561721 0.49479577 0.13805271 0.00000000 0.19768426## [19] 0.00000000 0.00000000 0.00000000 1.58009168 1.49781876 0.26264546## [25] 0.00000000 0.00000000
rownames(mt)=LETTERScolnames(mt)=NULLmt
## [,1] [,2] [,3] [,4] [,5]## A 1.2629543 1.08576936 2.44136463 0.00000000 0.00000000## B 0.0000000 0.00000000 0.00000000 0.00000000 0.57671878## C 1.3297993 0.00000000 0.00000000 0.00000000 0.00000000## D 1.2724293 0.04672617 0.25014132 1.25408311 1.62544730## E 0.4146414 0.00000000 0.61824329 0.77214219 0.00000000## F 0.0000000 0.00000000 0.00000000 0.00000000 1.67829721## G 0.0000000 0.00000000 0.00000000 0.00000000 0.00000000## H 0.0000000 0.00000000 0.00000000 0.00000000 0.00000000## I 0.0000000 0.72675075 0.35872890 0.99698686 0.02538287## J 2.4046534 1.15191175 0.00000000 0.00000000 0.02747534## K 0.7635935 0.99216037 0.00000000 1.25601882 0.00000000## L 0.0000000 0.00000000 0.00000000 0.64667439 1.05375086## M 0.0000000 1.23830410 0.00000000 1.29931230 0.00000000## N 0.0000000 0.00000000 0.24226348 0.00000000 0.33561721## O 0.0000000 1.75790309 0.00000000 0.00837096 0.49479577## P 0.0000000 0.56074609 0.36594112 0.00000000 0.13805271## Q 0.2522234 0.00000000 0.24841265 0.59625902 0.00000000## R 0.0000000 0.00000000 0.06528818 0.11971764 0.19768426## S 0.4356833 0.00000000 0.01915639 0.00000000 0.00000000## T 0.0000000 0.00000000 0.25733838 1.45598840 0.00000000## U 0.0000000 0.00000000 0.00000000 0.22901959 0.00000000## V 0.3773956 1.15653700 0.00000000 0.99654393 1.58009168## W 0.1333364 0.83204713 0.66413570 0.78185918 1.49781876## X 0.8041895 0.00000000 1.10096910 0.00000000 0.26264546## Y 0.0000000 0.26613736 0.14377148 0.00000000 0.00000000## Z 0.5036080 0.00000000 0.00000000 0.04658030 0.00000000
方法三:merge 和sapply也很配
老板给提示说可以用match
。可我没有想出来match
怎么做,脑子里却蹦出了merge
!!!因为同样是匹配,我想,merge
可以拼接两个表格,可以保留所有数据,生成缺失值。然后用0来替换缺失值不就可以咯。
x=x=data.frame(LETTERS)ma <- function(y){ k=merge(x, y, by.x = "LETTERS",by.y = "LETTERS.1.n.",all.x = TRUE) k[is.na(k)==T] <- 0 print(k[,2])}my=sapply(a,ma)
## [1] 1.2629543 0.0000000 1.3297993 1.2724293 0.4146414 0.0000000 0.0000000## [8] 0.0000000 0.0000000 2.4046534 0.7635935 0.0000000 0.0000000 0.0000000## [15] 0.0000000 0.0000000 0.2522234 0.0000000 0.4356833 0.0000000 0.0000000## [22] 0.3773956 0.1333364 0.8041895 0.0000000 0.5036080## [1] 1.08576936 0.00000000 0.00000000 0.04672617 0.00000000 0.00000000## [7] 0.00000000 0.00000000 0.72675075 1.15191175 0.99216037 0.00000000## [13] 1.23830410 0.00000000 1.75790309 0.56074609 0.00000000 0.00000000## [19] 0.00000000 0.00000000 0.00000000 1.15653700 0.83204713 0.00000000## [25] 0.26613736 0.00000000## [1] 2.44136463 0.00000000 0.00000000 0.25014132 0.61824329 0.00000000## [7] 0.00000000 0.00000000 0.35872890 0.00000000 0.00000000 0.00000000## [13] 0.00000000 0.24226348 0.00000000 0.36594112 0.24841265 0.06528818## [19] 0.01915639 0.25733838 0.00000000 0.00000000 0.66413570 1.10096910## [25] 0.14377148 0.00000000## [1] 0.00000000 0.00000000 0.00000000 1.25408311 0.77214219 0.00000000## [7] 0.00000000 0.00000000 0.99698686 0.00000000 1.25601882 0.64667439## [13] 1.29931230 0.00000000 0.00837096 0.00000000 0.59625902 0.11971764## [19] 0.00000000 1.45598840 0.22901959 0.99654393 0.78185918 0.00000000## [25] 0.00000000 0.04658030## [1] 0.00000000 0.57671878 0.00000000 1.62544730 0.00000000 1.67829721## [7] 0.00000000 0.00000000 0.02538287 0.02747534 0.00000000 1.05375086## [13] 0.00000000 0.33561721 0.49479577 0.13805271 0.00000000 0.19768426## [19] 0.00000000 0.00000000 0.00000000 1.58009168 1.49781876 0.26264546## [25] 0.00000000 0.00000000
rownames(my)=LETTERScolnames(my)=NULLmy
## [,1] [,2] [,3] [,4] [,5]## A 1.2629543 1.08576936 2.44136463 0.00000000 0.00000000## B 0.0000000 0.00000000 0.00000000 0.00000000 0.57671878## C 1.3297993 0.00000000 0.00000000 0.00000000 0.00000000## D 1.2724293 0.04672617 0.25014132 1.25408311 1.62544730## E 0.4146414 0.00000000 0.61824329 0.77214219 0.00000000## F 0.0000000 0.00000000 0.00000000 0.00000000 1.67829721## G 0.0000000 0.00000000 0.00000000 0.00000000 0.00000000## H 0.0000000 0.00000000 0.00000000 0.00000000 0.00000000## I 0.0000000 0.72675075 0.35872890 0.99698686 0.02538287## J 2.4046534 1.15191175 0.00000000 0.00000000 0.02747534## K 0.7635935 0.99216037 0.00000000 1.25601882 0.00000000## L 0.0000000 0.00000000 0.00000000 0.64667439 1.05375086## M 0.0000000 1.23830410 0.00000000 1.29931230 0.00000000## N 0.0000000 0.00000000 0.24226348 0.00000000 0.33561721## O 0.0000000 1.75790309 0.00000000 0.00837096 0.49479577## P 0.0000000 0.56074609 0.36594112 0.00000000 0.13805271## Q 0.2522234 0.00000000 0.24841265 0.59625902 0.00000000## R 0.0000000 0.00000000 0.06528818 0.11971764 0.19768426## S 0.4356833 0.00000000 0.01915639 0.00000000 0.00000000## T 0.0000000 0.00000000 0.25733838 1.45598840 0.00000000## U 0.0000000 0.00000000 0.00000000 0.22901959 0.00000000## V 0.3773956 1.15653700 0.00000000 0.99654393 1.58009168## W 0.1333364 0.83204713 0.66413570 0.78185918 1.49781876## X 0.8041895 0.00000000 1.10096910 0.00000000 0.26264546## Y 0.0000000 0.26613736 0.14377148 0.00000000 0.00000000## Z 0.5036080 0.00000000 0.00000000 0.04658030 0.00000000
最后判断下三种方法得出的结果是否相同:
identical(mt,mx)
## [1] TRUE
identical(mt,my)
## [1] TRUE
吼。大功告成。