从数据框中的所有相关列中减去单行的值

时间:2016-01-27 11:52:12

标签: r vector dataframe

我有以下数据集:

foo=data.frame(index=rep(1:10,3),
               type=rep(c("A","B","C"),each=10),
               ping=rnorm(30),
               pong=runif(30))

我想将pingpong的列index==5type=="B"的值减去整列pingpong }。 这有效:

vec=matrix(subset(foo,index==5 & type=="B",select=ping:pong),2,1)
foo[,c("ping","pong")]=foo[,c("ping","pong")]-vec

但是,我很惊讶我必须将vec指定为列向量,而不是行向量。我原以为我需要将同一行向量减去foo行的所有(类似子集)。你能解释一下这是为什么吗?此外,如果使用更简单或更清晰的代码可以获得相同的结果,请告诉我。

3 个答案:

答案 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 == 5type == 'B'的行,则可能需要将部分包含在某个函数中,例如minmax或{{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