我有一个带有以下变量的数据框:
df <- data.frame(ID = seq(1:5),
Price.A = c(10,12,14,16,18),
Price.B = c(6,7,9,8,5),
Price.C = c(27,26,25,24,23),
Choice = c("A", "A", "B", "B", "C"))
我想创建一个名为Expenditure的变量,该变量根据变量的值从Price.A,Price.B或Price.C中选择值选择。
我尝试使用以下代码创建它:
df$Expenditure <- with(df, get(paste("Price.", Choice, sep ="")))
但是,它返回所有观察值的Price.A的值。
在我的实际应用程序中,我有数百个名称,而不是A,B和C,因此ifelse命令不可行。
有人知道该怎么做吗?
这里有几种基于* apply的方法:
df$Expenditure <- sapply(seq_along(df[[1]]), function(i) {
df[i, sprintf("Price.%s", df$Choice[i])]
})
df$Expenditure <- mapply(function(x, y) {
df[x, sprintf("Price.%s", y)]
}, row.names(df), df$Choice
)
第二个假设您的对象的默认row.names
为1:nrow(df)
。
重塑数据可能更有意义。当前,您的数据不是“整齐”的格式
library(dplyr)
library(tidyr)
df %>% gather(Price, Expendeture, -ID, -Choice) %>%
filter(Price == paste0("Price.", Choice)) %>%
select(-Price)
否则,您可以对矩阵进行矩阵索引
cols <- grep("Price", names(df), value=T)
mm <- as.matrix(df[, cols])
colidx <- match(paste0("Price.", df$Choice), cols)
df$Expenditure <- mm[cbind(1:length(colidx), colidx)]
df$Expenditure[df$Choice=="A"] <- df$Price.A[df$Choice=="A"]
df$Expenditure[df$Choice=="B"] <- df$Price.B[df$Choice=="B"]
df$Expenditure[df$Choice=="C"] <- df$Price.C[df$Choice=="C"]
这里是如何通过循环放大的方法:
df$Expenditure <- NA
for(i in unique(df$Choice)){
j <- paste0("Price.",i)
df$Expenditure[df$Choice==i] <- df[df$Choice==i,colnames(df) == j]
}
ID Price.A Price.B Price.C Choice Expenditure 1 1 10 6 27 A 10 2 2 12 7 26 A 12 3 3 14 9 25 B 9 4 4 16 8 24 B 8 5 5 18 5 23 C 23
您可以轻松将其包装到函数中,并根据需要使用apply
。
还有许多方法过于复杂,尽管我认为当基数R表现出色时,使用某些第三方程序包来执行此操作是一种糟糕的做法。这是一个:
df <- data.frame(ID = seq(1:5),
PriceA = c(10,12,14,16,18),
PriceB = c(6,7,9,8,5),
PriceC = c(27,26,25,24,23),
Choice = c("A", "A", "B", "B", "C"))
require(sqldf)
df$Expenditure <- unname(sqldf("SELECT
CASE
WHEN Choice == 'A' THEN PriceA
WHEN Choice == 'B' THEN PriceB
WHEN Choice == 'C' THEN PriceC
END
from df"))
怎么样
for (i in 1:nrow(df)) {
df$Expenditure[i] <- with(df[i, ], get(paste("Price.", Choice, sep="")))
}