dplyr म्यूट करें / पंक्तियों के सबसेट पर कई कॉलम बदलें


85

मैं एक dplyr-आधारित वर्कफ़्लो आज़माने की प्रक्रिया में हूँ (बजाय ज्यादातर data.table का उपयोग करने के बजाय, जिसका मैं उपयोग कर रहा हूँ), और मुझे एक समस्या आई है कि मैं इसके लिए एक समान dplyr समाधान नहीं ढूँढ सकता । मैं आमतौर पर उस परिदृश्य में दौड़ता हूं, जहां मुझे किसी शर्त के आधार पर कई कॉलमों को सशर्त रूप से अपडेट / प्रतिस्थापित करने की आवश्यकता होती है। यहाँ कुछ उदाहरण कोड है, मेरे डेटा के साथ। समाधान:

library(data.table)

# Create some sample data
set.seed(1)
dt <- data.table(site = sample(1:6, 50, replace=T),
                 space = sample(1:4, 50, replace=T),
                 measure = sample(c('cfl', 'led', 'linear', 'exit'), 50, 
                               replace=T),
                 qty = round(runif(50) * 30),
                 qty.exit = 0,
                 delta.watts = sample(10.5:100.5, 50, replace=T),
                 cf = runif(50))

# Replace the values of several columns for rows where measure is "exit"
dt <- dt[measure == 'exit', 
         `:=`(qty.exit = qty,
              cf = 0,
              delta.watts = 13)]

क्या इस समस्या का एक सरल dplyr समाधान है? मैं ifelse का उपयोग करने से बचना चाहूंगा क्योंकि मैं कई बार शर्त नहीं लिखना चाहता हूं - यह एक सरलीकृत उदाहरण है, लेकिन कभी-कभी एक ही स्थिति के आधार पर कई असाइनमेंट होते हैं।

मदद के लिए अग्रिम धन्यवाद!

जवाबों:


81

ये समाधान (1) पाइपलाइन को बनाए रखते हैं, (2) इनपुट को अधिलेखित नहीं करते हैं और (3) केवल यह आवश्यक है कि शर्त एक बार निर्दिष्ट की जाए:

1a) mutate_cond डेटा फ़्रेम या डेटा तालिकाओं के लिए एक सरल फ़ंक्शन बनाएं जिन्हें पाइपलाइनों में शामिल किया जा सकता है। यह फ़ंक्शन जैसा है mutateलेकिन केवल स्थिति को संतुष्ट करने वाली पंक्तियों पर कार्य करता है:

mutate_cond <- function(.data, condition, ..., envir = parent.frame()) {
  condition <- eval(substitute(condition), .data, envir)
  .data[condition, ] <- .data[condition, ] %>% mutate(...)
  .data
}

DF %>% mutate_cond(measure == 'exit', qty.exit = qty, cf = 0, delta.watts = 13)

1b) mutate_last यह डेटा फ़्रेम या डेटा टेबल के लिए एक वैकल्पिक फ़ंक्शन है जो फिर से पसंद है mutateलेकिन केवल group_by(नीचे उदाहरण में) के भीतर उपयोग किया जाता है और केवल प्रत्येक समूह के बजाय अंतिम समूह पर काम करता है। ध्यान दें कि TRUE> FALSE इसलिए यदि group_byकोई शर्त निर्दिष्ट करता है तो mutate_lastकेवल उस स्थिति को संतुष्ट करने वाली पंक्तियों पर काम करेगा।

mutate_last <- function(.data, ...) {
  n <- n_groups(.data)
  indices <- attr(.data, "indices")[[n]] + 1
  .data[indices, ] <- .data[indices, ] %>% mutate(...)
  .data
}


DF %>% 
   group_by(is.exit = measure == 'exit') %>%
   mutate_last(qty.exit = qty, cf = 0, delta.watts = 13) %>%
   ungroup() %>%
   select(-is.exit)

2) फैक्टर आउट कंडीशन फैक्टर इसे अतिरिक्त कॉलम बनाकर कंडीशन को बाहर निकालता है जिसे बाद में हटा दिया जाता है। फिर उपयोग ifelse, replaceया चित्रण के साथ तार्किकों के साथ अंकगणित। यह डेटा टेबल के लिए भी काम करता है।

library(dplyr)

DF %>% mutate(is.exit = measure == 'exit',
              qty.exit = ifelse(is.exit, qty, qty.exit),
              cf = (!is.exit) * cf,
              delta.watts = replace(delta.watts, is.exit, 13)) %>%
       select(-is.exit)

3) sqldf हम updateडेटा फ्रेम के लिए पाइप लाइन में sqldf पैकेज के माध्यम से SQL का उपयोग कर सकते हैं (लेकिन डेटा टेबल नहीं जब तक कि हम उन्हें परिवर्तित नहीं करते हैं - यह duspr में बग का प्रतिनिधित्व कर सकता है। dplyr समस्या 1579 देखें )। ऐसा लग सकता है कि हम अवांछनीय रूप से इस कोड में इनपुट को संशोधित कर रहे हैं, updateलेकिन वास्तव में अस्तित्व में आने वाले updateडेटाबेस में इनपुट की एक प्रति पर काम कर रहा है और वास्तविक इनपुट पर नहीं।

library(sqldf)

DF %>% 
   do(sqldf(c("update '.' 
                 set 'qty.exit' = qty, cf = 0, 'delta.watts' = 13 
                 where measure = 'exit'", 
              "select * from '.'")))

4) row_case_when यह भी चेक करें कि रिटर्निंग ए टिबबलrow_case_when में परिभाषित किया गया है : केस_व्यू के साथ वेक्टर कैसे करें? । यह एक सिंटैक्स का उपयोग करता है case_whenलेकिन पंक्तियों पर लागू होता है।

library(dplyr)

DF %>%
  row_case_when(
    measure == "exit" ~ data.frame(qty.exit = qty, cf = 0, delta.watts = 13),
    TRUE ~ data.frame(qty.exit, cf, delta.watts)
  )

नोट 1: हमने इसका उपयोग किया हैDF

set.seed(1)
DF <- data.frame(site = sample(1:6, 50, replace=T),
                 space = sample(1:4, 50, replace=T),
                 measure = sample(c('cfl', 'led', 'linear', 'exit'), 50, 
                               replace=T),
                 qty = round(runif(50) * 30),
                 qty.exit = 0,
                 delta.watts = sample(10.5:100.5, 50, replace=T),
                 cf = runif(50))

नोट 2: कितनी आसानी से पंक्तियों का एक सबसेट को अद्यतन करने को निर्दिष्ट करने की समस्या भी dplyr मुद्दों में चर्चा की है 134 , 631 , 1518 और 1573 के साथ 631 मुख्य थ्रेड जा रहा है और 1573 जवाब यहां की समीक्षा की जा रही है।


1
बहुत बढ़िया जवाब, धन्यवाद! आपके mutate_cond और @Kevin Ushey के mutate_when दोनों इस समस्या के अच्छे समाधान हैं। मुझे लगता है कि मेरे पास mutate_when की पठनीयता / लचीलेपन के लिए थोड़ी वरीयता है, लेकिन मैं इस उत्तर को पूरी तरह से "जांच" दूंगा।
क्रिस न्यूटन

मुझे वास्तव में mutate_cond दृष्टिकोण पसंद है। ऐसा लगता है कि यह समारोह मुझे बहुत पसंद है या इसके कुछ बहुत ही निकटवर्ती में शामिल होने का गुण है और यह वेक्टरइंडसाइज़विच (जो कि github.com/hadley/dplyr/issues/1573 में चर्चा की गई है ) के उपयोग से बेहतर समाधान होगा जो लोग सोच रहे हैं। यहाँ के बारे में ...
मैग्नस

मुझे mutate_cond बहुत पसंद है। विभिन्न विकल्पों के अलग-अलग उत्तर होने चाहिए थे।
होल्गर ब्रैंडल

यह एक दो साल हो गया है और गितुब मुद्दे बंद और बंद लगते हैं। क्या इस समस्या का कोई आधिकारिक समाधान है?
static_rtti

27

आप इसे magrittrदो-तरफा पाइप से कर सकते हैं %<>%:

library(dplyr)
library(magrittr)

dt[dt$measure=="exit",] %<>% mutate(qty.exit = qty,
                                    cf = 0,  
                                    delta.watts = 13)

यह टाइपिंग की मात्रा को कम करता है, लेकिन फिर भी बहुत धीमा है data.table


दरअसल, अब जब मुझे इसका परीक्षण करने का मौका मिला है, तो मैं एक ऐसा समाधान पसंद करूंगा, जो dt [dt $ उपाय == 'बाहर निकलें'] संकेतन का उपयोग करके कम करने की आवश्यकता को टालता है, क्योंकि इससे लंबे समय तक नुकसान हो सकता है dt नाम।
क्रिस न्यूटन

सिर्फ एक FYI करें, लेकिन यह समाधान तभी काम करेगा जब data.frame/ tibbleजिसमें पहले से परिभाषित कॉलम शामिल हो mutate। यदि आप एक नया कॉलम जोड़ने की कोशिश कर रहे हैं, तो यह काम नहीं करेगा, उदाहरण के लिए, पहली बार एक लूप के माध्यम से चल रहा है और एक को संशोधित कर रहा है data.frame
उर्सस फ्रॉस्ट

@UrsusFrost एक नया कॉलम जो केवल डेटासेट का सबसेट है, मुझे जोड़ना अजीब लगता है। आप उन पंक्तियों में NA जोड़ते हैं जो सब्सट्रेट नहीं हैं?
बारालुह

@ बरालुह हां, मैं इसकी सराहना कर सकता हूं। यह एक लूप का हिस्सा है जिसमें मैं तारीखों की सूची में डेटा बढ़ाता हूं और जोड़ता हूं। पहले कुछ तारीखों को बाद की तारीखों से अलग माना जाना चाहिए क्योंकि यह वास्तविक दुनिया की व्यावसायिक प्रक्रियाओं की नकल कर रहा है। आगे की पुनरावृत्तियों में, तिथियों की स्थितियों के आधार पर, डेटा की गणना अलग-अलग की जाती है। सशर्तता के कारण, मैं अनजाने में पिछली तारीखों को बदलना नहीं चाहता data.frame। एफडब्ल्यूआईडब्ल्यू, मैं सिर्फ data.tableइसके बजाय उपयोग करने के लिए वापस चला गया dplyrक्योंकि इसकी iअभिव्यक्ति इसे आसानी से संभालती है - प्लस समग्र लूप बहुत तेज चलता है।
उर्सस फ्रॉस्ट

18

यहाँ एक समाधान है जो मुझे पसंद है:

mutate_when <- function(data, ...) {
  dots <- eval(substitute(alist(...)))
  for (i in seq(1, length(dots), by = 2)) {
    condition <- eval(dots[[i]], envir = data)
    mutations <- eval(dots[[i + 1]], envir = data[condition, , drop = FALSE])
    data[condition, names(mutations)] <- mutations
  }
  data
}

यह आपको उदाहरण के लिए चीजें लिखने देता है

mtcars %>% mutate_when(
  mpg > 22,    list(cyl = 100),
  disp == 160, list(cyl = 200)
)

जो काफी पठनीय है - हालाँकि यह उतना अच्छा नहीं हो सकता जितना कि यह हो सकता है।


14

जैसा कि eipi10 से पता चलता है, dplyr में सबसेट प्रतिस्थापन करने का एक सरल तरीका नहीं है क्योंकि DT पास-दर-संदर्भ अर्थ-विज्ञान बनाम dplyr का उपयोग पास-दर-मूल्य का उपयोग करता है। dplyr को ifelse()पूरे वेक्टर पर उपयोग की आवश्यकता होती है , जबकि DT सब्मिट और अपडेट को संदर्भ द्वारा (पूरे DT को वापस करते हुए) करेगा। तो, इस अभ्यास के लिए, डीटी काफी तेजी से होगा।

आप पहले वैकल्पिक रूप से सबसे पहले सब्मिट कर सकते हैं, फिर अपडेट कर सकते हैं, और अंत में पुनः प्राप्त कर सकते हैं:

dt.sub <- dt[dt$measure == "exit",] %>%
  mutate(qty.exit= qty, cf= 0, delta.watts= 13)

dt.new <- rbind(dt.sub, dt[dt$measure != "exit",])

लेकिन DT बहुत तेजी से होने वाला है: (eipi10 के नए उत्तर का उपयोग करने के लिए तैयार)

library(data.table)
library(dplyr)
library(microbenchmark)
microbenchmark(dt= {dt <- dt[measure == 'exit', 
                            `:=`(qty.exit = qty,
                                 cf = 0,
                                 delta.watts = 13)]},
               eipi10= {dt[dt$measure=="exit",] %<>% mutate(qty.exit = qty,
                                cf = 0,  
                                delta.watts = 13)},
               alex= {dt.sub <- dt[dt$measure == "exit",] %>%
                 mutate(qty.exit= qty, cf= 0, delta.watts= 13)

               dt.new <- rbind(dt.sub, dt[dt$measure != "exit",])})


Unit: microseconds
expr      min        lq      mean   median       uq      max neval cld
     dt  591.480  672.2565  747.0771  743.341  780.973 1837.539   100  a 
 eipi10 3481.212 3677.1685 4008.0314 3796.909 3936.796 6857.509   100   b
   alex 3412.029 3637.6350 3867.0649 3726.204 3936.985 5424.427   100   b

10

मैं बस इस पार ठोकर खाई और वास्तव mutate_cond()में @ जी द्वारा पसंद है। Grothendieck, लेकिन यह भी नए चर को संभालने के लिए काम में आ सकता है सोचा। तो, नीचे दो जोड़ दिए गए हैं:

असंबंधित: दूसरी अंतिम पंक्ति dplyrका उपयोग करके थोड़ा अधिक बनाया गयाfilter()

शुरुआत में तीन नई लाइनों में उपयोग के लिए परिवर्तनशील नाम मिलते हैं mutate(), और होने से पहले डेटा फ़्रेम में किसी भी नए चर को प्रारंभ करता mutate()है। नई चर के शेष के लिए प्रारंभ कर रहे हैं data.frameका उपयोग कर new_init, जो लापता (के लिए सेट है NA) एक डिफ़ॉल्ट के रूप में।

mutate_cond <- function(.data, condition, ..., new_init = NA, envir = parent.frame()) {
  # Initialize any new variables as new_init
  new_vars <- substitute(list(...))[-1]
  new_vars %<>% sapply(deparse) %>% names %>% setdiff(names(.data))
  .data[, new_vars] <- new_init

  condition <- eval(substitute(condition), .data, envir)
  .data[condition, ] <- .data %>% filter(condition) %>% mutate(...)
  .data
}

आईरिस डेटा का उपयोग करने के कुछ उदाहरण यहां दिए गए हैं:

Petal.Length88 में बदलें Species == "setosa"। यह मूल फ़ंक्शन के साथ-साथ इस नए संस्करण में भी काम करेगा।

iris %>% mutate_cond(Species == "setosa", Petal.Length = 88)

ऊपर के समान, लेकिन एक नया वैरिएबल भी बनाएं x( NAपंक्तियों में शर्त में शामिल नहीं)। पहले संभव नहीं था।

iris %>% mutate_cond(Species == "setosa", Petal.Length = 88, x = TRUE)

ऊपर के समान, लेकिन xFALSE के लिए सेट की गई पंक्तियों को इस स्थिति में शामिल नहीं किया गया है ।

iris %>% mutate_cond(Species == "setosa", Petal.Length = 88, x = TRUE, new_init = FALSE)

यह उदाहरण दिखाता है कि विभिन्न मूल्यों के साथ कई नए चर को आरंभ करने के new_initलिए कैसे सेट किया जा सकता है list। इधर, दो नए चर बाहर रखा गया पंक्तियों के साथ बनाई गई हैं विभिन्न मूल्यों का उपयोग कर (प्रारंभ किया जा रहा xके रूप में initialised FALSE, yके रूप में NA)

iris %>% mutate_cond(Species == "setosa" & Sepal.Length < 5,
                  x = TRUE, y = Sepal.Length ^ 2,
                  new_init = list(FALSE, NA))

आपका mutate_condकार्य मेरे डेटासेट पर एक त्रुटि देता है, और Grothendiecks का कार्य नहीं करता है। Error: incorrect length (4700), expecting: 168फ़िल्टर फ़ंक्शन से संबंधित लगता है।
आरएच

क्या आपने इसे एक पुस्तकालय में रखा है या इसे एक समारोह के रूप में औपचारिक रूप दिया है? यह एक नो-ब्रेनर की तरह लगता है, खासकर सभी सुधारों के साथ।
नेटल

1
नहीं, मुझे लगता है कि इस समय के लिए duspr के साथ सबसे अच्छा तरीका है म्यूटेट के साथ गठबंधन करना if_elseया case_when
साइमन जैक्सन

क्या आप इस दृष्टिकोण के लिए एक उदाहरण (या लिंक) प्रदान कर सकते हैं?
नेटल

6

mutate_cond एक शानदार कार्य है, लेकिन यह एक त्रुटि देता है यदि स्थिति बनाने के लिए उपयोग किए गए कॉलम (s) में NA है। मुझे लगता है कि एक सशर्त उत्परिवर्तन को केवल ऐसी पंक्तियों को अकेला छोड़ देना चाहिए। यह फ़िल्टर () के व्यवहार से मेल खाता है, जो स्थिति के सही होने पर पंक्तियों को लौटाता है, लेकिन FALSE और NA के साथ दोनों पंक्तियों को छोड़ देता है।

इस छोटे से परिवर्तन के साथ फ़ंक्शन एक आकर्षण की तरह काम करता है:

mutate_cond <- function(.data, condition, ..., envir = parent.frame()) {
    condition <- eval(substitute(condition), .data, envir)
    condition[is.na(condition)] = FALSE
    .data[condition, ] <- .data[condition, ] %>% mutate(...)
    .data
}

धन्यवाद मैग्नस! मैं एक एनीमेशन बनाने वाली सभी वस्तुओं के लिए कार्यों और समय सारणी को अपडेट करने के लिए इसका उपयोग कर रहा हूं। मैंने एनए समस्या को मारा क्योंकि डेटा इतना विविध है कि कुछ कार्यों में कुछ वस्तुओं के लिए कोई मतलब नहीं है, इसलिए मेरे पास उन कोशिकाओं में एनए है। अन्य mutate_cond के ऊपर दुर्घटनाग्रस्त हो गया, लेकिन आपके समाधान ने एक आकर्षण की तरह काम किया।
फिल वैन क्लेर

यदि यह आपके लिए उपयोगी है, तो यह फ़ंक्शन एक छोटे से पैकेज में उपलब्ध है जो मैंने लिखा था, "ज़ूल्यूटिल्स"। यह CRAN पर नहीं है, लेकिन आप इसे रिमूव्स: install_github ("torfason / zulutils") का उपयोग करके स्थापित कर सकते हैं
Magnus

महान! बहुत धन्यवाद। मैं अभी भी इसका उपयोग कर रहा हूं।
फिल वैन क्लेर

4

मैं वास्तव में इसमें कोई बदलाव नहीं देखता हूं dplyrजिससे यह बहुत आसान हो जाए। case_whenएक कॉलम के लिए कई अलग-अलग स्थितियों और परिणामों के लिए बहुत अच्छा है, लेकिन यह इस मामले के लिए मदद नहीं करता है जहां आप एक शर्त के आधार पर कई कॉलम बदलना चाहते हैं। इसी तरह, recodeयदि आप एक कॉलम में कई अलग-अलग मानों को प्रतिस्थापित कर रहे हैं तो टाइपिंग को सहेजता है , लेकिन एक साथ कई कॉलमों में ऐसा करने में मदद नहीं करता है। अंत में, mutate_atआदि केवल कॉलम नाम की शर्तों को लागू करते हैं जो डेटाफ्रेम में पंक्तियाँ नहीं हैं। आप संभवतः mutate_at के लिए एक फ़ंक्शन लिख सकते हैं जो यह करेगा लेकिन मैं यह पता नहीं लगा सकता हूं कि आप इसे अलग-अलग कॉलम के लिए अलग तरह से कैसे व्यवहार करेंगे।

यहाँ कहा गया है कि मैं nestफॉर्म tidyrऔर mapसे का उपयोग करके इसे कैसे देखूंगा purrr

library(data.table)
library(dplyr)
library(tidyr)
library(purrr)

# Create some sample data
set.seed(1)
dt <- data.table(site = sample(1:6, 50, replace=T),
                 space = sample(1:4, 50, replace=T),
                 measure = sample(c('cfl', 'led', 'linear', 'exit'), 50, 
                                  replace=T),
                 qty = round(runif(50) * 30),
                 qty.exit = 0,
                 delta.watts = sample(10.5:100.5, 50, replace=T),
                 cf = runif(50))

dt2 <- dt %>% 
  nest(-measure) %>% 
  mutate(data = if_else(
    measure == "exit", 
    map(data, function(x) mutate(x, qty.exit = qty, cf = 0, delta.watts = 13)),
    data
  )) %>%
  unnest()

1
केवल एक चीज जो मैं nest(-measure)group_by
सुझाऊँगा

@DaveGruenewald सुझाव को प्रतिबिंबित करने के लिए संपादित
24

4

एक संक्षिप्त समाधान फ़िल्टर किए गए सबसेट पर म्यूटेशन करना होगा और फिर तालिका की गैर-निकास पंक्तियों को वापस जोड़ना होगा:

library(dplyr)

dt %>% 
    filter(measure == 'exit') %>%
    mutate(qty.exit = qty, cf = 0, delta.watts = 13) %>%
    rbind(dt %>% filter(measure != 'exit'))

3

के निर्माण के साथ rlang, Grothendieck का 1a उदाहरण का थोड़ा संशोधित संस्करण संभव है, envirतर्क की आवश्यकता को समाप्त करता है, क्योंकि स्वचालित रूप से बनाए enquo()गए वातावरण को कैप्चर करता है .p

mutate_rows <- function(.data, .p, ...) {
  .p <- rlang::enquo(.p)
  .p_lgl <- rlang::eval_tidy(.p, .data)
  .data[.p_lgl, ] <- .data[.p_lgl, ] %>% mutate(...)
  .data
}

dt %>% mutate_rows(measure == "exit", qty.exit = qty, cf = 0, delta.watts = 13)

2

आप डेटासेट को विभाजित कर सकते हैं और TRUEभाग पर एक नियमित रूप से म्यूट कॉल कर सकते हैं ।

dplyr 0.8 में फ़ंक्शन होता है group_splitजो समूहों द्वारा विभाजित होता है (और समूहों को सीधे कॉल में परिभाषित किया जा सकता है) इसलिए हम इसका उपयोग यहां करेंगे, लेकिन यह भी base::splitकाम करता है।

library(tidyverse)
df1 %>%
  group_split(measure == "exit", keep=FALSE) %>% # or `split(.$measure == "exit")`
  modify_at(2,~mutate(.,qty.exit = qty, cf = 0, delta.watts = 13)) %>%
  bind_rows()

#    site space measure qty qty.exit delta.watts          cf
# 1     1     4     led   1        0        73.5 0.246240409
# 2     2     3     cfl  25        0        56.5 0.360315879
# 3     5     4     cfl   3        0        38.5 0.279966850
# 4     5     3  linear  19        0        40.5 0.281439486
# 5     2     3  linear  18        0        82.5 0.007898384
# 6     5     1  linear  29        0        33.5 0.392412729
# 7     5     3  linear   6        0        46.5 0.970848817
# 8     4     1     led  10        0        89.5 0.404447182
# 9     4     1     led  18        0        96.5 0.115594622
# 10    6     3  linear  18        0        15.5 0.017919745
# 11    4     3     led  22        0        54.5 0.901829577
# 12    3     3     led  17        0        79.5 0.063949974
# 13    1     3     led  16        0        86.5 0.551321441
# 14    6     4     cfl   5        0        65.5 0.256845013
# 15    4     2     led  12        0        29.5 0.340603733
# 16    5     3  linear  27        0        63.5 0.895166931
# 17    1     4     led   0        0        47.5 0.173088800
# 18    5     3  linear  20        0        89.5 0.438504370
# 19    2     4     cfl  18        0        45.5 0.031725246
# 20    2     3     led  24        0        94.5 0.456653397
# 21    3     3     cfl  24        0        73.5 0.161274319
# 22    5     3     led   9        0        62.5 0.252212124
# 23    5     1     led  15        0        40.5 0.115608182
# 24    3     3     cfl   3        0        89.5 0.066147321
# 25    6     4     cfl   2        0        35.5 0.007888337
# 26    5     1  linear   7        0        51.5 0.835458916
# 27    2     3  linear  28        0        36.5 0.691483644
# 28    5     4     led   6        0        43.5 0.604847889
# 29    6     1  linear  12        0        59.5 0.918838163
# 30    3     3  linear   7        0        73.5 0.471644760
# 31    4     2     led   5        0        34.5 0.972078100
# 32    1     3     cfl  17        0        80.5 0.457241602
# 33    5     4  linear   3        0        16.5 0.492500255
# 34    3     2     cfl  12        0        44.5 0.804236607
# 35    2     2     cfl  21        0        50.5 0.845094268
# 36    3     2  linear  10        0        23.5 0.637194873
# 37    4     3     led   6        0        69.5 0.161431896
# 38    3     2    exit  19       19        13.0 0.000000000
# 39    6     3    exit   7        7        13.0 0.000000000
# 40    6     2    exit  20       20        13.0 0.000000000
# 41    3     2    exit   1        1        13.0 0.000000000
# 42    2     4    exit  19       19        13.0 0.000000000
# 43    3     1    exit  24       24        13.0 0.000000000
# 44    3     3    exit  16       16        13.0 0.000000000
# 45    5     3    exit   9        9        13.0 0.000000000
# 46    2     3    exit   6        6        13.0 0.000000000
# 47    4     1    exit   1        1        13.0 0.000000000
# 48    1     1    exit  14       14        13.0 0.000000000
# 49    6     3    exit   7        7        13.0 0.000000000
# 50    2     4    exit   3        3        13.0 0.000000000

यदि पंक्ति आदेश मामलों, का उपयोग tibble::rowid_to_columnपहले, तो dplyr::arrangeपर rowidऔर अंत में इसे बाहर का चयन करें।

डेटा

df1 <- data.frame(site = sample(1:6, 50, replace=T),
                 space = sample(1:4, 50, replace=T),
                 measure = sample(c('cfl', 'led', 'linear', 'exit'), 50, 
                                  replace=T),
                 qty = round(runif(50) * 30),
                 qty.exit = 0,
                 delta.watts = sample(10.5:100.5, 50, replace=T),
                 cf = runif(50),
                 stringsAsFactors = F)

2

मुझे लगता है कि इस उत्तर का उल्लेख पहले नहीं किया गया है। यह लगभग 'डिफ़ॉल्ट' data.table-Solution के रूप में तेजी से चलता है ।

उपयोग base::replace()

df %>% mutate( qty.exit = replace( qty.exit, measure == 'exit', qty[ measure == 'exit'] ),
                          cf = replace( cf, measure == 'exit', 0 ),
                          delta.watts = replace( delta.watts, measure == 'exit', 13 ) )

recycles की जगह प्रतिस्थापन मूल्य, इसलिए जब आप स्तंभों के मूल्यों चाहते qtycolums में प्रवेश किया qty.exitहै, तो आप सबसेट के लिए है qty के रूप में अच्छी तरह से ... इसलिए qty[ measure == 'exit']पहले प्रतिस्थापन में ..

अब, आप शायद measure == 'exit'हर समय किसी भी प्रकार का पुनर्लेखन नहीं करना चाहेंगे ... इसलिए आप उस चयन वाले एक इंडेक्स-वेक्टर बना सकते हैं, और इसे ऊपर के कार्यों में उपयोग कर सकते हैं।

#build an index-vector matching the condition
index.v <- which( df$measure == 'exit' )

df %>% mutate( qty.exit = replace( qty.exit, index.v, qty[ index.v] ),
               cf = replace( cf, index.v, 0 ),
               delta.watts = replace( delta.watts, index.v, 13 ) )

मानक

# Unit: milliseconds
#         expr      min       lq     mean   median       uq      max neval
# data.table   1.005018 1.053370 1.137456 1.112871 1.186228 1.690996   100
# wimpel       1.061052 1.079128 1.218183 1.105037 1.137272 7.390613   100
# wimpel.index 1.043881 1.064818 1.131675 1.085304 1.108502 4.192995   100

1

सामान्य dplyr सिंटैक्स के साथ तोड़ने की कीमत पर, आप withinआधार से उपयोग कर सकते हैं :

dt %>% within(qty.exit[measure == 'exit'] <- qty[measure == 'exit'],
              delta.watts[measure == 'exit'] <- 13)

यह पाइप के साथ अच्छी तरह से एकीकृत होता है, और आप इसके अंदर बहुत कुछ भी कर सकते हैं।


यह लिखित रूप में काम नहीं करता है क्योंकि दूसरा असाइनमेंट वास्तव में नहीं होता है। लेकिन अगर आप करते हैं dt %>% within({ delta.watts[measure == 'exit'] <- 13 ; qty.exit[measure == 'exit'] <- qty[measure == 'exit'] ; cf[measure == 'exit'] <- 0 })तो यह काम करता है
देखिए 24
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.