Indeed it can be simplified a lot!
Let's start with generating some testing data
set.seed(1)
df <- data.frame(pid = rep(letters[1:2], each=5),
rating = runif(10))
df
# pid rating
# 1 a 0.26550866
# 2 a 0.37212390
# 3 a 0.57285336
# 4 a 0.90820779
# 5 a 0.20168193
# 6 b 0.89838968
# 7 b 0.94467527
# 8 b 0.66079779
# 9 b 0.62911404
# 10 b 0.06178627
Now we can run your manual approach:
d<-subset(df, pid == "a")
d<-acf(d$rating, plot = FALSE, lag.max=1)
ac<-data.frame(pid="a", ac=d[["acf"]][2, ,1])
d<-subset(df, pid == "b")
d<-acf(d$rating, plot = FALSE, lag.max=1)
ac2<-data.frame(pid="b", ac=d[["acf"]][2, ,1])
ac<-rbind(ac, ac2)
ac
# pid ac
# 1 a -0.1840563
# 2 b 0.1849619
To simplify things, we can put the actual autocorrelation computation in a function, so we just need to call it with the data:
autocor <- function(x, ...){
acf(x, plot=FALSE, lag.max=1)[["acf"]][2, ,1]
}
autocor(df$rating[1:5])
# [1] -0.1840563
autocor(df$rating[6:10])
# [1] 0.1849619
So, the problem reduces to applying this function to every set of rating corresponding to a given pid. The package dplyr has functions for this purpose:
library(tidyverse)
df %>%
group_by(pid) %>%
summarize(ac = autocor(rating))
# A tibble: 2 x 2
# pid ac
# <chr> <dbl>
# 1 a -0.184
# 2 b 0.185
That's it!