विशिष्ट पंक्तियों पर कंडीशनिंग करते हुए गतिशील रूप से कई कॉलम म्यूट करना


11

मुझे पता है कि यहां आसपास कई समान प्रश्न हैं, लेकिन उनमें से कोई भी सटीक मुद्दे को संबोधित नहीं करता है जो मैं कर रहा हूं।

set.seed(4)
df = data.frame(
  Key = c("A", "B", "A", "D", "A"),
  Val1 = rnorm(5),
  Val2 = runif(5),
  Val3 = 1:5
)

मैं उन पंक्तियों के मान मानों को शून्य करना चाहता हूं जहां कुंजी == "ए" कॉलम नामों को एक के माध्यम से संदर्भित किया जाता है grep:

cols = grep("Val", names(df), value = TRUE)

आम तौर पर इस मामले में जो मैं चाहता हूं उसे प्राप्त करने के लिए मैं इस data.tableतरह का उपयोग करूंगा :

library(data.table)
df = as.data.table(df)
df[Key == "A", (cols) := 0]

और वांछित आउटपुट इस तरह है:

  Key      Val1       Val2 Val3
1   A  0.000000 0.00000000    0
2   B -1.383814 0.55925762    2
3   A  0.000000 0.00000000    0
4   D  1.437151 0.05632773    4
5   A  0.000000 0.00000000    0

हालाँकि इस बार मुझे उपयोग करने की आवश्यकता है dplyrक्योंकि मैं एक टीम प्रोजेक्ट पर काम कर रहा हूं जहां हर कोई इसका उपयोग करता है। मेरे द्वारा प्रदान किया गया डेटा चित्रण है और मेरा वास्तविक डेटा> 5m पंक्तियों के साथ 16 मान स्तंभों को अद्यतन किया जाना है। एकमात्र समाधान जिसके साथ मैं आ सकता था वह mutate_atइस तरह का उपयोग कर रहा है:

df %>% mutate_at(.vars = vars(cols), .funs = function(x) ifelse(df$Key == "A", 0, x))

हालाँकि, यह मेरे वास्तविक डेटा पर बेहद धीमा प्रतीत होता है । मैं एक समाधान खोजने की उम्मीद कर रहा था जो अधिक सुरुचिपूर्ण है और, इससे भी महत्वपूर्ण बात, तेज है।

मैंने कई संयोजनों का उपयोग करने की कोशिश की है , का mapउपयोग करते हुए unquoting !!, प्रयोग getऔर :=(जो कष्टप्रद रूप :=से data.table में नकाबपोश हो सकते हैं ) आदि, लेकिन मुझे लगता है कि ये समझ कैसे इन कामों के लिए बस एक गहन समाधान बनाने के लिए पर्याप्त गहरी नहीं है।


6
इसमें कितना समय लग जाता है? df [df $ कुंजी == 'ए', कॉलम] <- 0। मैं देख सकता हूं कि यह धीमा है क्योंकि आप स्तंभों और पंक्तियों पर इफल्स और लूपिंग कह रहे हैं।
स्टुपिडॉल्फ नोव

स्टुपिडॉल्फ, यह मेरे डेटा के साथ वास्तव में बहुत तेज़ है, जबकि बहुत कॉम्पैक्ट और सुरुचिपूर्ण है। धन्यवाद। यदि आप चाहें तो इसे उत्तर के रूप में जोड़ने के लिए स्वतंत्र महसूस करें।
लिवियस 11

ठीक है मैं आपको इसके चारों ओर पाने के लिए एक और समाधान दिखा सकता हूं ..
स्टुपिडॉल्फ

जवाबों:


9

इस despr कमांड के साथ,

df %>% mutate_at(.vars = vars(cols), .funs = function(x) ifelse(df$Key == "A", 0, x))

आप वास्तव में df $ की == "ए" स्टेटमेंट का मूल्यांकन कर रहे हैं, n बार, जहां n = आपके पास कॉलम की संख्या।

चारों ओर एक काम उन पंक्तियों को पूर्व-परिभाषित करना है जिन्हें आप बदलना चाहते हैं:

idx = which(DF$Key=="A")
DF %>% mutate_at(.vars = vars(cols), .funs = function(x){x[idx]=0;x})

एक क्लीनर और बेहतर तरीका, सही ढंग से @IceCreamToucan (नीचे टिप्पणियां देखें) द्वारा इंगित किया गया है, इसे अतिरिक्त मापदंडों को पारित करते समय फ़ंक्शन को प्रतिस्थापित करने के लिए उपयोग करना है:

DF %>% mutate_at(.vars = vars(cols), replace, DF$Key == 'A', 0)

हम इन सभी दृष्टिकोणों को परीक्षण करने के लिए रख सकते हैं, और मुझे लगता है कि dplyr और data.table तुलनीय हैं।

#simulate data
set.seed(100)
Key = sample(LETTERS[1:3],1000000,replace=TRUE)
DF = as.data.frame(data.frame(Key,matrix(runif(1000000*10),nrow=1000000,ncol=10)))
DT = as.data.table(DF)

cols = grep("[35789]", names(DF), value = TRUE)

#long method
system.time(DF %>% mutate_at(.vars = vars(cols), .funs = function(x) ifelse(DF$Key == "A", 0, x)))
user  system elapsed 
  0.121   0.035   0.156 

#old base R way
system.time(DF[idx,cols] <- 0)
   user  system elapsed 
  0.085   0.021   0.106 

#dplyr
# define function
func = function(){
       idx = which(DF$Key=="A")
       DF %>% mutate_at(.vars = vars(cols), .funs = function(x){x[idx]=0;x})
}
system.time(func())
user  system elapsed 
  0.020   0.006   0.026

#data.table
system.time(DT[Key=="A", (cols) := 0])
   user  system elapsed 
  0.012   0.001   0.013 
#replace with dplyr
system.time(DF %>% mutate_at(.vars = vars(cols), replace, DF$Key == 'A', 0))
user  system elapsed 
  0.007   0.001   0.008

4
म्यूट करने के लिए अतिरिक्त तर्कों का मूल्यांकन एक बार किया जाता है और प्रदान किए गए फ़ंक्शन के लिए एक पैरामीटर के रूप में पारित किया जाता है (उदाहरण के लिए lapply के समान), इसलिए आप इसे अस्थायी रूप से अस्थायी वैरिएबल आईडी के बिना बना सकते हैंdf %>% mutate_at(vars(contains('Val')), replace, df$Key == 'A', 0)
IceCreamToucan

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

मेरी मशीन पर परीक्षण करने के बाद, ऐसा लगता है कि यह replaceविधि आपकी मूल idxविधि से थोड़ी धीमी है ।
आइसक्रीम टाकन

1
मुझे भी लगता dplyr::if_else()है कि आधार की तुलना में तेज है ifelse()
सिंदरी_बलदुर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.