मुझे नीचे नेस्टेड लूप को तेज करने की जरूरत है। आइटम आईडी से जुड़े स्कोर तिथि के अनुसार दर्ज किए जाते हैं। एकाधिक अंकों वाले प्रत्येक आइटम के लिए, मुझे स्कोर और उनके बीच की समय दूरी को जोड़ने की आवश्यकता है। नीचे दिए गए टॉय डेटा पर, यह ठीक काम करता है, लेकिन जब परीक्षण डेटा को दसियों हज़ार पंक्तियों वाले डेटा से बदल दिया जाता है, तो यह उपयोगी होने के लिए बहुत धीमा हो जाता है। क्या ऐसा करने के बेहतर तरीके हैं?
# create some simulated data
test <- matrix(1:18, byrow=TRUE, nrow=6)
test[,1] <- c(1,2,1,3,2,3)
test[,2] <- c(70,92,62,90,85,82)
test[,3] <- c("2019-01-01","2019-01-01", "2020-01-01", "2019-01-01", "2020-01-01", "2020-01-01")
colnames(test) <- c("ID", "Score", "Date")
test <- data.frame(test)
test$Date <- as.Date(test$Date)
# create a dataframe to hold all the post-loop data
df <- data.frame(matrix(ncol = 4, nrow = 0))
col_names <- c("ID", "Years", "BeginScore", "EndScore")
# get all the unique item IDs
ids <- unique(test$ID)
# loop through each unique item id
for(i in 1:length(ids))
{
# get all the instances of that single item
item <- test[test$ID == ids[i],]
# create a matrix to hold the data
scores <- data.frame(matrix(1:((nrow(item)-1)*4), byrow=TRUE, nrow=nrow(item)-1))
colnames(scores) <- col_names
# create an index, starting at the last (bc real data is ordered by data)
index <- nrow(item)
# loop through the list of instances of the sigle item and assign info
for(j in 1:(nrow(item)-1))
{
scores$Years <- time_length(item[index,3]-item[(index -1),3], "years")
scores$BeginScore <- item[(index-1),2]
scores$EndScore <- item[index, 2]
scores$ID <- item[index,1]
index <- index - 1
}
# bind the single item to the collected data and then loop to next unique item
df <- rbind(df, scores)
}
2 जवाब
for
लूप ऐसे ऑपरेशन के लिए सही टूल नहीं है। एक खाली मैट्रिक्स/डेटाफ्रेम बनाना और इसे भरना भी आर में बहुत अक्षम है।
हज़ारों पंक्तियाँ बहुत अधिक डेटा नहीं हैं। आप इस dplyr
दृष्टिकोण को आजमा सकते हैं।
library(dplyr)
library(lubridate)
test %>%
mutate(Date = as.Date(Date)) %>%
group_by(ID) %>%
summarise(BeginScore = nth(Score, n() - 1),
EndScore = last(Score),
Years = time_length(last(Date) - nth(Date, n() - 1), 'years'))
# ID BeginScore EndScore Years
# <chr> <chr> <chr> <dbl>
#1 1 70 62 0.999
#2 2 92 85 0.999
#3 3 90 82 0.999
Data.table और lubridate का उपयोग करना:
library(data.table)
library(lubridate)
setDT(test)
df <- test[, .(Years = time_length(max(Date) - min(Date), "years"), BeginScore = max(Score), EndScore = min(Score)), by = ID]
का उत्पादन
ID Years BeginScore EndScore
1 1 0.9993155 70 62
2 2 0.9993155 92 85
3 3 0.9993155 90 82
जोड़ने के लिए संपादित करें:
चूंकि min
/ max
काम नहीं करेगा यदि एक ही आईडी के साथ कई रिकॉर्ड हैं, तो इसके बजाय निम्नलिखित कोड का उपयोग किया जा सकता है:
test[, .(Years = time_length(Date[.N] - Date[.N - 1], "years"), BeginScore = Score[.N - 1], EndScore = Score[.N]), by = ID]