Here is an option. I would also recommend using NA instead of NA if 0 , because 0 might be the actual price.
library(dplyr) df %>% arrange(as.Date(Date, format = "%d/%m/%Y")) %>% group_by(Project) %>% mutate(lastPrice = lag(price))
Another option is to use shift from the version of devel data.table
library(data.table)
Or with base R
df <- df[order(df$Project, as.Date(df$Date, format = "%d/%m/%Y")), ] within(df, lastPrice <- ave(price, Project, FUN = function(x) c(NA, x[-length(x)])))
As a side note, it's best to keep the date column in the Date class first, so I recommend doing df$Date <- as.Date(df$Date, format = "%d/%m/%Y") once and for all.
source share