基于与数据帧的列名相关的另一个变量来分配变量的值

问题描述 投票:1回答:4

我有一个带有以下变量的数据框:

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.APrice.BPrice.C中选择值选择

我尝试使用以下代码创建它:

df$Expenditure <- with(df, get(paste("Price.", Choice, sep ="")))

但是,它返回所有观察值的Price.A的值。

在我的实际应用程序中,我有数百个名称,而不是A,B和C,因此ifelse命令不可行。

有人知道该怎么做吗?

r dataframe get
4个回答
1
投票

这里有几种基于* 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.names1:nrow(df)


2
投票

重塑数据可能更有意义。当前,您的数据不是“整齐”的格式

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)]

2
投票
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"))

0
投票

怎么样

for (i in 1:nrow(df)) {
   df$Expenditure[i] <- with(df[i, ], get(paste("Price.", Choice, sep="")))
}
© www.soinside.com 2019 - 2024. All rights reserved.