2012-02-27 11 views
10

मेरे पास प्रत्येक प्रतिभागी के लिए कई समय आकलन के साथ एक डेटा सेट है। मैं प्रत्येक प्रतिभागी के लिए अंतिम मूल्यांकन का चयन करना चाहता हूं। मेरे डाटासेट इस तरह दिखता है:अनुदैर्ध्य डेटा से अंतिम अवलोकन का चयन करें

ID week outcome 
1 2 14 
1 4 28 
1 6 42 
4 2 14 
4 6 46 
4 9 64 
4 9 71 
4 12 85 
9 2 14 
9 4 28 
9 6 51 
9 9 66 
9 12 84 

मैं प्रत्येक भागीदार के लिए केवल पिछले प्रेक्षण/मूल्यांकन का चयन करना चाहते हैं, लेकिन मैं केवल प्रत्येक भागीदार के लिए एक संकेतक के रूप सप्ताह के नंबर है। यह कैसे आर में करने के लिए संभव है (या उत्कृष्टता?) पहले से

धन्यवाद,

निकी

+1

एक अलग रूप में के रूप में, सुनिश्चित करें कि आप के साथ कुछ समझदार कर रहे हैं कि सुनिश्चित करें:

तुलना के लिए (क्योंकि इसे कहीं तैनात नहीं है), यहाँ आप मूल डेटा उत्पन्न कर सकते हैं कि कैसे, ताकि आप कोड चल सकता है यह डेटा; आखिरी उपलब्ध मूल्यांकन लेने से आप बहुत गलत अनुमानों का कारण बन सकते हैं, इस पर निर्भर करते हुए कि आप डेटा क्यों खो रहे हैं और आप क्या खोज रहे हैं। – Aaron

उत्तर

11

यहाँ एक आधार-आर दृष्टिकोण है:

do.call("rbind", 
     by(df, INDICES=df$ID, FUN=function(DF) DF[which.max(DF$week), ])) 
    ID week outcome 
1 1 6  42 
4 4 12  85 
9 9 12  84 

वैकल्पिक रूप से, data.table पैकेज इस प्रकार के डेटा फ्रेम मैनिप्लेशंस करने के लिए एक संक्षिप्त और अभिव्यक्तिपूर्ण भाषा प्रदान करता है:

library(data.table) 
dt <- data.table(df, key="ID") 

dt[, .SD[which.max(outcome), ], by=ID] 
#  ID week outcome 
# [1,] 1 6  42 
# [2,] 4 12  85 
# [3,] 9 12  84 

# Same but much faster. 
# (Actually, only the same as long as there are no ties for max(outcome)..) 
dt[ dt[,outcome==max(outcome),by=ID][[2]] ] # same, but much faster. 

# If there are ties for max(outcome), the following will still produce 
# the same results as the method using .SD, but will be faster 
i1 <- dt[,which.max(outcome), by=ID][[2]] 
i2 <- dt[,.N, by=ID][[2]] 
dt[i1 + cumsum(i2) - i2,] 

अंत में, यहाँ एक plyr आधारित समाधान

library(plyr) 

ddply(df, .(ID), function(X) X[which.max(X$week), ]) 
# ID week outcome 
# 1 1 6  42 
# 2 4 12  85 
# 3 9 12  84 
+0

अच्छा जवाब। मैं इस बारे में सोचने की कोशिश कर रहा था कि इसे प्लीयर या कुल के साथ कैसे किया जाए और असफल हो क्योंकि मैं यह नहीं समझ सकता कि इसे एक साथ हैकिंग के साथ परिणाम कैसे वापस लाया जाए। +1 –

+0

@ टाइलर रिंकर - क्या आप अभी जोड़ा गया प्लीयर समाधान देखेंगे? मैं ज्यादातर बेस-आर या डेटाटेबल का उपयोग कर समाप्त करता हूं, इसलिए इसमें कुछ स्पष्ट सुधार हो सकता है। धन्यवाद! –

+0

अच्छी तरह से काम करता है। अच्छी तरह से किया गया –

2

आधार में एक और विकल्प है: df[rev(rownames(df)),][match(unique(df$ID), rev(df$ID)), ]

+0

बहुत धन्यवाद, पहला एकदम सही काम करता है। दूसरे का उपयोग करके मुझे कुछ मामलों को दोहराया जाता है, कोई सुराग क्यों नहीं। – user1236418

+0

बस यहां रुचि के लिए ... मैं जोश के साथ रहूंगा! हालांकि डुप्लीस मुद्दे को देखेंगे .. – jbaums

+0

'grep' संख्याओं के सटीक मिलान के लिए वास्तव में उपयुक्त नहीं था ..' x == df $ ID' बेहतर काम करता है। – jbaums

1

मैं विभाजन का उपयोग करें और थोड़ा अधिक tapply अधिक बनने के लिए करने की कोशिश कर रहा है उनके साथ परिचित मुझे पता है कि इस प्रश्न का उत्तर पहले ही दिया गया है, लेकिन मैंने सोचा कि मैं विभाजन का उपयोग करके एक और सोलोट्यूशन जोड़ूंगा (बदसूरत क्षमा करें; मैं सुधार के लिए प्रतिक्रिया के लिए खुले से अधिक हूं; सोचा था कि कोड को कम करने के लिए टैपली करने के लिए उपयोग किया जा सकता था):

sdf <-with(df, split(df, ID)) 
max.week <- sapply(seq_along(sdf), function(x) which.max(sdf[[x]][, 'week'])) 
data.frame(t(mapply(function(x, y) y[x, ], max.week, sdf))) 

मुझे यह भी लगा कि हमारे पास 7 उत्तरों क्यों हैं, यह बेंचमार्क के लिए परिपक्व था। परिणाम आपको आश्चर्य हो सकता है (R2.14.1 साथ rbenchmark का उपयोग कर एक 7 विन मशीन पर):

# library(rbenchmark) 
# benchmark(
#  DATA.TABLE= {dt <- data.table(df, key="ID") 
#   dt[, .SD[which.max(outcome),], by=ID]}, 
#  DO.CALL={do.call("rbind", 
#   by(df, INDICES=df$ID, FUN=function(DF) DF[which.max(DF$week),]))}, 
#  PLYR=ddply(df, .(ID), function(X) X[which.max(X$week), ]), 
#  SPLIT={sdf <-with(df, split(df, ID)) 
#   max.week <- sapply(seq_along(sdf), function(x) which.max(sdf[[x]][, 'week'])) 
#   data.frame(t(mapply(function(x, y) y[x, ], max.week, sdf)))}, 
#  MATCH.INDEX=df[rev(rownames(df)),][match(unique(df$ID), rev(df$ID)), ], 
#  AGGREGATE=df[cumsum(aggregate(week ~ ID, df, which.max)$week), ], 
#  #WHICH.MAX.INDEX=df[sapply(unique(df$ID), function(x) which.max(x==df$ID)), ], 
#  BRYANS.INDEX = df[cumsum(as.numeric(lapply(split(df$week, df$ID), 
#   which.max))), ], 
#  SPLIT2={sdf <-with(df, split(df, ID)) 
#   df[cumsum(sapply(seq_along(sdf), function(x) which.max(sdf[[x]][, 'week']))), 
#   ]}, 
#  TAPPLY=df[tapply(seq_along(df$ID), df$ID, function(x){tail(x,1)}),], 
# columns = c("test", "replications", "elapsed", "relative", "user.self","sys.self"), 
# order = "test", replications = 1000, environment = parent.frame()) 

      test replications elapsed relative user.self sys.self 
6 AGGREGATE   1000 4.49 7.610169  2.84  0.05 
7 BRYANS.INDEX   1000 0.59 1.000000  0.20  0.00 
1 DATA.TABLE   1000 20.28 34.372881  11.98  0.00 
2  DO.CALL   1000 4.67 7.915254  2.95  0.03 
5 MATCH.INDEX   1000 1.07 1.813559  0.51  0.00 
3   PLYR   1000 10.61 17.983051  5.07  0.00 
4  SPLIT   1000 3.12 5.288136  1.81  0.00 
8  SPLIT2   1000 1.56 2.644068  1.28  0.00 
9  TAPPLY   1000 1.08 1.830508  0.88  0.00 

Edit1: मैं जो मैक्स समाधान यह सही परिणाम वापस नहीं करता है के रूप में छोड़े गए और के रूप में एक समग्र समाधान लौटे अच्छी तरह से मैं cumsum (मुझे उस कदम पसंद आया) का उपयोग कर (ब्रायन गुड्रिच की प्रशंसा) और विभाजन के एक अद्यतन संस्करण, एसपीएलआईटी 2 का उपयोग करना चाहता था।

संपादित करें 2: डसन ने एक टैपली समाधान के साथ भी चिमटा जो मैंने परीक्षण में फेंक दिया जो बहुत अच्छी तरह से दिख रहा था।

+0

हालांकि ओपी चाहता था कि आप तकनीकी रूप से सप्ताह के अनुसार सॉर्ट करना चाहते हैं, तो यह पहले से सॉर्ट नहीं किया गया था। इस मामले में इसे हफ्ते तक हल किया गया था, ओह ठीक है। – Dason

+1

हू? यह तालिका एक बहुत छोटे डेटासेट पर प्रत्येक परीक्षण 1000 बार दोहराना प्रतीत होता है। अभ्यास में किसी भी तरह के उपयोग (किसी भी तरह से) के परिणाम क्यों हैं? आपको _large_ डेटासेट पर, प्रत्येक विधि का _single_ परीक्षण चलाने की आवश्यकता है। _कि क्या मायने रखती है। डुप्लीकेट के लिए –

2

मैं इस खेल को खेल सकता हूं। मैंने लापता, sapply, और के बीच अन्य चीज़ों के बीच मतभेदों पर कुछ मानक चलाए। ऐसा लगता है कि जितना अधिक आप डेटा प्रकारों के नियंत्रण में हैं और ऑपरेशन जितना अधिक बुनियादी हैं, तेज़ी से यह है (उदाहरण के लिए, लापरवाही आम तौर पर तेजी से तेज है, और as.numeric (lapply (...)) जा रहा है तेजी से होने के लिए भी)। इस बात को ध्यान में रखते हुए, यह उपरोक्त के समान परिणाम उत्पन्न करता है और बाकी की तुलना में तेज़ हो सकता है।

df[cumsum(as.numeric(lapply(split(df$week, df$id), which.max))), ] 

स्पष्टीकरण: हम केवल प्रत्येक आईडी के लिए सप्ताह में कौन सा। मैक्स चाहते हैं। यह लप्ली की सामग्री को संभालता है। हमें केवल इन सापेक्ष बिंदुओं के वेक्टर की आवश्यकता है, इसलिए इसे संख्यात्मक बनाएं।नतीजा वेक्टर (3, 5, 5) है। हमें पूर्व अधिकतम पदों को जोड़ने की जरूरत है। यह cumsum के साथ पूरा किया गया है।

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

मैं इसे अपनी तुलना अपडेट करने के लिए ट्रिंकर पर छोड़ दूंगा!

8

यदि आप प्रति व्यक्ति आईडी के अंतिम अवलोकन की तलाश में हैं, तो एक साधारण दो लाइन कोड इसे करना चाहिए। जब भी संभव हो, मैं हमेशा सरल आधार समाधान के लिए तैयार हूं, जबकि किसी समस्या को हल करने के एक से अधिक तरीकों से हमेशा अच्छा होता है।

dat[order(dat$ID,dat$Week),] # Sort by ID and week 
dat[!duplicated(dat$ID, fromLast=T),] # Keep last observation per ID 

    ID Week Outcome 
3 1 6  42 
8 4 12  85 
13 9 12  84 
+0

+1। यह एक उपयोगी काम है। – AdamO

+0

यह एक उच्च गुणवत्ता वाला उत्तर है जो अधिक वोटों के योग्य है। जब 'आर' की बात आती है, तो मैं उन उत्तरों की सराहना करता हूं जिनमें नए पैकेज स्थापित करने शामिल नहीं हैं, आदि। अपने दो सेंट जोड़ने के लिए धन्यवाद। – ChrisP

2

यह उत्तर डेटा.table पैकेज का उपयोग करता है। बड़े डेटा सेट के साथ भी यह बहुत तेज़ होना चाहिए।

setkey(DT, ID, week)    # Ensure it's sorted. 
DT[DT[, .I[.N], by = ID][, V1]] 

स्पष्टीकरण: .I समूह के लिए पंक्ति स्थानों (इस मामले में समूह ID है) पकड़े एक पूर्णांक वेक्टर है। .N एक लम्बाई वाला एक पूर्णांक वेक्टर है जिसमें समूह में पंक्तियों की संख्या शामिल है। तो हम यहां क्या कर रहे हैं, "आंतरिक" DT[.] का उपयोग करके, प्रत्येक समूह के लिए अंतिम पंक्ति के स्थान को निकालने के लिए, ID और week के अनुसार डेटा सॉर्ट किया गया है। इसके बाद हम इसका उपयोग "बाहरी" DT[.] को सब्सक्राइब करने के लिए करते हैं।

DT <- 
    data.table(
    ID = c(rep(1, 3), rep(4, 5), rep(9, 5)), 
    week = c(2,4,6, 2,6,9,9,12, 2,4,6,9,12), 
    outcome = c(14,28,42, 14,46,64,71,85, 14,28,51,66,84)) 
संबंधित मुद्दे