मुझे नीचे नेस्टेड लूप को तेज करने की जरूरत है। आइटम आईडी से जुड़े स्कोर तिथि के अनुसार दर्ज किए जाते हैं। एकाधिक अंकों वाले प्रत्येक आइटम के लिए, मुझे स्कोर और उनके बीच की समय दूरी को जोड़ने की आवश्यकता है। नीचे दिए गए टॉय डेटा पर, यह ठीक काम करता है, लेकिन जब परीक्षण डेटा को दसियों हज़ार पंक्तियों वाले डेटा से बदल दिया जाता है, तो यह उपयोगी होने के लिए बहुत धीमा हो जाता है। क्या ऐसा करने के बेहतर तरीके हैं?

# 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)
}
-1
coolhand 25 जिंदा 2021, 03:19

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
3
Ronak Shah 25 जिंदा 2021, 06:05

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]
0
PavoDive 25 जिंदा 2021, 06:13