我有一个包含多个(数字)列的数据框,并希望创建一个新的数据框,其列是原始列。
> df <- data.frame(cbind(id=LETTERS[1:10],
wheat=c(123,234,345,456,678,987,876,654,432,321),barley=c(135,975,246,864,357,753,468,642,579,531)))
> df
id wheat barley
1 A 123 135
2 B 234 975
3 C 345 246
4 D 456 864
5 E 678 357
6 F 987 753
7 G 876 468
8 H 654 642
9 I 432 579
10 J 321 531
> rankeddf <- transform(df, wheat=rank(wheat), barley=rank(barley))
> rankeddf
id wheat barley
1 A 1 1
2 B 2 10
3 C 4 2
4 D 6 9
5 E 8 3
6 F 10 8
7 G 9 4
8 H 7 7
9 I 5 6
10 J 3 5
问题是,列的数量和名称各不相同。我有一个指定它们的向量:
cols <- c("wheat", "barley")
如何动态构建transform
语句?或者甚至遍历cols
向量,在每次迭代时应用一次transform
语句?我猜这个答案将与eval
或evalq
有关,但我还没有完全了解它们。例如,
> rankeddf2 <- df
> for (col in cols) {rankeddf2 <- transform(rankeddf2, evalq(paste(col,"=rank(",col,")",sep="")))}
> rankeddf2
id wheat barley
1 A 123 135
2 B 234 975
3 C 345 246
4 D 456 864
5 E 678 357
6 F 987 753
7 G 876 468
8 H 654 642
9 I 432 579
10 J 321 531
没有做到这一点。
或者,还有另一种方法吗?
答案 0 :(得分:6)
您可以使用lapply
和rank()
:
as.data.frame(lapply(df[, cols], rank))
wheat barley
1 1 1
2 2 10
3 4 2
4 6 9
5 8 3
6 10 8
7 9 4
8 7 7
9 5 6
10 3 5
好的,所以在这个过程中你会失去第一列,但这很容易添加回来:
data.frame(id=df[[1]], lapply(df[, cols], rank))
id wheat barley
1 A 1 1
2 B 2 10
3 C 4 2
4 D 6 9
5 E 8 3
6 F 10 8
7 G 9 4
8 H 7 7
9 I 5 6
10 J 3 5
答案 1 :(得分:4)
我喜欢将transform()
和相关的with()
和within()
视为语法糖,这些语法在顶层交互式有用,但经常通过{{1}进行子集和替换},'['()
等更容易用于这样的工作:
'[<-'()
> df2 <- df ## copy
> df2[, cols] <- apply(df[, cols], 2, rank)
> df2
id wheat barley
1 A 1 1
2 B 2 10
3 C 4 2
4 D 6 9
5 E 8 3
6 F 10 8
7 G 9 4
8 H 7 7
9 I 5 6
10 J 3 5
和'['()
已经按照您的要求执行了操作,因此您尝试使用子集和替换功能强制'[<-'()
执行已经实现的操作。