Question

The goal is to have the last argument of the function call to provide the name for the new column to be bound to the original data frame.

Referring to this and this previous question and building upon the minimal working example of the first.

GroupId <-          c(1,1,1,1,2,2,2,3,3)
IndId <-            c(1,1,2,2,3,4,4,5,5)
IndGroupProperty <- c(1,2,1,2,3,3,4,5,6)
PropertyType <-     c(1,2,1,2,2,2,1,2,2)

df <- data.frame(GroupId, IndId, IndGroupProperty, PropertyType)
df

ValidGroupC <-       c(1,1,1,1,0,0,0,0,0)
df <- data.frame(df, ValidGroupC)
df

library(dplyr)
grouptest <- function(object, group, ind, type, new){
groupvar <- deparse(substitute(group)) 
indvar <- deparse(substitute(ind)) 
typevar <- deparse(substitute(type)) 
eval(substitute(
tmp <- object[, c(groupvar, indvar, typevar)] %.%
  group_by(group, ind) %.%
  mutate(type1 = any(type == 1))  %.%
  group_by(group, add = FALSE) %.%
  mutate(tmp2 = all(type1) * 1) %.%
  select(-type1)
  ))
new <- tmp[, 4]                    # this is the relevant part
tmp <- cbind(object, new)          # this is the relevant part
}

df <- grouptest(df, GroupId, IndId, PropertyType, ValidGroup)
df

So most of the code is already a product of the referenced questions. The relevant part for this question is at the end where I take the 4th column of the calculations I made to tmp and put it in an new object, the name of which should be taken from the new argument in the function call, which I then bind to the original data frame.

My question: why is the last column of the final df not named ValidGroup ? I don't get what is wrong - new should be replaced by ValidGroup, but it isn't?

I have tried putting the two lines inside the eval(), which results in Error in cbind(df, ValidGroup) : object 'ValidGroup' not found.

I have tried putting another eval(substitute()) around the two lines, same Error.

I have tried numerous other variations of where to put the lines, using a deparsed newvar, naming the tmp also new, . . .

Was it helpful?

Solution

You want to change the last two lines highlighted in your function to:

object[, new] <- tmp[, 4]
object

Then, when you call the function specify the new argument as a character string:

> df <- grouptest(df, GroupId, IndId, PropertyType, "ValidGroup")   
> df
  GroupId IndId IndGroupProperty PropertyType ValidGroupC ValidGroup
1       1     1                1            1           1          1
2       1     1                2            2           1          1
3       1     2                1            1           1          1
4       1     2                2            2           1          1
5       2     3                3            2           0          0
6       2     4                3            2           0          0
7       2     4                4            1           0          0
8       3     5                5            2           0          0
9       3     5                6            2           0          0

OTHER TIPS

If the object is always a data.frame, why don't you simply make a new one?

tmp <- data.frame(object, new=tmp[,4])
names(tmp)[4] <- as.character(match.call()$new)
return(tmp)

Edit: Changed code to accept name instead of character for argument new. I still don't think this is a good idea, though. You should at least have an optional argument to switch the second line to just names(tmp)[4] <- new in line with @hadley 's reasoning in this thread.

I suspect that you are looking for the assign function:

assign(deparse(substitute(new)), tmp[,4])

So apparently I missunderstood the question. Here's another approach. Instead of using cbind, you can just add a new column to your existing object.

object[, deparse(substitute(new))] <- tmp[,4]
object
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top