`Dplyr` এ গতিশীল পরিবর্তনশীল নাম ব্যবহার করুন`


168

আমি dplyr::mutate()একটি ডেটা ফ্রেমে একাধিক নতুন কলাম তৈরি করতে ব্যবহার করতে চাই । কলামের নাম এবং তাদের বিষয়বস্তু গতিশীলভাবে উত্পন্ন করা উচিত।

আইরিস থেকে ডেটা উদাহরণ:

library(dplyr)
iris <- tbl_df(iris)

আমি Petal.Widthভেরিয়েবল থেকে আমার নতুন কলামগুলি পরিবর্তন করতে একটি ফাংশন তৈরি করেছি :

multipetal <- function(df, n) {
    varname <- paste("petal", n , sep=".")
    df <- mutate(df, varname = Petal.Width * n)  ## problem arises here
    df
}

এখন আমি আমার কলামগুলি তৈরি করতে একটি লুপ তৈরি করব:

for(i in 2:5) {
    iris <- multipetal(df=iris, n=i)
}

তবে, যেহেতু মিউটেট মনে করে যে বর্ণনামটি একটি আক্ষরিক পরিবর্তনশীল নাম, তাই লুপটি কেবলমাত্র চারটি (পেটাল ২ - পাপড়ি বলে) বলা হয়) এর পরিবর্তে একটি নতুন ভেরিয়েবল তৈরি করে (যার নাম ভেরনাম) creates

আমি mutate()আমার গতিশীল নামটি পরিবর্তনশীল নাম হিসাবে কীভাবে ব্যবহার করতে পারি ?


1
আমি পরিবর্তন নিয়ে জোর দিচ্ছি না, আমি জিজ্ঞাসা করছি এটি সম্ভব কিনা। হতে পারে এটি কেবল একটি ছোট কৌশল যা আমি জানি না। যদি অন্য কোনও উপায় থাকে তবে আসুন এটি শুনি।
টিম এস এস

আমি সেখানে বিশ্বাস ঘড়িতে একটি স্থান মধ্যে lazyeval প্যাকেজ
Baptiste


16
উইগনেট এমনকি উল্লেখ করে না mutate_, এবং এটি কীভাবে এটি ব্যবহার করতে হয় তা অন্যান্য কার্যকারিতা থেকে সত্যই স্পষ্ট হয় না।
ন্যাকনডাস

উত্তর:


191

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

multipetal <- function(df, n) {
    varname <- paste("petal", n , sep=".")
    df[[varname]] <- with(df, Petal.Width * n)
    df
}

দ্য mutateফাংশন এটি খুব সহজ নামে পরামিতি মাধ্যমে নতুন কলাম নাম করে তোলে। তবে ধরে নেওয়া যায় আপনি কমান্ডটি টাইপ করার সময় নামটি জানতেন। আপনি যদি কলামের নামটি গতিশীলভাবে নির্দিষ্ট করতে চান, তবে আপনাকে নামযুক্ত যুক্তিটিও তৈরি করতে হবে।


dplyr সংস্করণ> = 0.7

dplyr(0.7) এর সর্বশেষতম সংস্করণটি :=প্যারামিটারের নামগুলি গতিশীলরূপে বরাদ্দ করে ব্যবহার করে এটি করে । আপনি আপনার ফাংশনটি লিখতে পারেন:

# --- dplyr version 0.7+---
multipetal <- function(df, n) {
    varname <- paste("petal", n , sep=".")
    mutate(df, !!varname := Petal.Width * n)
}

আরও তথ্যের জন্য ডকুমেন্টেশন উপলভ্য ফর্মটি দেখুন vignette("programming", "dplyr")


dplyr (> = 0.3 এবং <0.7)

সামান্য পূর্ববর্তী সংস্করণ dplyr(> = 0.3 <0.7), অনেকগুলি কার্যকারিতার "স্ট্যান্ডার্ড মূল্যায়ন" বিকল্পের ব্যবহারকে উত্সাহিত করেছিল। আরও তথ্যের জন্য অ-মানক মূল্যায়ন ভিগনেট দেখুন ( vignette("nse"))।

সুতরাং এখানে, উত্তরটি ব্যবহার mutate_()না করে ব্যবহার করা উচিত mutate():

# --- dplyr version 0.3-0.5---
multipetal <- function(df, n) {
    varname <- paste("petal", n , sep=".")
    varval <- lazyeval::interp(~Petal.Width * n, n=n)
    mutate_(df, .dots= setNames(list(varval), varname))
}

dplyr <0.3

নোট dplyrকরুন প্রশ্নটি যখন মূলত উত্থাপিত হয়েছিল তখন এর পুরানো সংস্করণগুলিতে এটিও সম্ভব । এটির যত্ন সহকারে ব্যবহার প্রয়োজন quoteএবং setName:

# --- dplyr versions < 0.3 ---
multipetal <- function(df, n) {
    varname <- paste("petal", n , sep=".")
    pp <- c(quote(df), setNames(list(quote(Petal.Width * n)), varname))
    do.call("mutate", pp)
}

24
আপনাকে ধন্যবাদ, এটি সহায়ক। বিটিডব্লিউ, আমি সর্বদা সত্যই নাটকীয় পরিবর্তনশীল তৈরি করি।
টিম এস এস

27
হে হে। এটি সম্ভবত আমার প্রিয় টাইপগুলির মধ্যে একটি যা আমি কিছুক্ষণের মধ্যে তৈরি করেছি। আমি মনে করি আমি এটি ছেড়ে দেব।
মিস্টার ফ্লিক

1
do.call()সম্ভবত আপনি যা মনে করেন তা করেন না: rpubs.com/hadley/do-call2 । Dplyr এর ডিভ সংস্করণে এনএসই ভিগনেটটিও দেখুন।
হ্যাডলি

4
সুতরাং আমি যদি আপনার হ্যাডলি পয়েন্টটি বুঝতে পারি তবে আমি do.callব্যবহারের জন্য do.call("mutate")এবং dfতালিকার উদ্ধৃতিটি উপরে আপডেট করেছি । আপনি কি পরামর্শ দিচ্ছেন? এবং যখন lazyevalসংস্করণটি dplyrপ্রকাশিত সংস্করণ হয়, তবে mutate_(df, .dots= setNames(list(~Petal.Width * n), varname))কি আরও ভাল সমাধান হতে পারে?
মিস্টার ফ্লিক

1
আমার যদি কেবল অ্যাসাইনমেন্টের বাম দিকে নয় তবে ডানদিকেও পরিবর্তনশীল কলামের শিরোনামের প্রয়োজন হয়? যেমন mutate(df, !!newVar := (!!var1 + !!var2) / 2)কাজ করে না :(
মারিও রিউটার

55

dplyr( 0.6.0এপ্রিল 2017 এর অপেক্ষায়) এর নতুন প্রকাশে আমরা একটি অ্যাসাইনমেন্টও করতে পারি ( :=) এবং !!মূল্যায়ন না করার জন্য ( ) উদ্ধৃতি দিয়ে কলামের নাম হিসাবে ভেরিয়েবলগুলি পাস করতে পারি

 library(dplyr)
 multipetalN <- function(df, n){
      varname <- paste0("petal.", n)
      df %>%
         mutate(!!varname := Petal.Width * n)
 }

 data(iris)
 iris1 <- tbl_df(iris)
 iris2 <- tbl_df(iris)
 for(i in 2:5) {
     iris2 <- multipetalN(df=iris2, n=i)
 }   

multipetal'মিরিফ্লিক'-এর' আইরিস 1 ' এর প্রয়োগের ভিত্তিতে আউটপুট চেক করা হচ্ছে

identical(iris1, iris2)
#[1] TRUE

26

অনেক পরীক্ষা এবং ত্রুটির পরেও আমি প্যাটার্নটি পেয়েছি UQ(rlang::sym("some string here"))) স্ট্রিং এবং ডিপি্লায়ার ক্রিয়াগুলির সাথে কাজ করার জন্য সত্যই দরকারী বলে মনে করি। এটি অনেক আশ্চর্যজনক পরিস্থিতিতে কাজ করে বলে মনে হচ্ছে।

এখানে একটি উদাহরণ mutate। আমরা একটি ফাংশন তৈরি করতে চাই যা দুটি কলাম একসাথে যুক্ত করে, যেখানে আপনি উভয় কলামের নামকে স্ট্রিং হিসাবে পাস করেন। এটি করার জন্য আমরা অ্যাসাইনমেন্ট অপারেটরের সাথে এই প্যাটার্নটি ব্যবহার :=করতে পারি।

## Take column `name1`, add it to column `name2`, and call the result `new_name`
mutate_values <- function(new_name, name1, name2){
  mtcars %>% 
    mutate(UQ(rlang::sym(new_name)) :=  UQ(rlang::sym(name1)) +  UQ(rlang::sym(name2)))
}
mutate_values('test', 'mpg', 'cyl')

প্যাটার্নটি অন্যান্য dplyrফাংশনগুলির সাথেও কাজ করে। এখানে filter:

## filter a column by a value 
filter_values <- function(name, value){
  mtcars %>% 
    filter(UQ(rlang::sym(name)) != value)
}
filter_values('gear', 4)

বা arrange:

## transform a variable and then sort by it 
arrange_values <- function(name, transform){
  mtcars %>% 
    arrange(UQ(rlang::sym(name)) %>%  UQ(rlang::sym(transform)))
}
arrange_values('mpg', 'sin')

কারণ select, আপনার প্যাটার্নটি ব্যবহার করার দরকার নেই। পরিবর্তে আপনি ব্যবহার করতে পারেন !!:

## select a column 
select_name <- function(name){
  mtcars %>% 
    select(!!name)
}
select_name('mpg')

আপনার টিপস খুব ভাল কাজ করে, তবে আমার কিছুটা সমস্যা আছে। আমি একটি প্রাথমিক কলামটি myColইউআরএল (উদাহরণস্বরূপ) এ পরিবর্তন করি myColInitialValueএবং ডেটাফ্রেমের শেষে পুরাতন কলামটি dfএকটি নতুন নাম দিয়ে অনুলিপি করি । তবে একটি which(colnames(df)=='myCol')কলটি # এর পাঠান myColInitialValue। আমি কোনও ইস্যু লিখিনি কারণ আমি কোনও উপসংহার খুঁজে পেলাম না। আমার লক্ষ্যটি escapeপ্যারামিটারের জন্য DT::datatable()। আমি escape=FALSEঅপেক্ষা করছি। ধ্রুবক সহ এটি কাজ করে না তবে টিটি প্যাকেজটি খারাপ # কলামও পেয়েছে বলে মনে হচ্ছে। :)
ফিলি_বি


দেখে মনে হচ্ছে গতিশীল ভেরিয়েবলের কারণ নয়। (বিটিডব্লিউ ডিপেক্স যোগ করা হয়েছে)
ফিলি_বি

এই উত্তরের জন্য ধন্যবাদ! এখানে আমি এটি কীভাবে ব্যবহার করেছি তার একটি অতি-সহজ উদাহরণ:varname = sym("Petal.Width"); ggplot(iris, aes(x=!!varname)) + geom_histogram()
bdemarest

এটি আমার জন্য এমন একটি সূত্রের ভিতরে কাজ করেছিল যেখানে !! বর্ণটি কাজ করে না।
ডাকাত

12

এখানে অন্য সংস্করণ রয়েছে এবং এটি যুক্তিযুক্ত কিছুটা সহজ ler

multipetal <- function(df, n) {
    varname <- paste("petal", n, sep=".")
    df<-mutate_(df, .dots=setNames(paste0("Petal.Width*",n), varname))
    df
}

for(i in 2:5) {
    iris <- multipetal(df=iris, n=i)
}

> head(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species petal.2 petal.3 petal.4 petal.5
1          5.1         3.5          1.4         0.2  setosa     0.4     0.6     0.8       1
2          4.9         3.0          1.4         0.2  setosa     0.4     0.6     0.8       1
3          4.7         3.2          1.3         0.2  setosa     0.4     0.6     0.8       1
4          4.6         3.1          1.5         0.2  setosa     0.4     0.6     0.8       1
5          5.0         3.6          1.4         0.2  setosa     0.4     0.6     0.8       1
6          5.4         3.9          1.7         0.4  setosa     0.8     1.2     1.6       2

8

আমাদের সাথে rlang 0.4.0কোঁকড়ানো-কোঁকড়ানো অপারেটর রয়েছে ( {{}}) যা এটি খুব সহজ করে তোলে।

library(dplyr)
library(rlang)

iris1 <- tbl_df(iris)

multipetal <- function(df, n) {
   varname <- paste("petal", n , sep=".")
   mutate(df, {{varname}} := Petal.Width * n)
}

multipetal(iris1, 4)

# A tibble: 150 x 6
#   Sepal.Length Sepal.Width Petal.Length Petal.Width Species petal.4
#          <dbl>       <dbl>        <dbl>       <dbl> <fct>     <dbl>
# 1          5.1         3.5          1.4         0.2 setosa      0.8
# 2          4.9         3            1.4         0.2 setosa      0.8
# 3          4.7         3.2          1.3         0.2 setosa      0.8
# 4          4.6         3.1          1.5         0.2 setosa      0.8
# 5          5           3.6          1.4         0.2 setosa      0.8
# 6          5.4         3.9          1.7         0.4 setosa      1.6
# 7          4.6         3.4          1.4         0.3 setosa      1.2
# 8          5           3.4          1.5         0.2 setosa      0.8
# 9          4.4         2.9          1.4         0.2 setosa      0.8
#10          4.9         3.1          1.5         0.1 setosa      0.4
# … with 140 more rows

কলামের নাম হিসাবে নির্ধারিত হওয়ার জন্য আমরা উদ্ধৃত / অব্যক্ত ভেরিয়েবলের নামগুলিও পাস করতে পারি।

multipetal <- function(df, name, n) {
   mutate(df, {{name}} := Petal.Width * n)
}

multipetal(iris1, temp, 3)

# A tibble: 150 x 6
#   Sepal.Length Sepal.Width Petal.Length Petal.Width Species  temp
#          <dbl>       <dbl>        <dbl>       <dbl> <fct>   <dbl>
# 1          5.1         3.5          1.4         0.2 setosa  0.6  
# 2          4.9         3            1.4         0.2 setosa  0.6  
# 3          4.7         3.2          1.3         0.2 setosa  0.6  
# 4          4.6         3.1          1.5         0.2 setosa  0.6  
# 5          5           3.6          1.4         0.2 setosa  0.6  
# 6          5.4         3.9          1.7         0.4 setosa  1.2  
# 7          4.6         3.4          1.4         0.3 setosa  0.900
# 8          5           3.4          1.5         0.2 setosa  0.6  
# 9          4.4         2.9          1.4         0.2 setosa  0.6  
#10          4.9         3.1          1.5         0.1 setosa  0.3  
# … with 140 more rows

এটি একই সাথে কাজ করে

multipetal(iris1, "temp", 3)

4

আমি একটি উত্তরও যোগ করছি যা এটি সামান্য বাড়িয়েছে কারণ উত্তর অনুসন্ধানের সময় আমি এই এন্ট্রিতে এসেছি এবং এটির আমার প্রায় প্রয়োজন ছিল তবে আমার আরও কিছু দরকার ছিল যা আমি এমআরফ্লিকের উত্তর এবং এর মাধ্যমে পেয়েছি আর লাজিয়েভাল ভিগনেটস।

আমি এমন একটি ফাংশন তৈরি করতে চেয়েছিলাম যা ডেটাফ্রেম এবং কলামের নামের একটি ভেক্টর (স্ট্রিং হিসাবে) নিতে পারে যা আমি স্ট্রিং থেকে তারিখের অবজেক্টে রূপান্তর করতে চাই। আমি কীভাবে as.Date()আর্গুমেন্টটি স্ট্রিং করব এবং এটি একটি কলামে রূপান্তর করব তা বুঝতে পারছিলাম না, সুতরাং নীচের মত আমি এটি করেছি।

নীচে আমি এসই মিউটেট ( mutate_()) এবং .dotsযুক্তির মাধ্যমে এটি কীভাবে করেছি । সমালোচনা যা এটিকে আরও উন্নত করে তা স্বাগত।

library(dplyr)

dat <- data.frame(a="leave alone",
                  dt="2015-08-03 00:00:00",
                  dt2="2015-01-20 00:00:00")

# This function takes a dataframe and list of column names
# that have strings that need to be
# converted to dates in the data frame
convertSelectDates <- function(df, dtnames=character(0)) {
    for (col in dtnames) {
        varval <- sprintf("as.Date(%s)", col)
        df <- df %>% mutate_(.dots= setNames(list(varval), col))
    }
    return(df)
}

dat <- convertSelectDates(dat, c("dt", "dt2"))
dat %>% str

3

ইন্টারেক্টিভ ব্যবহারের জন্য আমি dplyr ব্যবহার করে উপভোগ করার সময়, dplyr ব্যবহার করে এটি করা আমার কাছে অসাধারণ কৌশল বলে মনে হচ্ছে কারণ lazyeval :: ইন্টারপ (), সেটনাম, ইত্যাদি কাজের ক্ষেত্রগুলি ব্যবহার করতে আপনাকে হুপের মধ্য দিয়ে যেতে হবে।

এখানে বেস আর ব্যবহার করে একটি সহজ সংস্করণ দেওয়া হয়েছে, এতে কমপক্ষে আমার কাছে ফাংশনের অভ্যন্তরে লুপটি রাখার জন্য এটি আরও স্বজ্ঞাত বলে মনে হয় এবং যা মিঃফ্লিক্সের সমাধানকে প্রসারিত করে।

multipetal <- function(df, n) {
   for (i in 1:n){
      varname <- paste("petal", i , sep=".")
      df[[varname]] <- with(df, Petal.Width * i)
   }
   df
}
multipetal(iris, 3) 

2
+1, যদিও আমি dplyrঅ-ইন্টারেক্টিভ সেটিংসে এখনও প্রচুর পরিমাণে ব্যবহার করি তবে এটি কোনও ফাংশনের অভ্যন্তরে ভ্যারিয়েবল ইনপুট দিয়ে ব্যবহার করা খুব চঞ্চল সিনট্যাক্স ব্যবহার করে।
পল হিমস্ট্র্রা

3

আপনি প্যাকেজটি উপভোগ করতে পারেন friendlyevalযা নতুন / নৈমিত্তিক dplyrব্যবহারকারীদের জন্য একটি সরলীকৃত পরিচ্ছন্ন ইভিএল এবং ডকুমেন্টেশন উপস্থাপন করে।

আপনি স্ট্রিংগুলি তৈরি করছেন যা আপনি mutateকলামের নাম হিসাবে বিবেচনা করতে চান । সুতরাং friendlyevalআপনি লিখতে পারে ব্যবহার করে:

multipetal <- function(df, n) {
  varname <- paste("petal", n , sep=".")
  df <- mutate(df, !!treat_string_as_col(varname) := Petal.Width * n)
  df
}

for(i in 2:5) {
  iris <- multipetal(df=iris, n=i)
}

যা হুডের অধীনে কল করে rlangফাংশন যা পরীক্ষা করেvarname এটি কলামের নাম হিসাবে বৈধ।

friendlyeval কোডটি কোনও সময় কোনও আরস্টুডিও অ্যাডিনের সাথে সমতুল্য পরিপাটি এভাল কোডে রূপান্তর করা যায়।

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