2017-08-28 11 views
9

चलो कहते हैं कि मैं निम्नलिखित की तरह कई पंक्तियों के साथ एक डेटा फ्रेम करते हैं:मान चुनें पंक्ति-वार दिनांकों के बीच रैंक के आधार पर

df <- data.frame(a = c(NA,20,NA), 
       date1 = c("2016-03-01", "2016-02-01", "2016-02-01"), 
       b = c(50,NA, NA), 
       date2 = c("2016-02-01", "2016-03-01", "2016-03-01"), 
       c = c(10,10, 10), 
       date3 = c("2016-01-01","2016-01-01", "2016-01-01")) 

प्रत्येक पंक्ति के लिए, मैं नवीनतम मूल्य जो एक NA नहीं है प्राप्त करना चाहते हैं a, b, और cdates के अनुसार (इसलिए मैं क्रमश: date1, date2, या date3 पर देखता हूं और सबसे हालिया चुनता हूं)।

असल में, date1 दिनांक मान b करने के लिए इसी, date3 दिनांक मान c करने के लिए इसी देता है देता है दिनांक मान a, date2 करने के लिए इसी देता है।

तो date1 > date2 & date1 > date3, मैं, मैं date2 और date3 की तुलना करेंगे, मूल्य लेने के लिए a हालांकि चाहते हैं, तो मूल्य aNA है (जो मेरे उदाहरण में मामला है)। मेरे उदाहरण में, date2 > date3, और चूंकि मान bNA नहीं है लेकिन 50 है, तो मैं अपने अंतिम परिणाम के रूप में 50 ले जाऊंगा।

अब मैं जब से मैं dplyr उपयोग कर रहा हूँ मेरी dataframe

में सभी पंक्तियों के लिए ऐसा करना चाहते हैं, मैं पद समारोह (उपयोग करते हुए मेरे उदाहरण में से case_when फ़ंक्शन का उपयोग करने की कोशिश की, मैं एक पहले स्थान पर देखो तिथि, और फिर लिंक किए गए मान को देखें। यदि यह एनए है, तो मैं दूसरी सबसे अच्छी रैंकिंग इत्यादि देखता हूं ...)

हालांकि, मैं बस इतना नहीं कर सकता, जैसा कि मैं करना चाहता हूं, :

df <- df %>% 
     mutate(result = case_when(is.na(a) & is.na(b) & is.na(c) ~ NA_integer_, 
            rev(rank(date1, date2, date3))[1] == 3 & !is.na(a) ~ a, 
            rev(rank(date1, date2, date3))[2] == 3 & !is.na(b) ~ b, 
            rev(rank(date1, date2, date3))[3] == 3 & !is.na(a) ~ c, 
            rev(rank(date1, date2, date3))[1] == 2 & !is.na(a) ~ a, 
            rev(rank(date1, date2, date3))[2] == 2 & !is.na(b) ~ b, 
            rev(rank(date1, date2, date3))[3] == 2 & !is.na(a) ~ c, 
            rev(rank(date1, date2, date3))[1] == 1 & !is.na(a) ~ a, 
            rev(rank(date1, date2, date3))[2] == 1 & !is.na(b) ~ b, 
            rev(rank(date1, date2, date3))[3] == 1 & !is.na(a) ~ c)) 

क्योंकि rank फ़ंक्शन की आवश्यकता है तर्क के रूप में एक अनूठा वेक्टर (लेकिन मैं c(date1, date2, date3) नहीं डाल सकते न क्योंकि यह मुझे इस सदिश का नहीं पूरे आदेश और प्रत्येक पंक्ति के लिए पद देना होगा)

मेरी उदाहरण परिणाम रहा है करने के लिए

होगा चाहते हैं में
res 

a date1   b  date2  c date3  result 
NA 2016-03-01 50  2016-02-01 10 2016-01-01 50 
20 2016-02-01 NA  2016-03-01 10 2016-01-01 20 
NA 2016-02-01 NA  2016-03-01 10 2016-01-01 10 

क्या किसी के पास इस समस्या का कोई विचार या यहां तक ​​कि एक पूरी तरह से अलग दृष्टिकोण है?

उत्तर

4

मैं लंबे समय से प्रारूप में परिवर्तित और प्रासंगिक मूल्यों की गणना करने का सुझाव है। यदि आप चाहते हैं, तो आप परिणाम को अपने मूल डेटा में जोड़ सकते हैं। फ्रेम। यहाँ कैसे आपको लगता है कि data.table का उपयोग कर सकते हैं:

library(data.table) 
setDT(df)      # convert to data.table object 
df[, row := .I]    # add a row-id 
dflong <- melt(df, id = "row", measure = patterns("^date", "^(a|b|c)"), 
       na.rm = TRUE) # convert to long format 
setorder(dflong, value1)  # reorder by date value 
dflong <- unique(dflong, by = "row", fromLast = TRUE) # get the latest dates 
df[dflong, result := i.value2, on = "row"] # add result to original data 

df 
# a  date1 b  date2 c  date3 row result 
#1: NA 2016-03-01 50 2016-02-01 10 2016-01-01 1  50 
#2: 20 2016-02-01 NA 2016-03-01 10 2016-01-01 2  20 
#3: NA 2016-02-01 NA 2016-03-01 10 2016-01-01 3  10 
+0

धन्यवाद! मैं डेटा.table ऑब्जेक्ट के उपयोग के लिए एल्गोरिदम धन्यवाद की गति से प्रभावित हूं – MBB

2

यहाँ एक तरह से यह करने के लिए ...

df$result <- apply(df, 1, function(x){ 
    dates <- as.Date(x[seq(2, length(x), 2)]) 
    values <- x[seq(1,length(x),2)] 
    return(values[!is.na(values)][which.max(dates[!is.na(values)])]) 
}) 

df 
    a  date1 b  date2 c  date3 result 
1 NA 2016-03-01 50 2016-02-01 10 2016-01-01  50 
2 20 2016-02-01 NA 2016-03-01 10 2016-01-01  20 
3 NA 2016-02-01 NA 2016-03-01 10 2016-01-01  10 
3

यह इसे संभाल चाहिए। सबसे पहले हमने डेटा को साफ-सुथरा रूप में रखा (प्रत्येक पंक्ति के लिए 1 पंक्ति, वैल्यू, पंक्ति_नम के साथ यह पहचानने के लिए कि किस प्रकार की साफ पंक्ति संबंधित है)। फिर हम एनएएस, group_by row_num, दिनांक अवरोही के अनुसार आदेश फ़िल्टर करते हैं, और पहली पंक्ति लेते हैं।

df %>% 
    mutate(row_num = row_number()) %>% 
    unite(a, a, date1) %>% 
    unite(b, b, date2) %>% 
    unite(c, c, date3) %>% 
    gather(key, value, -row_num) %>% 
    select(-key) %>% 
    separate(value, into=c("Value", "Date"), sep = "_") %>% 
    mutate(Date = as.Date(Date)) %>% 
    filter(Value != "NA") %>% 
    group_by(row_num) %>% 
    top_n(1, Date) %>% 
    ungroup() 

Results

1
यहाँ

एक और दृष्टिकोण:

df$row <- 1:nrow(df) 

gather(df, key, date_val, date1, date2, date3, -row) %>% 
    select(-key) %>% 
    gather(key, val, a,b,c) %>% 
    filter(!is.na(val)) %>% 
    group_by(row) %>% 
    mutate(max_date = max(date_val)) %>% 
    filter(date_val == max_date) %>% summarise(result = max(val)) %>% 
    left_join(df, by="row") %>% select(-row) 

# A tibble: 3 × 7 
    result  a  date1  b  date2  c  date3 
    <dbl> <dbl>  <fctr> <dbl>  <fctr> <dbl>  <fctr> 
1  50 NA 2016-03-01 50 2016-02-01 10 2016-01-01 
2  20 20 2016-02-01 NA 2016-03-01 10 2016-01-01 
3  10 NA 2016-02-01 NA 2016-03-01 10 2016-01-01 
1

एक और base विकल्प:

df$id <- 1:nrow(df) 
d2 <- reshape(df, varying = list(seq(1, by = 2, len = (ncol(df) - 1)/2), 
           seq(2, by = 2, len = (ncol(df) - 1)/2)), 
       direction = "long") 

d2 <- with(d2, d2[order(-id, date1, decreasing = TRUE), ]) 

cbind(df, res = tapply(d2$a[!is.na(d2$a)], d2$id[!is.na(d2$a)], `[`, 1)) 
# a  date1 b  date2 c  date3 id res 
# 1 NA 2016-03-01 50 2016-02-01 10 2016-01-01 1 50 
# 2 20 2016-02-01 NA 2016-03-01 10 2016-01-01 2 20 
# 3 NA 2016-02-01 NA 2016-03-01 10 2016-01-01 3 10 
0

पार्टी खत्म हो गया था, लेकिन मैं तो बस इस पोस्ट में आए और करने का निर्णय लिया निम्नलिखित छोड़ दो। विचार यह था कि मैं डेटा फ्रेम बनाना और नौकरी करना चाहता था।

out <- data.frame(group = 1:nrow(df), 
        date = as.Date(unlist(df[, grep(x = names(df), "[1-9]")]), 
           "%Y-%m-%d"), 
        result = unlist(df[nchar(names(df)) == 1])) %>% 
     filter(complete.cases(.)) %>% 
     group_by(group) %>% 
     slice(which.max(date)) %>% 
     ungroup 

cbind(df, result = out$result) 

# a  date1 b  date2 c  date3 result 
#1 NA 2016-03-01 50 2016-02-01 10 2016-01-01  50 
#2 20 2016-02-01 NA 2016-03-01 10 2016-01-01  20 
#3 NA 2016-02-01 NA 2016-03-01 10 2016-01-01  10 

यदि मैं डेटाटेबल का उपयोग करता हूं, तो मैं निम्नलिखित कार्य करता हूं, जो डॉकेंडो के उत्तर पर आधारित है।

setDT(df)[, row := .I] 

out <- melt(df, id = "row", measure = patterns("^date", "^(a|b|c)"), 
      value.name = c("date", "result"), na.rm = TRUE) [, 
       date := as.Date(date, "%Y-%m-%d")][, 
        .SD[which.max(date)], by = row][, c("row", "result")] 

df[out, on = "row"] 

# a  date1 b  date2 c  date3 row result 
#1: 20 2016-02-01 NA 2016-03-01 10 2016-01-01 2  20 
#2: NA 2016-03-01 50 2016-02-01 10 2016-01-01 1  50 
#3: NA 2016-02-01 NA 2016-03-01 10 2016-01-01 3  10 
संबंधित मुद्दे