পাইপ অপারেটর%>% ব্যবহার করার সময় শর্তসাপেক্ষ মূল্যায়ন


93

পাইপ অপারেটর ব্যবহার করার সময় %>%যেমন প্যাকেজের সাথে dplyr, ggvis, dycharts, ইত্যাদি কিভাবে আমি শর্তসাপেক্ষে একটি পদক্ষেপ কি? উদাহরণ স্বরূপ;

step_1 %>%
step_2 %>%

if(condition)
step_3

এই পদ্ধতিগুলি কার্যকর বলে মনে হচ্ছে না:

step_1 %>%
step_2 
if(condition) %>% step_3

step_1 %>%
step_2 %>%
if(condition) step_3

একটি দীর্ঘ পথ আছে:

if(condition)
{
step_1 %>%
step_2 
}else{
step_1 %>%
step_2 %>%
step_3
}

সমস্ত বাড়াবাড়ি ছাড়া ভাল উপায় আছে?


4
(বেন যেমন সরবরাহ করা হয়েছে) এর সাথে কাজ করার একটি উদাহরণ পছন্দনীয় হবে, তাই হবে।
ফ্র্যাঙ্ক

উত্তর:


104

এখানে একটি দ্রুত উদাহরণ যা এর সুবিধা গ্রহণ করে .এবং ifelse:

X<-1
Y<-T

X %>% add(1) %>% { ifelse(Y ,add(.,1), . ) }

এর মধ্যে ifelseযদি Yহয় TRUEতবে 1 যোগ করবে, অন্যথায় এটি শেষ মানটি ফিরিয়ে দেবে X.স্ট্যান্ড-যা, ফাংশন যেখানে চেন পূর্ববর্তী ধাপে থেকে আউটপুট যায় বলে তাই আমি উভয় শাখা তে এটি ব্যবহার করতে পারেন।

@ বেনবোলকার যেমন উল্লেখ করেছেন তেমন সম্পাদনা করুন , আপনি হয়ত নাও চান ifelse, সুতরাং এখানে একটি ifসংস্করণ রয়েছে।

X %>% 
add(1) %>% 
 {if(Y) add(.,1) else .}

শৃঙ্খলা চালিয়ে যাওয়ার জন্য {আমার ifএবং ifelseবিবৃতিগুলির চারপাশে ব্রেস ব্যবহার করা উচিত বলে উল্লেখ করার জন্য @ ফ্র্যাঙ্ককে ধন্যবাদ জানাই ।


4
আমি সম্পাদনা-পরবর্তী সংস্করণটি পছন্দ করি। ifelseনিয়ন্ত্রণ প্রবাহের জন্য অপ্রাকৃত মনে হয়।
ফ্র্যাঙ্ক

7
একটি বিষয় লক্ষণীয়: শৃঙ্খলে কোনও পরবর্তী পদক্ষেপ থাকলে ব্যবহার করুন {}। উদাহরণস্বরূপ, যদি আপনার এখানে না থাকে তবে খারাপ জিনিস ঘটে (কেবল Yকোনও কারণে মুদ্রণ করা): X %>% "+"(1) %>% {if(Y) "+"(1) else .} %>% "*"(5)
ফ্রাঙ্ক

ম্যাজিস্ট্রি ওরফে ব্যবহারের addফলে উদাহরণটি আরও পরিষ্কার হবে।
ctbrown

কোড গল্ফিং পদগুলিতে, এই নির্দিষ্ট উদাহরণটি অবশ্যই লেখা যেতে পারে X %>% add(1*Y)তবে অবশ্যই এটি মূল প্রশ্নের উত্তর দেয় না
talat

4
শর্তাধীন ব্লকের মধ্যে একটি গুরুত্বপূর্ণ বিষয় {}হ'ল আপনাকে অবশ্যই dplyr পাইপের পূর্ববর্তী যুক্তিটি ডট (।) দিয়ে উল্লেখ করতে হবে - অন্যথায় শর্তাধীন ব্লকটি গ্রহণ করে না। যুক্তি!
চটপটি বিন বিন

32

আমি মনে করি এটি একটি কেস purrr::when। তাদের সংখ্যা 25 এর নিচে হলে কয়েকটি সংখ্যা যোগ করুন, অন্যথায় 0 প্রদান করুন।


library("magrittr")
1:3 %>% 
  purrr::when(sum(.) < 25 ~ sum(.), 
              ~0
  )
#> [1] 6

whenপ্রথম বৈধ শর্তের ক্রিয়া থেকে প্রাপ্ত মানটি প্রদান করে। বামদিকে শর্তটি এবং তার ডানদিকে ~কর্মটি রাখুন। উপরে, আমরা কেবল একটি শর্ত ব্যবহার করেছি (এবং তারপরে অন্য কোনও কেস), তবে আপনার অনেক শর্ত থাকতে পারে।

আপনি সহজেই এটি দীর্ঘতর পাইপের সাথে সংহত করতে পারেন।


4
সুন্দর! এটি 'স্যুইচ'-এর আরও স্বজ্ঞাত বিকল্প সরবরাহ করে।
স্টিভ জি জোনস

16

@ জনপল দ্বারা প্রদত্ত উত্তরের জন্য এখানে একটি পরিবর্তন রয়েছে। এই প্রকরণটি `if`যৌগিক if ... else ...বিবরণের পরিবর্তে ফাংশনটি ব্যবহার করে ।

library(magrittr)

X <- 1
Y <- TRUE

X %>% `if`(Y, . + 1, .) %>% multiply_by(2)
# [1] 4

মনে রাখবেন যে এক্ষেত্রে কোঁকড়া ধনুর্বন্ধনীগুলি `if`ফাংশনটির চারপাশে বা কোনও ifelseফাংশনের আশেপাশের প্রয়োজন হয় না - কেবলমাত্র if ... else ...বিবৃতিটির চারপাশে । তবে, যদি বিন্দু স্থানধারক কেবল নেস্টেড ফাংশন কলটিতে উপস্থিত হয়, তবে ম্যাজিট্রেটর ডিফল্টরূপে বাম হাতটি ডান হাতের প্রথম যুক্তির সাথে পাইপ করবে। এই আচরণটি কোঁকড়া ধনুর্বন্ধনীগুলিতে আবদ্ধ করে আবশ্যক। এই দুটি শৃঙ্খলের মধ্যে পার্থক্যটি দ্রষ্টব্য:

X %>% `if`(Y, . + 1, . + 2)
# [1] TRUE
X %>% {`if`(Y, . + 1, . + 2)}
# [1] 4

বিন্দুর স্থানধারকটি ফাংশনটিতে প্রদর্শিত হওয়ার পরে কোনও ফাংশন কলের মধ্যেই আস্তে আস্তে `if`থাকে, যেহেতু . + 1এবং যথাক্রমে এবং . + 2হিসাবে ব্যাখ্যা করা হয়। সুতরাং, প্রথম অভিব্যক্তি ফলাফলটি ফিরিয়ে দিচ্ছে , (অদ্ভুতভাবে যথেষ্ট, অতিরিক্ত অব্যক্ত যুক্তি সম্পর্কে অভিযোগ করে না), এবং দ্বিতীয় প্রকাশটি ফলাফলটি ফিরিয়ে দিচ্ছে যা এই ক্ষেত্রে কাঙ্ক্ষিত আচরণ।`+`(., 1)`+`(., 2)`if`(1, TRUE, 1 + 1, 1 + 2)`if``if`(TRUE, 1 + 1, 1 + 2)

ম্যাজিট্রিট পাইপ অপারেটর কীভাবে ডট প্লেসহোল্ডারের সাথে আচরণ করে সে সম্পর্কে আরও তথ্যের জন্য , বিশেষত "গৌণ উদ্দেশ্যে ডট ব্যবহার করা" বিভাগে বিভাগের জন্য সহায়তা ফাইলটি দেখুন %>%


ব্যবহার `ìf`এবং এর মধ্যে পার্থক্য কি ifelse? তারা কি আচরণে অভিন্ন?
চটপটি বিন

@ অগিলিবিয়ান ifএবং ifelseক্রিয়াকলাপগুলির আচরণ অভিন্ন নয়। ifelseফাংশন একটি ভেক্টরকৃত হয় if। আপনি যদি ifলজিকাল ভেক্টর সহ ফাংশন সরবরাহ করেন তবে এটি একটি সতর্কতা মুদ্রণ করবে এবং এটি কেবলমাত্র লজিকাল ভেক্টরের প্রথম উপাদানটি ব্যবহার করবে। তুলনা `if`(c(T, F), 1:2, 3:4)করার জন্য ifelse(c(T, F), 1:2, 3:4)
ক্যামেরন বিগানেক

দুর্দান্ত, স্পষ্টতার জন্য ধন্যবাদ! উপরের সমস্যাটি যেমন ভেক্টরবিহীন তাই আপনি নিজের সমাধানটিও লিখে রাখতে পারতেনX %>% { ifelse(Y, .+1, .+2) }
Agile Bean

12

পাইপগুলি থেকে সামান্য ছোট্ট করে ফিরে যাওয়া আমার পক্ষে সহজ মনে হবে (যদিও আমি অন্যান্য সমাধানগুলি দেখতে আগ্রহী হব), যেমন:

library("dplyr")
z <- data.frame(a=1:2)
z %>% mutate(b=a^2) -> z2
if (z2$b[1]>1) {
    z2 %>% mutate(b=b^2) -> z2
}
z2 %>% mutate(b=b^2) -> z3

এটি @ জনপলের উত্তরের একটি সামান্য পরিবর্তন (আপনি সম্ভবত এটি চাইবেন না ifelse, যা এর উভয় যুক্তির মূল্যায়ন করে এবং ভেক্টরাইজড)। .শর্তটি মিথ্যা হলে স্বয়ংক্রিয়ভাবে ফিরে আসার জন্য এটি সংশোধন করে ভাল লাগবে ... ( সাবধানতা : আমি মনে করি এটি কাজ করে তবে এটি সম্পর্কে সত্যিকার অর্থে পরীক্ষা / ধারণা করা হয়নি ...)

iff <- function(cond,x,y) {
    if(cond) return(x) else return(y)
}

z %>% mutate(b=a^2) %>%
    iff(cond=z2$b[1]>1,mutate(.,b=b^2),.) %>%
 mutate(b=b^2) -> z4

8

আমি পছন্দ করি purrr::whenএবং এখানে সরবরাহিত অন্যান্য বেস সমাধানগুলি দুর্দান্ত but তবে আমি আরও কমপ্যাক্ট এবং নমনীয় কিছু চাইছিলাম যাতে আমি ফাংশনটি ডিজাইন করলাম pif(পাইপ যদি হয়), উত্তরের শেষে কোড এবং ডকটি দেখুন।

আর্গুমেন্টগুলি হয় ফাংশনগুলির প্রকাশ হতে পারে (সূত্র নোটেশন সমর্থিত), এবং শর্ত থাকলে ইনপুটটি ডিফল্টরূপে অপরিবর্তিত অবস্থায় ফিরে আসে FALSE

অন্যান্য উত্তরের উদাহরণগুলিতে ব্যবহৃত:

## from Ben Bolker
data.frame(a=1:2) %>% 
  mutate(b=a^2) %>%
  pif(~b[1]>1, ~mutate(.,b=b^2)) %>%
  mutate(b=b^2)
#   a  b
# 1 1  1
# 2 2 16

## from Lorenz Walthert
1:3 %>% pif(sum(.) < 25,sum,0)
# [1] 6

## from clbieganek 
1 %>% pif(TRUE,~. + 1) %>% `*`(2)
# [1] 4

# from theforestecologist
1 %>% `+`(1) %>% pif(TRUE ,~ .+1)
# [1] 3

অন্যান্য উদাহরণ:

## using functions
iris %>% pif(is.data.frame, dim, nrow)
# [1] 150   5

## using formulas
iris %>% pif(~is.numeric(Species), 
             ~"numeric :)",
             ~paste(class(Species)[1],":("))
# [1] "factor :("

## using expressions
iris %>% pif(nrow(.) > 2, head(.,2))
#   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1          5.1         3.5          1.4         0.2  setosa
# 2          4.9         3.0          1.4         0.2  setosa

## careful with expressions
iris %>% pif(TRUE, dim,  warning("this will be evaluated"))
# [1] 150   5
# Warning message:
# In inherits(false, "formula") : this will be evaluated
iris %>% pif(TRUE, dim, ~warning("this won't be evaluated"))
# [1] 150   5

ফাংশন

#' Pipe friendly conditional operation
#'
#' Apply a transformation on the data only if a condition is met, 
#' by default if condition is not met the input is returned unchanged.
#' 
#' The use of formula or functions is recommended over the use of expressions
#' for the following reasons :
#' 
#' \itemize{
#'   \item If \code{true} and/or \code{false} are provided as expressions they 
#'   will be evaluated wether the condition is \code{TRUE} or \code{FALSE}.
#'   Functions or formulas on the other hand will be applied on the data only if
#'   the relevant condition is met
#'   \item Formulas support calling directly a column of the data by its name 
#'   without \code{x$foo} notation.
#'   \item Dot notation will work in expressions only if `pif` is used in a pipe
#'   chain
#' }
#' 
#' @param x An object
#' @param p A predicate function, a formula describing such a predicate function, or an expression.
#' @param true,false Functions to apply to the data, formulas describing such functions, or expressions.
#'
#' @return The output of \code{true} or \code{false}, either as expressions or applied on data as functions
#' @export
#'
#' @examples
#'# using functions
#'pif(iris, is.data.frame, dim, nrow)
#'# using formulas
#'pif(iris, ~is.numeric(Species), ~"numeric :)",~paste(class(Species)[1],":("))
#'# using expressions
#'pif(iris, nrow(iris) > 2, head(iris,2))
#'# careful with expressions
#'pif(iris, TRUE, dim,  warning("this will be evaluated"))
#'pif(iris, TRUE, dim, ~warning("this won't be evaluated"))
pif <- function(x, p, true, false = identity){
  if(!requireNamespace("purrr")) 
    stop("Package 'purrr' needs to be installed to use function 'pif'")

  if(inherits(p,     "formula"))
    p     <- purrr::as_mapper(
      if(!is.list(x)) p else update(p,~with(...,.)))
  if(inherits(true,  "formula"))
    true  <- purrr::as_mapper(
      if(!is.list(x)) true else update(true,~with(...,.)))
  if(inherits(false, "formula"))
    false <- purrr::as_mapper(
      if(!is.list(x)) false else update(false,~with(...,.)))

  if ( (is.function(p) && p(x)) || (!is.function(p) && p)){
    if(is.function(true)) true(x) else true
  }  else {
    if(is.function(false)) false(x) else false
  }
}

"অন্যদিকে কার্যকারিতা বা সূত্রগুলি প্রাসঙ্গিক শর্ত পূরণ হলেই ডেটাতে প্রয়োগ করা হবে।" আপনি কেন এমন সিদ্ধান্ত নিয়েছেন তা ব্যাখ্যা করতে পারেন?
মিহাগজভোদা

সুতরাং আমি কেবল আমার গণনা করার জন্য যা প্রয়োজন তা গণনা করি, তবে কেন আমি প্রকাশের সাথে তা না করলাম তা অবাক করি। কিছু কারণে মনে হচ্ছে আমি অ-মানক মূল্যায়ন ব্যবহার করতে চাই না। আমি মনে করি আমার কাস্টম ফাংশনগুলিতে আমার একটি পরিবর্তিত সংস্করণ রয়েছে, সুযোগ পেলেই আপডেট করব।
মুডি_ মুডস্কিপার

আপনি এটি আপডেট করার সময় দয়া করে আমাকে জানান। ধন্যবাদ!
মিহাগজভোদা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.