Extreme Processing Time on For Loop Using Large Dataset
I've prepared a routine that copies the value of one cell ("DBH") to another cell ("DG"), in another row, where the row being copied to occurs immediately following the row being copied from (in time, not necessarily in the table).
PlotID 'R8' represents the eight measurement, 'R7' the 7th, and so forth.
The loop is designed to check if the row has a preceding measurement, and if so, records the unique row identifier for that measurement. It then uses the preceding row identifier to search for the preceding record to be copied through a second nested loop.
The problem is the full dataset I'm using contains north of 650,000 records. I knew this structure would be somewhat inefficient, but when I run it the runtime is only moving through about 10,000 records an hour. Any suggestions to improve computational efficiency?
# sort TreeInit Table to facilitate desired iteration
FVS_TreeInit$StandPlotTree_ID <- paste(FVS_TreeInit$StandPlot_ID,"T",FVS_TreeInit$Tree_ID,sep="")
# loop through FVS_TreeInit and add previous diameter increment identifier to current row
for (i in seq_len(nrow(FVS_TreeInit))){
if (FVS_TreeInit[i,"Plot_ID"] == "R8"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R7T",FVS_TreeInit[i,"Tree_ID"],sep="")
for (f in seq_len(nrow(FVS_TreeInit))){
if (FVS_TreeInit[f,"StandPlotTree_ID"] == find){
FVS_TreeInit[i,"GD"] <- FVS_TreeInit[f,"DBH"]
break
}
}
} else if (FVS_TreeInit[i,"Plot_ID"] == "R7"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R6T",FVS_TreeInit[i,"Tree_ID"],sep="")
for (f in seq_len(nrow(FVS_TreeInit))){
if (FVS_TreeInit[f,"StandPlotTree_ID"] == find){
FVS_TreeInit[i,"GD"] <- FVS_TreeInit[f,"DBH"]
break
}
}
} else if (FVS_TreeInit[i,"Plot_ID"] == "R6"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R5T",FVS_TreeInit[i,"Tree_ID"],sep="")
for (f in seq_len(nrow(FVS_TreeInit))){
if (FVS_TreeInit[f,"StandPlotTree_ID"] == find){
FVS_TreeInit[i,"GD"] <- FVS_TreeInit[f,"DBH"]
break
}
}
} else if (FVS_TreeInit[i,"Plot_ID"] == "R5"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R4T",FVS_TreeInit[i,"Tree_ID"],sep="")
for (f in seq_len(nrow(FVS_TreeInit))){
if (FVS_TreeInit[f,"StandPlotTree_ID"] == find){
FVS_TreeInit[i,"GD"] <- FVS_TreeInit[f,"DBH"]
break
}
}
} else if (FVS_TreeInit[i,"Plot_ID"] == "R4"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R3T",FVS_TreeInit[i,"Tree_ID"],sep="")
for (f in seq_len(nrow(FVS_TreeInit))){
if (FVS_TreeInit[f,"StandPlotTree_ID"] == find){
FVS_TreeInit[i,"GD"] <- FVS_TreeInit[f,"DBH"]
break
}
}
} else if (FVS_TreeInit[i,"Plot_ID"] == "R3"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R2T",FVS_TreeInit[i,"Tree_ID"],sep="")
for (f in seq_len(nrow(FVS_TreeInit))){
if (FVS_TreeInit[f,"StandPlotTree_ID"] == find){
FVS_TreeInit[i,"GD"] <- FVS_TreeInit[f,"DBH"]
break
}
}
} else if (FVS_TreeInit[i,"Plot_ID"] == "R2"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R1T",FVS_TreeInit[i,"Tree_ID"],sep="")
for (f in seq_len(nrow(FVS_TreeInit))){
if (FVS_TreeInit[f,"StandPlotTree_ID"] == find){
FVS_TreeInit[i,"GD"] <- FVS_TreeInit[f,"DBH"]
break
}
}
} else if (FVS_TreeInit[i,"Plot_ID"] == "R1"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R0T",FVS_TreeInit[i,"Tree_ID"],sep="")
for (f in seq_len(nrow(FVS_TreeInit))){
if (FVS_TreeInit[f,"StandPlotTree_ID"] == find){
FVS_TreeInit[i,"GD"] <- FVS_TreeInit[f,"DBH"]
break
}
}
} else{
FVS_TreeInit[i,"GD"] <- NA
}
if (i%%1000 == 0){
print(paste(i," rows iterated...",sep=""))
}
}
}
Some sample data (.csv):
Stand_ID,Plot_ID,StandPlot_ID,Tree_ID,DBH,DG,Species,Age,StandPlotTree_ID,StandPlotTree_ID_Past
D18P186001,R0,D18P186001R0,1,4.76378225,,ABBA,,D18P186001R0T1,
D18P186001,R0,D18P186001R0,2,1.259843219,,BEPA,,D18P186001R0T2,
D18P186001,R0,D18P186001R0,3,0.275590695,,BEPA,,D18P186001R0T3,
D18P186001,R0,D18P186001R0,4,0.629921609,,BEPA,,D18P186001R0T4,
D18P186001,R0,D18P186001R0,5,0.1968505,,BEPA,,D18P186001R0T5,
D18P186001,R0,D18P186001R0,6,3.70078925,,ABBA,26,D18P186001R0T6,
D18P186001,R0,D18P186001R0,7,2.834647125,,ABBA,,D18P186001R0T7,
D18P186001,R0,D18P186001R0,8,1.259843219,,,,D18P186001R0T8,
D18P186001,R0,D18P186001R0,9,2.283465875,,,,D18P186001R0T9,
D18P186001,R0,D18P186001R0,10,1.181103,,,,D18P186001R0T10,
D18P186001,R0,D18P186001R0,11,1.535433938,,BEPA,,D18P186001R0T11,
D18P186001,R0,D18P186001R0,12,4.212600625,,ABBA,,D18P186001R0T12,
D18P186001,R0,D18P186001R0,13,3.30708825,,ABBA,,D18P186001R0T13,
D18P186001,R0,D18P186001R0,14,1.259843219,,ABBA,,D18P186001R0T14,
D18P186001,R0,D18P186001R0,15,4.212600625,,ABBA,28,D18P186001R0T15,
D18P186001,R0,D18P186001R0,16,3.149608,,ABBA,28,D18P186001R0T16,
D18P186001,R0,D18P186001R0,17,1.181103,,ABBA,,D18P186001R0T17,
D18P186001,R0,D18P186001R0,18,0.944882438,,BEPA,,D18P186001R0T18,
D18P186001,R0,D18P186001R0,19,0.393701,,BEPA,,D18P186001R0T19,
D18P186001,R0,D18P186001R0,20,0.314960805,,BEPA,,D18P186001R0T20,
D18P186001,R0,D18P186001R0,21,2.362206,,ABBA,22,D18P186001R0T21,
D18P186001,R0,D18P186001R0,22,0.314960805,,BEPA,,D18P186001R0T22,
D18P186001,R0,D18P186001R0,23,1.062992719,,ABBA,,D18P186001R0T23,
D18P186001,R0,D18P186001R0,24,3.93701,,ABBA,25,D18P186001R0T24,
D18P186001,R0,D18P186001R0,25,4.76378225,,ABBA,,D18P186001R0T25,
D18P186001,R0,D18P186001R0,26,0.748031891,,BEPA,,D18P186001R0T26,
D18P186001,R0,D18P186001R0,27,0.944882438,,BEPA,,D18P186001R0T27,
D18P186001,R0,D18P186001R0,28,3.267718375,,ABBA,,D18P186001R0T28,
D18P186001,R0,D18P186001R0,29,0.314960805,,BEPA,,D18P186001R0T29,
D18P186001,R0,D18P186001R0,30,0.472441219,,BEPA,,D18P186001R0T30,
D18P186001,R0,D18P186001R0,31,4.606301625,,ABBA,,D18P186001R0T31,
D18P186001,R0,D18P186001R0,32,4.055120375,,ABBA,,D18P186001R0T32,
D18P186001,R0,D18P186001R0,33,0.433071109,,,,D18P186001R0T33,
D18P186001,R0,D18P186001R0,34,1.023622562,,,,D18P186001R0T34,
D18P186001,R0,D18P186001R0,35,0.5905515,,,,D18P186001R0T35,
D18P186001,R0,D18P186001R0,36,0.748031891,,,,D18P186001R0T36,
D18P186001,R0,D18P186001R0,37,3.425198625,,ABBA,30,D18P186001R0T37,
D18P186001,R0,D18P186001R0,38,4.29134075,,ABBA,,D18P186001R0T38,
D18P186001,R0,D18P186001R0,39,3.93701,,ABBA,,D18P186001R0T39,
D18P186001,R0,D18P186001R0,40,4.251970875,,ABBA,,D18P186001R0T40,
D18P186001,R0,D18P186001R0,41,4.09449025,,ABBA,,D18P186001R0T41,
D18P186001,R0,D18P186001R0,42,6.181105625,,ABBA,24,D18P186001R0T42,
D18P186001,R0,D18P186001R0,43,3.858269875,,ABBA,,D18P186001R0T43,
D18P186001,R0,D18P186001R0,44,3.7401595,,ABBA,,D18P186001R0T44,
D18P186001,R0,D18P186001R0,45,0.5905515,,ABBA,,D18P186001R0T45,
D18P186001,R0,D18P186001R0,46,1.259843219,,ABBA,,D18P186001R0T46,
D18P186001,R0,D18P186001R0,47,3.89763975,,ABBA,,D18P186001R0T47,
D18P186001,R0,D18P186001R0,48,0.708661781,,ABBA,,D18P186001R0T48,
D18P186001,R0,D18P186001R0,49,0.314960805,,ABBA,,D18P186001R0T49,
D18P186001,R0,D18P186001R0,50,4.1338605,,ABBA,,D18P186001R0T50,
D18P186001,R0,D18P186001R0,51,1.889764875,,BEPA,,D18P186001R0T51,
D18P186001,R0,D18P186001R0,52,0.314960805,,,,D18P186001R0T52,
D18P186001,R0,D18P186001R0,53,0.629921609,,BEPA,,D18P186001R0T53,
D18P186001,R0,D18P186001R0,54,0.354330891,,BEPA,,D18P186001R0T54,
D18P186001,R0,D18P186001R0,55,1.456693719,,BEPA,,D18P186001R0T55,
D18P186001,R0,D18P186001R0,56,2.047245125,,,,D18P186001R0T56,
D18P186001,R0,D18P186001R0,57,2.480316375,,,,D18P186001R0T57,
D18P186001,R0,D18P186001R0,58,1.968505,,,,D18P186001R0T58,
D18P186001,R0,D18P186001R0,59,3.93701,,ABBA,,D18P186001R0T59,
D18P186001,R0,D18P186001R0,60,1.102362781,,ABBA,,D18P186001R0T60,
D18P186001,R0,D18P186001R0,61,0.472441219,,BEPA,,D18P186001R0T61,
D18P186001,R0,D18P186001R0,62,0.905512281,,BEPA,,D18P186001R0T62,
D18P186001,R0,D18P186001R0,63,0.944882438,,BEPA,,D18P186001R0T63,
D18P186001,R0,D18P186001R0,64,1.574804,,ABBA,,D18P186001R0T64,
D18P186001,R0,D18P186001R0,65,0.472441219,,BEPA,,D18P186001R0T65,
D18P186001,R0,D18P186001R0,66,5.15748325,,ABBA,,D18P186001R0T66,
D18P186001,R0,D18P186001R0,67,5.35433375,,ABBA,29,D18P186001R0T67,
D18P186001,R0,D18P186001R0,68,0.511811281,,ABBA,,D18P186001R0T68,
D18P186001,R0,D18P186001R0,69,4.68504175,,ABBA,,D18P186001R0T69,
D18P186001,R0,D18P186001R0,70,6.8897675,,ABBA,23,D18P186001R0T70,
D18P186001,R0,D18P186001R0,71,0.275590695,,BEPA,,D18P186001R0T71,
D18P186001,R0,D18P186001R0,72,4.606301625,,ABBA,20,D18P186001R0T72,
D18P186001,R0,D18P186001R0,73,0.511811281,,BEPA,,D18P186001R0T73,
D18P186001,R0,D18P186001R0,74,0.275590695,,BEPA,,D18P186001R0T74,
D18P186001,R0,D18P186001R0,75,0.393701,,BEPA,,D18P186001R0T75,
D18P186001,R0,D18P186001R0,76,0.472441219,,BEPA,,D18P186001R0T76,
D18P186001,R0,D18P186001R0,77,0.669291719,,ABBA,,D18P186001R0T77,
D18P186001,R0,D18P186001R0,78,0.354330891,,BEPA,,D18P186001R0T78,
D18P186001,R0,D18P186001R0,79,4.409451125,,ABBA,,D18P186001R0T79,
D18P186001,R0,D18P186001R0,80,7.12598825,,ABBA,,D18P186001R0T80,
D18P186001,R0,D18P186001R0,81,4.724412,,ABBA,,D18P186001R0T81,
D18P186001,R1,D18P186001R1,1,5.86614475,,ABBA,,D18P186001R1T1,
D18P186001,R1,D18P186001R1,2,1.3779535,,BEPA,,D18P186001R1T2,
D18P186001,R1,D18P186001R1,3,,,BEPA,,D18P186001R1T3,
D18P186001,R1,D18P186001R1,4,,,BEPA,,D18P186001R1T4,
D18P186001,R1,D18P186001R1,5,0.236220609,,BEPA,,D18P186001R1T5,
D18P186001,R1,D18P186001R1,6,4.1338605,,ABBA,31,D18P186001R1T6,
D18P186001,R1,D18P186001R1,7,3.425198625,,ABBA,,D18P186001R1T7,
D18P186001,R1,D18P186001R1,9,2.480316375,,,,D18P186001R1T9,
D18P186001,R1,D18P186001R1,10,1.259843219,,,,D18P186001R1T10,
D18P186001,R1,D18P186001R1,11,1.574804,,BEPA,,D18P186001R1T11,
D18P186001,R1,D18P186001R1,12,4.88189225,,ABBA,,D18P186001R1T12,
D18P186001,R1,D18P186001R1,13,3.89763975,,ABBA,,D18P186001R1T13,
D18P186001,R1,D18P186001R1,14,1.3779535,,ABBA,,D18P186001R1T14,
D18P186001,R1,D18P186001R1,15,5.196853125,,ABBA,33,D18P186001R1T15,
D18P186001,R1,D18P186001R1,16,4.055120375,,ABBA,33,D18P186001R1T16,
D18P186001,R1,D18P186001R1,17,1.220473062,,ABBA,,D18P186001R1T17,
D18P186001,R1,D18P186001R1,18,0.9842525,,BEPA,,D18P186001R1T18,
D18P186001,R1,D18P186001R1,19,0.393701,,BEPA,,D18P186001R1T19,
D18P186001,R1,D18P186001R1,20,0.472441219,,BEPA,,D18P186001R1T20,
D18P186001,R1,D18P186001R1,21,2.716536938,,ABBA,27,D18P186001R1T21,
D18P186001,R1,D18P186001R1,22,,,BEPA,,D18P186001R1T22,
D18P186001,R1,D18P186001R1,23,1.181103,,ABBA,,D18P186001R1T23,
D18P186001,R1,D18P186001R1,24,5.000002625,,ABBA,30,D18P186001R1T24,
D18P186001,R1,D18P186001R1,25,4.88189225,,ABBA,,D18P186001R1T25,
D18P186001,R1,D18P186001R1,26,,,BEPA,,D18P186001R1T26,
D18P186001,R1,D18P186001R1,27,1.023622562,,BEPA,,D18P186001R1T27,
D18P186001,R1,D18P186001R1,28,4.330711,,ABBA,,D18P186001R1T28,
D18P186001,R1,D18P186001R1,29,0.354330891,,BEPA,,D18P186001R1T29,
D18P186001,R1,D18P186001R1,30,0.511811281,,BEPA,,D18P186001R1T30,
D18P186001,R1,D18P186001R1,31,5.74803475,,ABBA,,D18P186001R1T31,
D18P186001,R1,D18P186001R1,32,5.27559325,,ABBA,,D18P186001R1T32,
D18P186001,R1,D18P186001R1,33,,,,,D18P186001R1T33,
D18P186001,R1,D18P186001R1,34,0.944882438,,,,D18P186001R1T34,
D18P186001,R1,D18P186001R1,35,0.669291719,,,,D18P186001R1T35,
D18P186001,R1,D18P186001R1,36,1.062992719,,,,D18P186001R1T36,
D18P186001,R1,D18P186001R1,37,4.5275615,,ABBA,35,D18P186001R1T37,
D18P186001,R1,D18P186001R1,38,5.629924375,,ABBA,,D18P186001R1T38,
D18P186001,R1,D18P186001R1,39,4.88189225,,ABBA,,D18P186001R1T39,
D18P186001,R1,D18P186001R1,40,5.47244375,,ABBA,,D18P186001R1T40,
D18P186001,R1,D18P186001R1,41,4.842522375,,ABBA,,D18P186001R1T41,
D18P186001,R1,D18P186001R1,42,7.204728,,ABBA,29,D18P186001R1T42,
D18P186001,R1,D18P186001R1,43,4.842522375,,ABBA,,D18P186001R1T43,
D18P186001,R1,D18P186001R1,44,4.606301625,,ABBA,,D18P186001R1T44,
D18P186001,R1,D18P186001R1,45,0.748031891,,ABBA,,D18P186001R1T45,
D18P186001,R1,D18P186001R1,46,1.3779535,,ABBA,,D18P186001R1T46,
D18P186001,R1,D18P186001R1,47,4.37008125,,ABBA,,D18P186001R1T47,
D18P186001,R1,D18P186001R1,48,0.9842525,,ABBA,,D18P186001R1T48,
D18P186001,R1,D18P186001R1,49,0.354330891,,ABBA,,D18P186001R1T49,
D18P186001,R1,D18P186001R1,50,5.07874275,,ABBA,,D18P186001R1T50,
D18P186001,R1,D18P186001R1,51,2.401576062,,BEPA,,D18P186001R1T51,
D18P186001,R1,D18P186001R1,52,,,,,D18P186001R1T52,
D18P186001,R1,D18P186001R1,53,,,BEPA,,D18P186001R1T53,
D18P186001,R1,D18P186001R1,54,,,BEPA,,D18P186001R1T54,
D18P186001,R1,D18P186001R1,55,1.614174062,,BEPA,,D18P186001R1T55,
D18P186001,R1,D18P186001R1,56,2.401576062,,,,D18P186001R1T56,
D18P186001,R1,D18P186001R1,57,2.992127562,,,,D18P186001R1T57,
D18P186001,R1,D18P186001R1,58,2.204725562,,,,D18P186001R1T58,
D18P186001,R1,D18P186001R1,59,4.96063275,,ABBA,,D18P186001R1T59,
D18P186001,R1,D18P186001R1,60,1.456693719,,ABBA,,D18P186001R1T60,
D18P186001,R1,D18P186001R1,61,,,BEPA,,D18P186001R1T61,
D18P186001,R1,D18P186001R1,62,0.905512281,,BEPA,,D18P186001R1T62,
D18P186001,R1,D18P186001R1,63,1.023622562,,BEPA,,D18P186001R1T63,
D18P186001,R1,D18P186001R1,64,1.732284438,,ABBA,,D18P186001R1T64,
D18P186001,R1,D18P186001R1,65,0.629921609,,BEPA,,D18P186001R1T65,
D18P186001,R1,D18P186001R1,66,6.65354675,,ABBA,,D18P186001R1T66,
D18P186001,R1,D18P186001R1,67,7.204728,,ABBA,34,D18P186001R1T67,
D18P186001,R1,D18P186001R1,68,1.259843219,,ABBA,,D18P186001R1T68,
D18P186001,R1,D18P186001R1,69,5.66929425,,ABBA,,D18P186001R1T69,
D18P186001,R1,D18P186001R1,70,7.6771695,,ABBA,28,D18P186001R1T70,
D18P186001,R1,D18P186001R1,71,0.5905515,,BEPA,,D18P186001R1T71,
D18P186001,R1,D18P186001R1,72,5.629924375,,ABBA,25,D18P186001R1T72,
D18P186001,R1,D18P186001R1,73,0.275590695,,BEPA,,D18P186001R1T73,
D18P186001,R1,D18P186001R1,74,0.314960805,,BEPA,,D18P186001R1T74,
D18P186001,R1,D18P186001R1,75,0.354330891,,BEPA,,D18P186001R1T75,
D18P186001,R1,D18P186001R1,76,0.472441219,,BEPA,,D18P186001R1T76,
D18P186001,R1,D18P186001R1,77,0.944882438,,ABBA,,D18P186001R1T77,
D18P186001,R1,D18P186001R1,78,0.393701,,BEPA,,D18P186001R1T78,
D18P186001,R1,D18P186001R1,79,5.433073875,,ABBA,,D18P186001R1T79,
D18P186001,R1,D18P186001R1,80,8.03150025,,ABBA,,D18P186001R1T80,
D18P186001,R1,D18P186001R1,81,,,ABBA,,D18P186001R1T81,
D18P186001,R1,D18P186001R1,82,0.157480402,,BEPA,,D18P186001R1T82,
D18P186001,R1,D18P186001R1,83,0.118110305,,BEPA,,D18P186001R1T83,
D18P186001,R1,D18P186001R1,84,0.118110305,,BEPA,,D18P186001R1T84,
D18P186001,R1,D18P186001R1,85,0.118110305,,BEPA,,D18P186001R1T85,
D18P186001,R1,D18P186001R1,86,0.118110305,,BEPA,,D18P186001R1T86,
D18P186001,R1,D18P186001R1,87,0.157480402,,BEPA,,D18P186001R1T87,
D18P186001,R1,D18P186001R1,88,0.275590695,,BEPA,,D18P186001R1T88,
D18P186001,R1,D18P186001R1,89,1.102362781,,BEPA,,D18P186001R1T89,
D18P186001,R1,D18P186001R1,90,0.314960805,,BEPA,,D18P186001R1T90,
D18P186001,R1,D18P186001R1,91,0.1968505,,BEPA,,D18P186001R1T91,
D18P186001,R1,D18P186001R1,92,0.629921609,,ABBA,,D18P186001R1T92,
D18P186001,R1,D18P186001R1,93,0.1968505,,ABBA,,D18P186001R1T93,
D18P186001,R1,D18P186001R1,94,0.393701,,ABBA,,D18P186001R1T94,
D18P186001,R1,D18P186001R1,95,0.314960805,,BEPA,,D18P186001R1T95,
D18P186001,R1,D18P186001R1,96,0.393701,,BEPA,,D18P186001R1T96,
D18P186001,R1,D18P186001R1,97,0.275590695,,BEPA,,D18P186001R1T97,
D18P186001,R1,D18P186001R1,98,0.393701,,BEPA,,D18P186001R1T98,
D18P186001,R1,D18P186001R1,99,0.354330891,,BEPA,,D18P186001R1T99,
D18P186001,R1,D18P186001R1,100,0.354330891,,BEPA,,D18P186001R1T100,
D18P186001,R2,D18P186001R2,1,6.3779565,,ABBA,,D18P186001R2T1,
D18P186001,R2,D18P186001R2,2,1.417323562,,BEPA,,D18P186001R2T2,
D18P186001,R2,D18P186001R2,3,,,BEPA,,D18P186001R2T3,
D18P186001,R2,D18P186001R2,4,,,BEPA,,D18P186001R2T4,
D18P186001,R2,D18P186001R2,5,0.314960805,,BEPA,,D18P186001R2T5,
D18P186001,R2,D18P186001R2,6,4.251970875,,ABBA,33,D18P186001R2T6,
D18P186001,R2,D18P186001R2,7,3.58267925,,ABBA,,D18P186001R2T7,
D18P186001,R2,D18P186001R2,8,,,,,D18P186001R2T8,
D18P186001,R2,D18P186001R2,9,2.5590565,,,,D18P186001R2T9,
D18P186001,R2,D18P186001R2,10,1.220473062,,,,D18P186001R2T10,
D18P186001,R2,D18P186001R2,11,1.614174062,,BEPA,,D18P186001R2T11,
D18P186001,R2,D18P186001R2,12,5.07874275,,ABBA,,D18P186001R2T12,
D18P186001,R2,D18P186001R2,13,4.1338605,,ABBA,,D18P186001R2T13,
D18P186001,R2,D18P186001R2,14,1.3779535,,ABBA,,D18P186001R2T14,
D18P186001,R2,D18P186001R2,15,5.433073875,,ABBA,35,D18P186001R2T15,
D18P186001,R2,D18P186001R2,16,4.37008125,,ABBA,35,D18P186001R2T16,
D18P186001,R2,D18P186001R2,17,1.220473062,,ABBA,,D18P186001R2T17,
D18P186001,R2,D18P186001R2,18,1.181103,,BEPA,,D18P186001R2T18,
D18P186001,R2,D18P186001R2,19,0.393701,,BEPA,,D18P186001R2T19,
D18P186001,R2,D18P186001R2,20,0.551181391,,BEPA,,D18P186001R2T20,
D18P186001,R2,D18P186001R2,21,2.834647125,,ABBA,29,D18P186001R2T21,
D18P186001,R2,D18P186001R2,22,,,BEPA,,D18P186001R2T22,
D18P186001,R2,D18P186001R2,23,1.259843219,,ABBA,,D18P186001R2T23,
D18P186001,R2,D18P186001R2,24,5.3149635,,ABBA,32,D18P186001R2T24,
D18P186001,R2,D18P186001R2,25,5.039372875,,ABBA,,D18P186001R2T25,
D18P186001,R2,D18P186001R2,26,,,BEPA,,D18P186001R2T26,
D18P186001,R2,D18P186001R2,27,0.9842525,,BEPA,,D18P186001R2T27,
D18P186001,R2,D18P186001R2,28,4.48819125,,ABBA,,D18P186001R2T28,
D18P186001,R2,D18P186001R2,29,0.393701,,BEPA,,D18P186001R2T29,
D18P186001,R2,D18P186001R2,30,0.551181391,,BEPA,,D18P186001R2T30,
D18P186001,R2,D18P186001R2,31,6.06299525,,ABBA,,D18P186001R2T31,
D18P186001,R2,D18P186001R2,32,5.55118425,,ABBA,,D18P186001R2T32,
D18P186001,R2,D18P186001R2,33,,,,,D18P186001R2T33,
D18P186001,R2,D18P186001R2,34,1.023622562,,,,D18P186001R2T34,
D18P186001,R2,D18P186001R2,35,0.905512281,,,,D18P186001R2T35,
D18P186001,R2,D18P186001R2,36,1.141732938,,,,D18P186001R2T36,
D18P186001,R2,D18P186001R2,37,4.76378225,,ABBA,37,D18P186001R2T37,
D18P186001,R2,D18P186001R2,38,5.94488525,,ABBA,,D18P186001R2T38,
D18P186001,R2,D18P186001R2,39,5.118113,,ABBA,,D18P186001R2T39,
D18P186001,R2,D18P186001R2,40,5.826774875,,ABBA,,D18P186001R2T40,
D18P186001,R2,D18P186001R2,41,5.039372875,,ABBA,,D18P186001R2T41,
D18P186001,R2,D18P186001R2,42,7.5590595,,ABBA,31,D18P186001R2T42,
D18P186001,R2,D18P186001R2,43,5.07874275,,ABBA,,D18P186001R2T43,
D18P186001,R2,D18P186001R2,44,4.842522375,,ABBA,,D18P186001R2T44,
D18P186001,R2,D18P186001R2,45,0.748031891,,ABBA,,D18P186001R2T45,
D18P186001,R2,D18P186001R2,46,1.417323562,,ABBA,,D18P186001R2T46,
D18P186001,R2,D18P186001R2,47,4.5275615,,ABBA,,D18P186001R2T47,
D18P186001,R2,D18P186001R2,48,1.102362781,,ABBA,,D18P186001R2T48,
D18P186001,R2,D18P186001R2,49,0.5905515,,ABBA,,D18P186001R2T49,
D18P186001,R2,D18P186001R2,50,5.27559325,,ABBA,,D18P186001R2T50,
D18P186001,R2,D18P186001R2,51,2.5590565,,BEPA,,D18P186001R2T51,
D18P186001,R2,D18P186001R2,52,,,,,D18P186001R2T52,
D18P186001,R2,D18P186001R2,53,,,BEPA,,D18P186001R2T53,
D18P186001,R2,D18P186001R2,54,,,BEPA,,D18P186001R2T54,
D18P186001,R2,D18P186001R2,55,1.653544125,,BEPA,,D18P186001R2T55,
D18P186001,R2,D18P186001R2,56,2.401576062,,,,D18P186001R2T56,
D18P186001,R2,D18P186001R2,57,3.149608,,,,D18P186001R2T57,
D18P186001,R2,D18P186001R2,58,2.440946125,,,,D18P186001R2T58,
D18P186001,R2,D18P186001R2,59,5.15748325,,ABBA,,D18P186001R2T59,
D18P186001,R2,D18P186001R2,60,1.653544125,,ABBA,,D18P186001R2T60,
D18P186001,R2,D18P186001R2,61,,,BEPA,,D18P186001R2T61,
D18P186001,R2,D18P186001R2,62,0.944882438,,BEPA,,D18P186001R2T62,
D18P186001,R2,D18P186001R2,63,1.102362781,,BEPA,,D18P186001R2T63,
D18P186001,R2,D18P186001R2,64,1.811024562,,ABBA,,D18P186001R2T64,
D18P186001,R2,D18P186001R2,65,0.708661781,,BEPA,,D18P186001R2T65,
D18P186001,R2,D18P186001R2,66,7.12598825,,ABBA,,D18P186001R2T66,
D18P186001,R2,D18P186001R2,67,7.51968925,,ABBA,36,D18P186001R2T67,
D18P186001,R2,D18P186001R2,68,1.3779535,,ABBA,,D18P186001R2T68,
D18P186001,R2,D18P186001R2,69,6.14173575,,ABBA,,D18P186001R2T69,
D18P186001,R2,D18P186001R2,70,8.89764275,,ABBA,30,D18P186001R2T70,
D18P186001,R2,D18P186001R2,71,0.787402,,BEPA,,D18P186001R2T71,
D18P186001,R2,D18P186001R2,72,5.826774875,,ABBA,27,D18P186001R2T72,
D18P186001,R2,D18P186001R2,73,0.354330891,,BEPA,,D18P186001R2T73,
D18P186001,R2,D18P186001R2,74,0.511811281,,BEPA,,D18P186001R2T74,
D18P186001,R2,D18P186001R2,75,0.433071109,,BEPA,,D18P186001R2T75,
D18P186001,R2,D18P186001R2,76,0.551181391,,BEPA,,D18P186001R2T76,
D18P186001,R2,D18P186001R2,77,1.062992719,,ABBA,,D18P186001R2T77,
D18P186001,R2,D18P186001R2,78,0.511811281,,BEPA,,D18P186001R2T78,
D18P186001,R2,D18P186001R2,79,5.826774875,,ABBA,,D18P186001R2T79,
D18P186001,R2,D18P186001R2,80,8.50394175,,ABBA,,D18P186001R2T80,
D18P186001,R2,D18P186001R2,81,,,ABBA,,D18P186001R2T81,
D18P186001,R2,D18P186001R2,82,0.157480402,,BEPA,,D18P186001R2T82,
D18P186001,R2,D18P186001R2,83,0.118110305,,BEPA,,D18P186001R2T83,
D18P186001,R2,D18P186001R2,84,,,BEPA,,D18P186001R2T84,
D18P186001,R2,D18P186001R2,85,,,BEPA,,D18P186001R2T85,
D18P186001,R2,D18P186001R2,86,0.118110305,,BEPA,,D18P186001R2T86,
D18P186001,R2,D18P186001R2,87,,,BEPA,,D18P186001R2T87,
D18P186001,R2,D18P186001R2,88,0.314960805,,BEPA,,D18P186001R2T88,
D18P186001,R2,D18P186001R2,89,,,BEPA,,D18P186001R2T89,
D18P186001,R2,D18P186001R2,90,0.433071109,,BEPA,,D18P186001R2T90,
D18P186001,R2,D18P186001R2,91,0.078740201,,BEPA,,D18P186001R2T91,
D18P186001,R2,D18P186001R2,92,0.708661781,,ABBA,,D18P186001R2T92,
D18P186001,R2,D18P186001R2,93,0.393701,,ABBA,,D18P186001R2T93,
D18P186001,R2,D18P186001R2,94,0.472441219,,ABBA,,D18P186001R2T94,
D18P186001,R2,D18P186001R2,95,,,BEPA,,D18P186001R2T95,
D18P186001,R2,D18P186001R2,96,0.393701,,BEPA,,D18P186001R2T96,
D18P186001,R2,D18P186001R2,97,0.393701,,BEPA,,D18P186001R2T97,
D18P186001,R2,D18P186001R2,98,0.393701,,BEPA,,D18P186001R2T98,
D18P186001,R2,D18P186001R2,99,0.472441219,,BEPA,,D18P186001R2T99,
D18P186001,R2,D18P186001R2,100,0.433071109,,BEPA,,D18P186001R2T100,
D18P186001,R3,D18P186001R3,1,6.92913775,,ABBA,,D18P186001R3T1,
D18P186001,R3,D18P186001R3,2,1.456693719,,BEPA,,D18P186001R3T2,
D18P186001,R3,D18P186001R3,3,,,BEPA,,D18P186001R3T3,
D18P186001,R3,D18P186001R3,4,,,BEPA,,D18P186001R3T4,
D18P186001,R3,D18P186001R3,5,,,BEPA,,D18P186001R3T5,
D18P186001,R3,D18P186001R3,6,4.48819125,,ABBA,37,D18P186001R3T6,
D18P186001,R3,D18P186001R3,7,3.858269875,,ABBA,,D18P186001R3T7,
D18P186001,R3,D18P186001R3,8,,,,,D18P186001R3T8,
D18P186001,R3,D18P186001R3,9,2.716536938,,,,D18P186001R3T9,
D18P186001,R3,D18P186001R3,10,,,,,D18P186001R3T10,
D18P186001,R3,D18P186001R3,11,1.535433938,,BEPA,,D18P186001R3T11,
D18P186001,R3,D18P186001R3,12,5.590554125,,ABBA,,D18P186001R3T12,
D18P186001,R3,D18P186001R3,13,4.37008125,,ABBA,,D18P186001R3T13,
D18P186001,R3,D18P186001R3,14,1.338583438,,ABBA,,D18P186001R3T14,
D18P186001,R3,D18P186001R3,15,5.984255125,,ABBA,39,D18P186001R3T15,
D18P186001,R3,D18P186001R3,16,4.88189225,,ABBA,39,D18P186001R3T16,
D18P186001,R3,D18P186001R3,17,1.338583438,,ABBA,,D18P186001R3T17,
D18P186001,R3,D18P186001R3,18,1.141732938,,BEPA,,D18P186001R3T18,
D18P186001,R3,D18P186001R3,19,,,BEPA,,D18P186001R3T19,
D18P186001,R3,D18P186001R3,20,0.669291719,,BEPA,,D18P186001R3T20,
D18P186001,R3,D18P186001R3,21,3.070867875,,ABBA,33,D18P186001R3T21,
D18P186001,R3,D18P186001R3,22,,,BEPA,,D18P186001R3T22,
D18P186001,R3,D18P186001R3,23,1.259843219,,ABBA,,D18P186001R3T23,
D18P186001,R3,D18P186001R3,24,5.905515,,ABBA,36,D18P186001R3T24,
D18P186001,R3,D18P186001R3,25,5.433073875,,ABBA,,D18P186001R3T25,
D18P186001,R3,D18P186001R3,26,,,BEPA,,D18P186001R3T26,
D18P186001,R3,D18P186001R3,27,1.023622562,,BEPA,,D18P186001R3T27,
D18P186001,R3,D18P186001R3,28,4.96063275,,ABBA,,D18P186001R3T28,
D18P186001,R3,D18P186001R3,29,,,BEPA,,D18P186001R3T29,
D18P186001,R3,D18P186001R3,30,0.511811281,,BEPA,,D18P186001R3T30,
D18P186001,R3,D18P186001R3,31,6.6141765,,ABBA,,D18P186001R3T31,
D18P186001,R3,D18P186001R3,32,6.06299525,,ABBA,,D18P186001R3T32,
D18P186001,R3,D18P186001R3,33,,,,,D18P186001R3T33,
D18P186001,R3,D18P186001R3,34,0.9842525,,,,D18P186001R3T34,
D18P186001,R3,D18P186001R3,35,,,,,D18P186001R3T35,
D18P186001,R3,D18P186001R3,36,1.220473062,,,,D18P186001R3T36,
D18P186001,R3,D18P186001R3,37,5.236223375,,ABBA,41,D18P186001R3T37,
D18P186001,R3,D18P186001R3,38,6.4960665,,ABBA,,D18P186001R3T38,
Solution 1:
The real answer
Basically, your code written like you have programmed a lot in other languages but never used R
. It is hard to understand exactly what is going on because of all the nested loops, and I haven't run your code (see here for how to include data reproducibly).
I think though that all the loops can be removed, for example replacing the first condition with something like:
FVS_TreeInit$GD[
FVS_TreeInit$Plot_ID == "R8" &
FVS_TreeInit$StandPlotTree_ID == paste(FVS_TreeInit$Stand_ID,"R7T",FVS_TreeInit$Tree_ID,sep="")
] <- FVS_TreeInit$DBH
It will be significantly quicker if you use data.table
(here), just because it's such a fast implementation.
Cheap and easy answer
There is a cheap and easy way to speed up what you have without refactoring all the code, but it is still going to be slow.
The problem is that you constantly are looking up data with df[i, "columnName"]
. This is a very slow way to do it. Look at this example.
Create two random large (10e6
rows) data frame of strings:
# Random data function borrowed from: https://www.r-bloggers.com/2017/03/fast-data-lookups-in-r-dplyr-vs-data-table/
random_string_column <- function(n) {
stringi::stri_rand_strings(n = n, length = 8)
}
random_data_frame <- function(n) tibble(
col1 = random_string_column(n),
col2 = random_string_column(n)
)
df <- random_data_frame(10^6)
df2 <- random_data_frame(10^6)
head(df)
Output (df2 will be similar):
# A tibble: 6 x 2
col1 col2
<chr> <chr>
1 NykzxkNO qGusGkMa
2 mgivTVky xlCtwEba
3 zar6FbC4 dOYeQPfg
4 89fKLJFv RPsP2CZc
5 V2FH3Smt ObToBJFC
6 gXa0j5XZ QYKK6hD2
Now let's do 1000 random lookups your way:
rand_indeces <- sample(c(1:nrow(df), 1000))
system.time(
for(i in rand_indeces) {
if(df[i, "col2"]=="aaaaa") { #it never will
break
}
}
)
Output:
user system elapsed
138.58 0.23 140.72
Over two minutes. Now let's look in the other dataframe (new df
so we can see it's not because of caching), replacing the df[i, "col2"]=="aaaaa"
syntax with df2$col2[i] == "aaaaa"
.
system.time(
for(i in rand_indeces) {
if(df2$col2[i] == "aaaaa") { #it never will
break
}
}
)
Output:
user system elapsed
4.70 0.00 4.75
This should save you quite a bit of time. However, fundamentally doing lookups this way in R is slow (see here and here).
If you must do individual lookups, you can consider creating a hash table, either through environments
as in the first link or through some of the newer methods here. I think the collections
package looks intriguing - haven't used it yet.
However, by far the best thing to do would be to vectorise your code, as outlined at the top of this response.
Solution 2:
(Spoiler: jump to the Double Merge section for a result that is 150x faster than your nested loop. I expect this speed improvement to get better with larger data.)
Intermediate Improvements
First, your inner loops can all be reduced out of a for
loop to be much faster, perhaps changing
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R0T",FVS_TreeInit[i,"Tree_ID"],sep="")
for (f in seq_len(nrow(FVS_TreeInit))){
if (FVS_TreeInit[f,"StandPlotTree_ID"] == find){
FVS_TreeInit[i,"GD"] <- FVS_TreeInit[f,"DBH"]
break
}
}
to
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R0T",FVS_TreeInit[i,"Tree_ID"],sep="")
f <- FVS_TreeInit[,"StandPlotTree_ID"] == find
FVS_TreeInit[i,"GD"] <- FVS_TreeInit[f,"DBH"]
Notable in that is that we've changed from an iterative for
loop to a vectorized comparison, which in R tends to be much faster. However, one should note that we are doing the same thing for several "R*"
, so we can reduce your outer loop quite a bit; much of this is code-golf (reduce the number of characters to do the same thing), but in general don't repeat yourself": if you have the same (identical) code in multiple places, you increase the chances of changing one and not all of the others.
In that theme, I can get the same results so far by using this:
# loop through FVS_TreeInit and add previous diameter increment identifier to current row
for (i in seq_len(nrow(FVS_TreeInit))){
if (FVS_TreeInit[i,"Plot_ID"] == "R8"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R7T",FVS_TreeInit[i,"Tree_ID"],sep="")
} else if (FVS_TreeInit[i,"Plot_ID"] == "R7"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R6T",FVS_TreeInit[i,"Tree_ID"],sep="")
} else if (FVS_TreeInit[i,"Plot_ID"] == "R6"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R5T",FVS_TreeInit[i,"Tree_ID"],sep="")
} else if (FVS_TreeInit[i,"Plot_ID"] == "R5"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R4T",FVS_TreeInit[i,"Tree_ID"],sep="")
} else if (FVS_TreeInit[i,"Plot_ID"] == "R4"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R3T",FVS_TreeInit[i,"Tree_ID"],sep="")
} else if (FVS_TreeInit[i,"Plot_ID"] == "R3"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R2T",FVS_TreeInit[i,"Tree_ID"],sep="")
} else if (FVS_TreeInit[i,"Plot_ID"] == "R2"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R1T",FVS_TreeInit[i,"Tree_ID"],sep="")
} else if (FVS_TreeInit[i,"Plot_ID"] == "R1"){
find <- paste(FVS_TreeInit[i,"Stand_ID"],"R0T",FVS_TreeInit[i,"Tree_ID"],sep="")
} else {
find <- NA
}
FVS_TreeInit[i,"GD"] <- NA
if (!is.na(find)) {
f <- FVS_TreeInit[,"StandPlotTree_ID"] == find
if (any(f)) FVS_TreeInit[i,"GD"] <- FVS_TreeInit[f,"DBH"]
}
if (i%%1000 == 0){
print(paste(i," rows iterated...",sep=""))
}
}
Okay, that's shorter, and narrowing down to what is really important. Notably (for me), that we're effectively "joining" data together here based on some specific values. I think we can do all of that in much simpler steps (merges).
Double Merge
This is really just joining data back on itself based on three IDs: Stand_ID
, Tree_ID
, and Plot_ID
, where the latter is a time-component (and therefore needs to be adjusted for the self-join).
Stemming from the idea that your R*
values reflect time, I think we can safely assuming that R(n)
should be assigned to R(n+1)
, so let's create this intermediate frame programmatically:
prevPlot <- data.frame(prev_Plot_ID = unique(FVS_TreeInit$Plot_ID))
prevPlot$Plot_ID <- paste0("R", as.integer(gsub("R", "", prevPlot$prev_Plot_ID))-1)
prevPlot <- subset(prevPlot, prev_Plot_ID != "R0")
prevPlot
# prev_Plot_ID Plot_ID
# 2 R1 R0
# 3 R2 R1
# 4 R3 R2
We'll merge/join this onto the original FVS_Tree_Init
in order to identify the "previous Plot_ID
" and then merge back on itself to bring in the new value.
prevValues <- subset(merge(FVS_TreeInit, prevPlot, by = "Plot_ID", all.x = TRUE),
select = c(Stand_ID, prev_Plot_ID, Tree_ID, DBH))
names(prevValues)[4] <- "GD"
head(prevValues)
# Stand_ID prev_Plot_ID Tree_ID GD
# 1 D18P186001 R1 39 3.9370100
# 2 D18P186001 R1 40 4.2519709
# 3 D18P186001 R1 1 4.7637823
# 4 D18P186001 R1 2 1.2598432
# 5 D18P186001 R1 3 0.2755907
# 6 D18P186001 R1 4 0.6299216
new_FVS_TreeInit <- merge(
FVS_TreeInit, prevValues,
by.x = c("Stand_ID", "Plot_ID", "Tree_ID"),
by.y = c("Stand_ID", "prev_Plot_ID", "Tree_ID"),
all.x = TRUE)
identical(expected, new_FVS_TreeInit[names(expected)])
# [1] TRUE
where expected
is the output from your nested for
loop, and new_FVS_TreeInit[names(expected)]
is just a step to ensure all columns are in the same order (for comparison with identical
, not required for data processing).
FYI, this brings into focus the contradiction of your use of concatenated strings as singular keys (a fairly Excel-method for doing joins ... it works, certainly) with the premise of merging/joining data on one or more keys. Once you dismiss the singular-key Excel method and recognize that one or more works just as well -- and can be easier to read and maintain -- I think shifting a mindset to merges can be transformative to programming. See How to join (merge) data frames (inner, outer, left, right) and What's the difference between INNER JOIN, LEFT JOIN, RIGHT JOIN and FULL JOIN? for more discussion on the "calculus" of joins.
Benchmark
With this sample data, this performs about 150x faster.
bench::mark(
forloop = {
# your code
},
doublemerge = {
# my code
}
)
# Warning: Some expressions had a GC in every iteration; so filtering is disabled.
# # A tibble: 2 x 13
# expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time result memory time gc
# <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm> <list> <list> <list> <list>
# 1 forloop 272.4ms 284.86ms 3.51 656KB 7.02 2 4 570ms <df [318 x 11]> <Rprofmem ~ <bench_t~ <tibble ~
# 2 doublemerge 1.4ms 1.55ms 528. 346KB 1.99 265 1 502ms <df [318 x 11]> <Rprofmem ~ <bench_t~ <tibble ~
Solution 3:
I believe this can be reframed in a simpler way with much less code. It looks like you're doing a join on the data, where the lookup key is a modified version of the current Plot_ID where "R#" should be linked to "R#-1T".
A more idiomatic way to do this in R would be to create the appropriate key once for all rows, and then do a join based on that lookup key. That will be orders of magnitude faster than your loop approach, since it only needs to compile the lookup code once instead of 650,000 times, and joins are optimized for speed. See this page for an in-depth explanation why vectorization helps so much in R: https://www.noamross.net/archives/2014-04-16-vectorization-in-r-why/
I do this using dplyr below, but the approach would work very similarly in base r.
library(dplyr)
FVS_TreeInit %>%
# create key for all rows
mutate(prior_key = paste0(Stand_ID, "R",
parse_number(Plot_ID)-1, "T", # will be nonsense R-1T when starts from R0, that's ok,
Tree_ID)) %>% # it just won't replace GD there
# Use that key to join to a version of the data with just StandPlotTree_ID and
# DBH, which I rename as GD. Match `prior_key` with `StandPlotTree_ID` there.
left_join(FVS_TreeInit %>% transmute(StandPlotTree_ID, GD = DBH),
by = c("prior_key" = "StandPlotTree_ID"))
Benchmark
Your original code took 3.7 seconds to run on the provided sample data. My suggested replacement took 0.027 seconds, about a 140x speed replacement. I expect the time difference will grow much wider with larger data.
Solution 4:
A single-pass data.table
solution:
This can be accomplished in a single pass after ordering by Stand_ID
, Tree_ID
, then Plot_ID
(~6 milliseconds on my machine, including reading the data).
First, I copied the example data string to the object data
.
library(data.table)
dt <- fread(input = data) # read into a data.table
setorder(dt[, `:=`(Plot_ID = as.integer(substr(Plot_ID, 2, 2)), DG = as.numeric(DG))], # convert Plot_ID to an integer and DG to numeric (from logical)
# order by Stand_ID, Tree_ID, Plot_ID
Stand_ID, Tree_ID, Plot_ID)[
# create a temporary column indicating the rows that will pull DBH from the previous row
, pull := c(FALSE, diff(Plot_ID) == 1L) & Stand_ID == shift(Stand_ID) & Tree_ID == shift(Tree_ID)][
# pull DBH from the previous row where appropriate
pull == TRUE, DG := shift(dt$DBH)[dt$pull]][,
# clean up
`:=`(pull = NULL, Plot_ID = paste0("R", Plot_ID))]