I've already solved my problem, but I want to know if there is a more time-efficient way to solve it.
I have a 22 million rows x 9 columns dataframe, with columns having the following structure:
factorID = factor with 99000 levels
Date = date
RDate = numeric (date as progressive number as computed by R, number of days since 01/01/1970)
V1:V6 = integer
Each factor level is comprised by a time series of 231 intra-annual observations that cover a time-span of 40 years. Due to misfunctions, some observations present NA values, which could be shared across all 6 variables or confined to only 1. I wanted to replace those NA values with the nearest observation in the time domain, mainly the previous or next one (the simplest case, but sometimes the previous or next one were also NA).
To solve my problem, I tried and succeded with nested for loops:
## Isolating one factor at a time with the first loop, since NA amount and position
## differ for each level
for (i in 1:length(levels(df$factorID))){
ID = levels(df$factorID)[i]
Point_df <- subset(df, df$factorID == ID)
## Calculating total amount and position of NA and integer values by column,
## and identify them by their RDate
## If NA values are present in the column, execute the third loop
for (j in 1:6){
ID_column = j+3
NAcheck <- is.na(Point_df[[ID_column]])
difference_table <- cbind.data.frame(Point_df$RDate, NAcheck)
NoNA <- subset(difference_table, difference_table$NAcheck == FALSE)
True_NA <- subset(difference_table, difference_table$NAcheck == TRUE)
colnames(True_NA)[1] <- "RDate"
colnames(NoNA)[1] <- "RDate"
if (length(True_NA$RDate) > 0){
## With the third loop I compute the nearest not NA observation based on the
## minimum absolute value difference in the time domain (treating the date as a progressive number),
## then I replace one NA at a time
for (k in 1:length(True_NA$NAcheck)){
difference <- abs(True_NA$RDate[k]-NoNA$RDate)
difference_list <- cbind.data.frame(NoNA$RDate, difference)
replacing_difference <- min(difference)
replacing_date <- subset(difference_list, difference_list$difference==replacing_difference)
NA_tochange <- subset(Point_df, Point_df$RDate == True_NA$RDate[k])
replacing_value <- subset(Point_df, Point_df$RDate == replacing_date[1,1])
NA_tochange[[ID_column]] <- replacing_value[[ID_column]]
row <- as.numeric(rownames(True_NA)[k])
Point_df[row] <- NA_tochange
}
}
}
## Writing the new dataframe one level at a time
fwrite(Point_df, "B:/Point-predictors_NA-replaced.csv", append=TRUE, sep=",")
}
As you can imagine, solving the problem in this way is extremely time-consuming (using data.table with 2 threads on my notebook took 12 hours or so: the whole dataframe is more than 1 GB and each iteration of the whole loop writes something like 15-30 KB of data).
As I mentioned, since each ID has its own peculiarities, I couldn't come up with anything to automate the task better. How do you think the whole operation could be sped up?
Thanks a lot.
Edit As requested, I attach some examples; I didn't want to make the post longer than what it already was.
Sample data:
factorID Date RDate V1 V2 V3 V4 V5 V6
1 1989-02-06 6976 318 351 172 570 260 108
1 1989-05-13 7072 77 NA 591 NA 801 550
1 1989-05-29 7088 NA NA NA NA NA NA
1 1989-06-14 7104 252 305 286 835 271 85
.
2 1989-02-06 6976 236 389 323 2078 908 373
2 1989-05-13 7072 77 NA 591 NA 801 550
2 1989-05-29 7088 55 62 410 2001 NA NA
2 1989-06-14 7104 351 508 456 1618 780 421
Desired outcome:
factorID Date RDate V1 V2 V3 V4 V5 V6
1 1989-02-06 6976 318 351 172 570 260 108
1 1989-05-13 7072 77 351 591 570 801 550
1 1989-05-29 7088 77 351 591 570 801 550
1 1989-06-14 7104 252 305 286 835 271 85
.
2 1989-02-06 6976 236 389 323 2078 908 373
2 1989-05-13 7072 77 62 591 2001 801 550
2 1989-05-29 7088 55 62 410 2001 801 550
2 1989-06-14 7104 351 508 456 1618 780 421
I hope this will help.