[R] Identify first row of each ID within a data frame, create a variable first =1 for the first row and first=0 of all other rows
Rui Barradas
ru|pb@rr@d@@ @end|ng |rom @@po@pt
Sun Dec 1 08:05:24 CET 2024
Às 02:27 de 01/12/2024, Sorkin, John escreveu:
> Dear R help folks,
>
> First my apologizes for sending several related questions to the list server. I am trying to learn how to manipulate data in R . . . and am having difficulty getting my program to work. I greatly appreciate the help and support list member give!
>
> I am trying to write a program that will run through a data frame organized by ID and for the first line of each new group of data lines that has the same ID create a new variable first that will be 1 for the first line of the group and 0 for all other lines.
>
> e.g. if my original data is
> olddata
> ID date
> 1 1
> 1 1
> 1 2
> 1 2
> 1 3
> 1 3
> 1 4
> 1 4
> 1 5
> 1 5
> 2 5
> 2 5
> 2 5
> 2 6
> 2 6
> 2 6
> 3 10
> 3 10
>
> the new data will be
> newdata
> ID date first
> 1 1 1
> 1 1 0
> 1 2 0
> 1 2 0
> 1 3 0
> 1 3 0
> 1 4 0
> 1 4 0
> 1 5 0
> 1 5 0
> 2 5 1
> 2 5 0
> 2 5 0
> 2 6 0
> 2 6 0
> 2 6 0
> 3 10 1
> 3 10 0
>
> When I run the program below, I receive the following error:
> Error in df[, "ID"] : incorrect number of dimensions
>
> My code:
> # Create data.frame
> ID <- c(rep(1,10),rep(2,6),rep(3,2))
> date <- c(rep(1,2),rep(2,2),rep(3,2),rep(4,2),rep(5,2),
> rep(5,3),rep(6,3),rep(10,2))
> olddata <- data.frame(ID=ID,date=date)
> class(olddata)
> cat("This is the original data frame","\n")
> print(olddata)
>
> # This function is supposed to identify the first row
> # within each level of ID and, for the first row, set
> # the variable first to 1, and for all rows other than
> # the first row set first to 0.
> mydoit <- function(df){
> value <- ifelse (first(df[,"ID"]),1,0)
> cat("value=",value,"\n")
> df[,"first"] <- value
> }
> newdata <- aggregate(olddata,list(olddata[,"ID"]),mydoit)
>
> Thank you,
> John
>
>
> John David Sorkin M.D., Ph.D.
> Professor of Medicine, University of Maryland School of Medicine;
> Associate Director for Biostatistics and Informatics, Baltimore VA Medical Center Geriatrics Research, Education, and Clinical Center;
> PI Biostatistics and Informatics Core, University of Maryland School of Medicine Claude D. Pepper Older Americans Independence Center;
> Senior Statistician University of Maryland Center for Vascular Research;
>
> Division of Gerontology and Paliative Care,
> 10 North Greene Street
> GRECC (BT/18/GR)
> Baltimore, MD 21201-1524
> Cell phone 443-418-5382
>
>
>
> ______________________________________________
> R-help using r-project.org mailing list -- To UNSUBSCRIBE and more, see
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide https://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.
Hello,
And here are two other solutions.
olddata$first <- with(olddata, ave(seq_along(ID), ID, FUN = \(x) x ==
x[1L]))
olddata$first <- c(1L, diff(olddata$ID))
Of these two, diff is faster. But of all the solutions posted so far,
Ben Bolker's is the fastest. And it can be made a little faster if
as.integer substitutes for as.numeric.
And dplyr::mutate now has a .by argument, which avoids explicit the call
to group_by, with a performance gain.
library(microbenchmark)
mb <- microbenchmark(
ave = with(olddata, ave(seq_along(ID), ID, FUN = \(x) x == x[1L])),
dup_num = as.numeric(! duplicated(olddata$ID)),
dup_int = as.integer(! duplicated(olddata$ID)),
diff = diff = c(1L, diff(olddata$ID)),
dplyr_grp = olddata %>% group_by(ID) %>% mutate(first =
as.integer(row_number() == 1)),
dplyr = olddata %>% mutate(first = as.integer(row_number() == 1), .by
= ID)
)
print(mb, order = "median")
However, note that dplyr operates in entire data.frames and therefore is
expected to be slower when tested against instructions that process one
column only.
Hope this helps,
Rui Barradas
--
Este e-mail foi analisado pelo software antivírus AVG para verificar a presença de vírus.
www.avg.com
More information about the R-help
mailing list