我有以下数据集:
foo=data.frame(index=rep(1:10,3),
type=rep(c("A","B","C"),each=10),
ping=rnorm(30),
pong=runif(30))
我想将ping
和pong
的列index==5
和type=="B"
的值减去整列ping
和pong
}。
这有效:
vec=matrix(subset(foo,index==5 & type=="B",select=ping:pong),2,1)
foo[,c("ping","pong")]=foo[,c("ping","pong")]-vec
但是,我很惊讶我必须将vec
指定为列向量,而不是行向量。我原以为我需要将同一行向量减去foo
行的所有(类似子集)。你能解释一下这是为什么吗?此外,如果使用更简单或更清晰的代码可以获得相同的结果,请告诉我。
答案 0 :(得分:3)
你想这样做:
myselect <- with(foo, index ==5 & type == "B")
mycol <- c('ping','pong')
foo[, mycol] <- foo[, mycol] - as.list(foo[myselect, mycol])
vec
应该是一个列表,因为列表的减法是逐个元素完成的。这就是你想要的,这也是你实际做的事情:
首先,您没有将vec
指定为矩阵。如果您在列表中使用matrix()
而不是as.matrix()
,则会获得一个列表。由于数据框本质上是一个列表,matrix()
会为您提供一个带有属性“dim”的列表。该属性使其看起来像一个矩阵,但是:
> str(vec)
List of 2
$ : num 0.704
$ : num 0.164
- attr(*, "dim")= int [1:2] 2 1
你在这里使用的是函数matrix()
的副作用。它还会删除其他属性,因此会删除data.frame
的{{1}}信息并将其设为列表。如果vec
仍然是数据框,则无效。只有两个数据框具有相同的大小时,才能使用数学运算符。这不是这种情况。
vec
你也不应该把它变成一个矩阵。如果这样做,R将按列逐步回收您的矩阵和数据框。这意味着它从foo $ ping的第一个减去vec的第一个值,从foo $ ping的第二个减去vec的第二个值,再次从foo $ ping的第三个值减去vec的第一个值,依此类推。你把矩阵放在哪个方向并不重要,它始终是相同的(错误!)结果:
> vec=subset(foo,index==5 & type=="B",select=ping:pong)
> foo[,c("ping","pong")]-vec
Error in Ops.data.frame(foo[, c("ping", "pong")], vec) :
‘-’ only defined for equally-sized data frames
答案 1 :(得分:1)
您还可以执行以下操作。
Map(`-`, foo[, c("ping", "pong")],
subset(foo, index == 5 & type == "B")[, c("ping", "pong")])
这会返回列表,但您可以按data.frame
转换为as.data.frame()
。
Map
接受一个函数和一组向量,并按元素方式应用该函数。请注意,-
是减法函数。在此示例中,Map
被赋予两个data.frame
个对象,其元素是列。因此,这个Map
操作进行逐列减法。
有关详细信息,请参阅Advanced R page
答案 2 :(得分:0)
您可以尝试这样做:
foo$ping <- foo$ping - foo[foo$index == 5 & foo$type == 'B', 'ping']
foo$pong <- foo$pong - foo[foo$index == 5 & foo$type == 'B', 'pong']
如果您有多个匹配index == 5
和type == 'B'
的行,则可能需要将部分包含在某个函数中,例如min
,max
或{{1这给了一个单独的值。
要回答您的问题,您试图从数据框的列中的每一行中减去2x1矩阵,这与逐行减去两对值相同。你可以尝试这个,看看它是否有效,因为它们都是矢量:
mean
虽然这不会起作用,因为它将重复应用第二个向量(1和2):
x <- c(10, 20)
y <- c(5, 10)
x
[1] 10 20
y
[1] 5 10
x - y
[1] 5 10
然而,逐行操作它就像这样工作,虽然它循环得慢得多:
df <- data.frame(x = rep(10, 10), y = rep(5, 10))
df
x y
1 10 5
2 10 5
3 10 5
4 10 5
5 10 5
6 10 5
7 10 5
8 10 5
9 10 5
10 10 5
df - c(10, 5)
x y
1 0 -5
2 5 0
3 0 -5
4 5 0
5 0 -5
6 5 0
7 0 -5
8 5 0
9 0 -5
10 5 0