【问题标题】:Dataframe create new column based on other columns数据框根据其他列创建新列
【发布时间】:2017-01-03 01:40:42
【问题描述】:

我有一个数据框:

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 的矢量化答案应该可以完成这项工作。
  • 从技术上讲,你也可以使用 with(df, (a * c(-1L, 1L)[(a == b) +1L]) + b) 这样的东西,但它不是很直观

标签: r dataframe apply


【解决方案1】:

使用 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 随时测试和编辑这篇文章。
【解决方案2】:

如果你想要一个 apply 方法,那么 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

【讨论】:

    【解决方案3】:

    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)
    

    【讨论】:

      【解决方案4】:

      一个选项是ifelse,它是if/else 的矢量化版本。如果我们对每一行都执行此操作,则 OP 的 pandas 帖子中显示的 if/else 可以在 for 循环或 lapply/sapply 中完成,但这在 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 如果您想了解在哪里使用这些功能,this 可以帮助您。
      • @ragesz 当矢量化解决方案可用时,使用慢速 apply() 循环是个坏主意。不应寻求使用a specific type of command to solve a problem。相反,重要的是要了解哪些方法适用于哪些情况。此答案中的矢量化解决方案显示了解决 R 中问题的正确方法。
      【解决方案5】:

      这里有一个稍微容易混淆的代数方法:

      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 如何自动将布尔值转换为整数等。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-03
      • 1970-01-01
      • 1970-01-01
      • 2020-10-03
      • 1970-01-01
      • 2020-04-12
      • 1970-01-01
      相关资源
      最近更新 更多