একটি ফাংশনে একটি ডেটা ফ্রেম কলামের নাম পাস করুন


119

আমি একটি ডেটা.ফ্রেম ( x) এবং columnএটি থেকে একটি গ্রহণ করার জন্য একটি ফাংশন লেখার চেষ্টা করছি । ফাংশনটি এক্স এর উপর কিছু গণনা সম্পাদন করে এবং পরে অন্য ডেটা.ফ্রেম দেয়। ফাংশনে কলামের নামটি পাস করার জন্য আমি সেরা-অনুশীলন পদ্ধতিতে আটকে আছি।

দু'টি ন্যূনতম উদাহরণ fun1এবং fun2নীচে উদাহরণস্বরূপ x$columnব্যবহার করে ক্রিয়াকলাপ করতে সক্ষম হয়ে কাঙ্ক্ষিত ফলাফল দেয় max()। যাইহোক, উভয়ই আপাতদৃষ্টিতে (কমপক্ষে আমার কাছে) অবাস্তব উপর নির্ভর করে

  1. কল substitute()এবং সম্ভবতeval()
  2. একটি ক্যারেক্টার ভেক্টর হিসাবে কলামের নামটি পাস করার প্রয়োজন।

fun1 <- function(x, column){
  do.call("max", list(substitute(x[a], list(a = column))))
}

fun2 <- function(x, column){
  max(eval((substitute(x[a], list(a = column)))))
}

df <- data.frame(B = rnorm(10))
fun1(df, "B")
fun2(df, "B")

fun(df, B)উদাহরণস্বরূপ, আমি ফাংশনটি কল করতে সক্ষম হতে চাই । অন্যান্য বিকল্পগুলি আমি বিবেচনা করেছি কিন্তু চেষ্টা করেছি না:

  • columnকলাম নম্বরটির পূর্ণসংখ্যা হিসাবে পাস করুন । আমি মনে করি এটি এড়ানো হবে substitute()। আদর্শভাবে, ফাংশনটি গ্রহণ করতে পারে।
  • with(x, get(column)), তবে, এটি কার্যকর হলেও, আমি মনে করি এটি এখনও প্রয়োজন substitute
  • ব্যবহার করুন formula()এবং match.call(), যার সাথে আমার খুব বেশি অভিজ্ঞতা আছে।

সাবেকশন : do.call()বেশি পছন্দ eval()?

উত্তর:


108

আপনি কেবল কলামের নাম সরাসরি ব্যবহার করতে পারেন:

df <- data.frame(A=1:10, B=2:11, C=3:12)
fun1 <- function(x, column){
  max(x[,column])
}
fun1(df, "B")
fun1(df, c("B","A"))

বিকল্প, ইওয়াল ইত্যাদি ব্যবহার করার দরকার নেই

এমনকি আপনি প্যারামিটার হিসাবে পছন্দসই ফাংশনটি পাস করতে পারেন:

fun1 <- function(x, column, fn) {
  fn(x[,column])
}
fun1(df, "B", max)

বিকল্পভাবে, [[একবারে একক কলাম নির্বাচন করার জন্যও ব্যবহার করে :

df <- data.frame(A=1:10, B=2:11, C=3:12)
fun1 <- function(x, column){
  max(x[[column]])
}
fun1(df, "B")

14
স্ট্রিং হিসাবে কলামের নামটি পাস করার কোনও উপায় আছে কি?
কিমিমি

2
আপনার হয় হয় একটি অক্ষর হিসাবে উদ্ধৃত কলামের নাম বা কলামটির জন্য পূর্ণসংখ্যা সূচকটি পাস করতে হবে। কেবল পাসিংটি Bধরে নেওয়া হবে যে বি নিজেই একটি বস্তু।
শেন

আমি দেখি. আমি নিশ্চিত না কীভাবে আমি
সংশ্লেষিত

3
ধন্যবাদ! আমি [[সমাধানটি একমাত্র আমার জন্য কাজ করেছিলাম।
ইকোলজি টম


78

এই উত্তরটি বিদ্যমান উত্তরের মতো একই উপাদানগুলির অনেকটিকে কভার করবে, তবে এই সমস্যাটি (কলামের নামগুলি ফাংশনগুলিতে প্রেরণ করা) প্রায়শই যথেষ্ট আসে যে আমি সেখানে এমন উত্তর চেয়েছিলাম যা কিছুটা আরও বিস্তৃতভাবে coveredাকা থাকে।

মনে করুন আমাদের একটি খুব সাধারণ ডেটা ফ্রেম রয়েছে:

dat <- data.frame(x = 1:4,
                  y = 5:8)

এবং আমরা এমন একটি ফাংশন লিখতে চাই যা একটি নতুন কলাম তৈরি করে zযা কলামগুলির সমষ্টি xএবং y

এখানে একটি খুব সাধারণ হোঁচট খাচ্ছে যে একটি প্রাকৃতিক (তবে ভুল) প্রচেষ্টা প্রায়শই এরকম দেখাচ্ছে:

foo <- function(df,col_name,col1,col2){
      df$col_name <- df$col1 + df$col2
      df
}

#Call foo() like this:    
foo(dat,z,x,y)

এখানে সমস্যাটি হ'ল df$col1অভিব্যক্তিটি মূল্যায়ন করে না col1। এটি কেবল dfআক্ষরিক নামে পরিচিত একটি কলামের সন্ধান করে col1। এই আচরণটি ?Extract"পুনরাবৃত্ত (তালিকার মতো) অবজেক্টস" বিভাগে বর্ণিত হয়েছে ।

সবচেয়ে সহজ এবং অধিকাংশ প্রায়ই সুপারিশ সমাধান কেবল থেকে সুইচ হয় $যাও [[স্ট্রিং হিসেবে এবং ফাংশন আর্গুমেন্ট পাস:

new_column1 <- function(df,col_name,col1,col2){
    #Create new column col_name as sum of col1 and col2
    df[[col_name]] <- df[[col1]] + df[[col2]]
    df
}

> new_column1(dat,"z","x","y")
  x y  z
1 1 5  6
2 2 6  8
3 3 7 10
4 4 8 12

এটিকে প্রায়শই "সেরা অনুশীলন" হিসাবে বিবেচনা করা হয় কারণ এটি এমন পদ্ধতি যা স্ক্রু করা সবচেয়ে কঠিন। স্ট্রিং হিসাবে কলামের নামগুলি পাস করা ততই দ্ব্যর্থহীন get

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

আপনি যদি এই সমস্ত উদ্ধৃতিটি টাইপ করা থেকে সত্যই ব্যবহারকারীর সংরক্ষণ করতে চান তবে একটি বিকল্প হতে পারে খালি, অব্যক্ত কলামের নামগুলি স্ট্রিংয়ে রূপান্তর করে deparse(substitute()):

new_column2 <- function(df,col_name,col1,col2){
    col_name <- deparse(substitute(col_name))
    col1 <- deparse(substitute(col1))
    col2 <- deparse(substitute(col2))

    df[[col_name]] <- df[[col1]] + df[[col2]]
    df
}

> new_column2(dat,z,x,y)
  x y  z
1 1 5  6
2 2 6  8
3 3 7 10
4 4 8 12

এটি সত্যিই, কিছুটা নির্বোধ সম্ভবত, যেহেতু আমরা new_column1খালি নামগুলি স্ট্রিংয়ে রূপান্তর করতে কেবল অতিরিক্ত কাজ করে যাচ্ছি ঠিক তেমন কাজ করছি ।

পরিশেষে, আমরা যদি সত্যই অভিনব হতে চাই , আমরা সিদ্ধান্ত নিতে পারি যে দুটি কলামের নাম যুক্ত করার পরিবর্তে আমরা আরও নমনীয় হতে চাই এবং দুটি ভেরিয়েবলের অন্য সংমিশ্রণের অনুমতি দিতে চাই। eval()সেক্ষেত্রে আমরা সম্ভবত দুটি কলাম জড়িত একটি এক্সপ্রেশন ব্যবহার করে অবলম্বন করব :

new_column3 <- function(df,col_name,expr){
    col_name <- deparse(substitute(col_name))
    df[[col_name]] <- eval(substitute(expr),df,parent.frame())
    df
}

কেবল মজাদার জন্য, আমি এখনও deparse(substitute())নতুন কলামটির নাম ব্যবহার করছি । এখানে, নীচের সমস্তগুলি কাজ করবে:

> new_column3(dat,z,x+y)
  x y  z
1 1 5  6
2 2 6  8
3 3 7 10
4 4 8 12
> new_column3(dat,z,x-y)
  x y  z
1 1 5 -4
2 2 6 -4
3 3 7 -4
4 4 8 -4
> new_column3(dat,z,x*y)
  x y  z
1 1 5  5
2 2 6 12
3 3 7 21
4 4 8 32

সুতরাং সংক্ষিপ্ত উত্তরটি মূলত: ডাটা.ফ্রেমে কলামের নামগুলি স্ট্রিং হিসাবে পাস [[করুন এবং একক কলাম নির্বাচন করতে ব্যবহার করুন। শুধু ঢোকাতে শুরু eval, substituteইত্যাদি যদি সত্যিই জানি তুমি কি করছেন।


1
কেন এটি নির্বাচিত সেরা উত্তর নয় তা নিশ্চিত নন।
আয়ান

অমি ও না! দুর্দান্ত ব্যাখ্যা!
আলফ্রেডো জি মার্কেজ

22

ব্যক্তিগতভাবে আমি মনে করি যে কলামটি স্ট্রিং হিসাবে পাস করা বেশ কুশ্রী। আমি কিছু করতে পছন্দ করি:

get.max <- function(column,data=NULL){
    column<-eval(substitute(column),data, parent.frame())
    max(column)
}

যা ফল দেবে:

> get.max(mpg,mtcars)
[1] 33.9
> get.max(c(1,2,3,4,5))
[1] 5

ডেটা.ফ্রেমের স্পেসিফিকেশন কীভাবে alচ্ছিক তা লক্ষ্য করুন। এমনকি আপনি আপনার কলামগুলির কার্যকারিতা সহ কাজ করতে পারেন:

> get.max(1/mpg,mtcars)
[1] 0.09615385

9
আপনার উদ্ধৃতি ব্যবহার করা অভ্যাস থেকে দূরে থাকা দরকার is তাদের ব্যবহার না করা কুৎসিত! কেন? কারণ আপনি এমন একটি ফাংশন তৈরি করেছেন যা কেবল ইন্টারেক্টিভভাবে ব্যবহার করা যেতে পারে - এটির সাথে প্রোগ্রাম করা খুব কঠিন।
হ্যাডলি

27
আমি আরও ভাল উপায় দেখায় খুশি, তবে আমি এই এবং কিপ্লট (এক্স = এমপিজি, ডেটা = এমটিকার্স) এর মধ্যে পার্থক্য দেখতে ব্যর্থ হয়েছি। ggplot2 কখনই স্ট্রিং হিসাবে একটি কলামটি পাস করে না এবং আমি মনে করি এটি এর জন্য ভাল। আপনি কেন বলছেন যে এটি কেবল ইন্টারেক্টিভভাবে ব্যবহার করা যেতে পারে? কোন পরিস্থিতিতে এটি অনাকাঙ্ক্ষিত ফলাফলের দিকে নিয়ে যাবে? কীভাবে এটির সাথে প্রোগ্রাম করা আরও কঠিন? পোস্টটির শিরোনামে আমি এটি আরও নমনীয়ভাবে প্রদর্শন করি।
ইয়ান ফেলো

4
5 বছর পরে -) .. আমাদের কেন দরকার: প্যারেন্ট.ফ্রেম ()?
mql4beginner

15
7 বছর পরে: এখনও কুশল ব্যবহার করছেন না?
স্পেসডম্যান

11

আরেকটি উপায় হল tidy evaluationপদ্ধতির ব্যবহার । স্ট্রিং বা খালি কলামের নাম হিসাবে কোনও ডেটা ফ্রেমের কলামগুলি পাস করা বেশ সোজা। tidyeval এখানে আরও দেখুন ।

library(rlang)
library(tidyverse)

set.seed(123)
df <- data.frame(B = rnorm(10), D = rnorm(10))

স্ট্রিং হিসাবে কলামের নাম ব্যবহার করুন

fun3 <- function(x, ...) {
  # capture strings and create variables
  dots <- ensyms(...)
  # unquote to evaluate inside dplyr verbs
  summarise_at(x, vars(!!!dots), list(~ max(., na.rm = TRUE)))
}

fun3(df, "B")
#>          B
#> 1 1.715065

fun3(df, "B", "D")
#>          B        D
#> 1 1.715065 1.786913

খালি কলামের নাম ব্যবহার করুন

fun4 <- function(x, ...) {
  # capture expressions and create quosures
  dots <- enquos(...)
  # unquote to evaluate inside dplyr verbs
  summarise_at(x, vars(!!!dots), list(~ max(., na.rm = TRUE)))
}

fun4(df, B)
#>          B
#> 1 1.715065

fun4(df, B, D)
#>          B        D
#> 1 1.715065 1.786913
#>

2019-03-01 এ ডিপেক্স প্যাকেজ (v0.2.1.9000) দ্বারা তৈরি করা হয়েছে



1

অতিরিক্ত চিন্তা হিসাবে, কাস্টম ফাংশন থেকে অনুপযুক্ত কলামের নামটি পাস করার প্রয়োজন হলে match.call(), বিকল্প হিসাবে এটি সম্ভবত এই ক্ষেত্রেও কার্যকর হতে পারে deparse(substitute()):

df <- data.frame(A = 1:10, B = 2:11)

fun <- function(x, column){
  arg <- match.call()
  max(x[[arg$column]])
}

fun(df, A)
#> [1] 10

fun(df, B)
#> [1] 11

কলামের নামটিতে যদি টাইপ থাকে তবে ত্রুটি সহ থামানো আরও নিরাপদ হবে:

fun <- function(x, column) max(x[[match.call()$column]])
fun(df, typo)
#> Warning in max(x[[match.call()$column]]): no non-missing arguments to max;
#> returning -Inf
#> [1] -Inf

# Stop with error in case of typo
fun <- function(x, column){
  arg <- match.call()
  if (is.null(x[[arg$column]])) stop("Wrong column name")
  max(x[[arg$column]])
}

fun(df, typo)
#> Error in fun(df, typo): Wrong column name
fun(df, A)
#> [1] 10

2019-01-11 তারিখে ডিপেক্স প্যাকেজ (v0.2.1) দ্বারা তৈরি

আমি মনে করি না যে আমি উপরোক্ত উত্তরগুলিতে নির্দেশিত হিসাবে উদ্ধৃত কলামের নামটি পাস করার চেয়ে অতিরিক্ত টাইপিং এবং জটিলতা থাকায় এই পদ্ধতির ব্যবহার করব, তবে ভাল, এটি একটি পদ্ধতির।

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