1

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, . . .

Community
  • 1
  • 1
iraserd
  • 669
  • 1
  • 8
  • 26

3 Answers3

1

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
Thomas
  • 43,637
  • 12
  • 109
  • 140
  • Thank you, that works! Is it just me or can R syntax sometimes be quirky? To me that looks very similar to what i originally had... – iraserd Apr 15 '14 at 09:27
  • Everything takes practice. In time it will all become clear. :) – Thomas Apr 15 '14 at 10:00
0

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.

ilir
  • 3,236
  • 15
  • 23
  • I don't see your point. That still does not result in the new column to be named correctly? – iraserd Apr 15 '14 at 07:14
  • My bad :-). I added a solution, but I think this may result in the `data.frame` being rewritten. If it were a `data.table`, you could use `setnames()` to change it in place. – ilir Apr 15 '14 at 07:20
  • This does not work, results in the same `Error in grouptest(df, GroupId, IndId, PropertyType, ValidGroup) : object 'ValidGroup' not found` – iraserd Apr 15 '14 at 07:34
  • `ValidGroup` would have to be a `character` variable. I am not sure there is a way to do it otherwise. – ilir Apr 15 '14 at 07:37
  • Well I also tried to `deparse()` the value of `new`, which should render it a `character` class string and that didn't work either... :( – iraserd Apr 15 '14 at 07:42
  • @iraserd found a way, but it may be confusing for whoever uses it. Refer to the thread I mentioned in the answer for reasons why you should at least provide the alternative to pass a character string. – ilir Apr 15 '14 at 08:44
0

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
shadow
  • 21,823
  • 4
  • 63
  • 77
  • Thank you for your reply. How would I got about applying this? By simply adding two more lines at the end of the function I still get the last column named "new". I added the two lines `assign(deparse(substitute(new)), tmp[,4])` and `tmp ` between `tmp <- cbind(object, new)` and `}`. – iraserd Apr 15 '14 at 08:37