基于其他列创建新列的数据框架

17

我有一个数据框:

df <- data.frame('a'=c(1,2,3,4,5), 'b'=c(1,20,3,4,50))
df
    a    b
1   1    1
2   2   20
3   3    3
4   4    4
5   5   50

我想基于现有列创建一个新列。类似这样:

if (df[['a']] == df[['b']]) {
  df[['c']] <- df[['a']] + df[['b']]
} else {
  df[['c']] <- df[['b']] - df[['a']]
}

问题在于if条件只对第一行进行检查... 如果我从上述的if语句创建一个函数,然后使用apply()(或mapply()...),结果是相同的。

在Python/pandas中,我可以使用以下代码:

df['c'] = df[['a', 'b']].apply(lambda x: x['a'] + x['b'] if (x['a'] == x['b']) \
    else x['b'] - x['a'], axis=1)

我希望在R中得到类似的东西。因此,结果应该看起来像这样:

    a    b    c
1   1    1    2
2   2   20   18
3   3    3    6
4   4    4    8
5   5   50   45

问题在于当使用“==”作为逻辑运算符时,只会选择一个,即第一个条目。@akrun提供的向量化答案应该可以解决这个问题。 - JSN
3
从技术上讲,你也可以使用类似 with(df, (a * c(-1L, 1L)[(a == b) +1L]) + b) 的方法,但这并不是很直观。 - talat
5个回答

33

一个选项是ifelse,它是if/else的向量化版本。 如果我们对每一行进行此操作,则可以使用for循环或lapply/sapply中所示的if/else(在OP的pandas帖子中),但这在R中效率低下。

df <- transform(df, c= ifelse(a==b, a+b, b-a))
df
#  a  b  c
#1 1  1  2
#2 2 20 18
#3 3  3  6
#4 4  4  8
#5 5 50 45

这句话可以用其他方式表达

df$c <- with(df, ifelse(a==b, a+b, b-a))

为了在原始数据集中创建“c”列


由于OP希望在R中使用if/else获得类似的选项

df$c <- apply(df, 1, FUN = function(x) if(x[1]==x[2]) x[1]+x[2] else x[2]-x[1])

谢谢!如果可能的话,您能否请提供一个 apply()(或 sapply()mapply()tapply()lapply())的版本或具有基本示例的链接?我想通过这个简单的例子来了解它们的机制(我需要对更复杂的函数和条件进行 apply )。非常感谢! - ragesz
1
如果你想了解何时使用这些函数,可以参考这个链接 - akrun
3
当有向量化解决方案可用时,使用缓慢的 apply() 循环是不明智的。一个人不应该试图使用 某种特定类型的命令来解决问题。相反,重要的是要学习哪些方法适用于哪些情况。本答案中的向量化解决方案展示了在 R 中解决问题的正确方法。 - RHertel

10

这里是一种稍微有些复杂的代数方法:

df$c <- with(df, b + ((-1)^((a==b)+1) * a))

df
  a  b  c
1 1  1  2
2 2 20 18
3 3  3  6
4 4  4  8
5 5 50 45

这个想法是根据测试a == b的结果开关“减号”运算符。


非常好,谢谢!实际上我的问题是关于“基于现有列创建新列”的,我只是创建了一个简单的基本示例来说明这个问题。但是您的解决方案非常直观,我可以更好地理解R(例如R如何自动将布尔转换为整数等)。 - ragesz

8

如果您需要一个应用方法,那么另一种使用 mapply 的方法是创建一个函数并对其进行应用。

fun1 <- function(x, y) if (x == y) {x + y} else {y-x}
df$c <- mapply(fun1, df$a, df$b)
df
#  a  b  c
#1 1  1  2
#2 2 20 18
#3 3  3  6
#4 4  4  8
#5 5 50 45

7

使用dplyr包:

library(dplyr)

df <- df %>% 
  mutate(c = if_else(a == b, a + b, b - a))

df
#   a  b  c
# 1 1  1  2
# 2 2 20 18
# 3 3  3  6
# 4 4  4  8
# 5 5 50 45

你能提供关于性能方面的信息吗?比如说,@akrun的回答? - hello_there_andy
@hello_there_andy 请随意测试和编辑此帖。 - zx8754

4
一个使用 apply 的解决方案。
myFunction <- function(x){
  a <- x[1]
  b <- x[2]
  #further values ignored (if there are more than 2 columns)
  value <- if(a==b) a + b else b - a
  #or more complicated stuff
  return(value)
}

df$c <- apply(df, 1, myFunction)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接