ডেটা নির্বাচন করুন / বরাদ্দ করুন। যখন ভেরিয়েবলের নাম একটি অক্ষর ভেক্টরে সংরক্ষণ করা হয় তখন সারণি


92

data.tableযদি ভেরিয়েবলের নাম একটি অক্ষর ভেক্টরে সংরক্ষণ করা হয় তবে আপনি কীভাবে ভেরিয়েবলগুলি উল্লেখ করবেন ? উদাহরণস্বরূপ, এটি একটির জন্য কাজ করে data.frame:

df <- data.frame(col1 = 1:3)
colname <- "col1"
df[colname] <- 4:6
df
#   col1
# 1    4
# 2    5
# 3    6

চিহ্নিতকরণ সহ বা ছাড়াই আমি কীভাবে এই একই অপারেশনটি ডেটা টেবিলের জন্য সম্পাদন করতে পারি :=? এর সুস্পষ্ট জিনিসটি dt[ , list(colname)]কাজ করে না (বা আমি এটি আশাও করিনি)।

উত্তর:


133

প্রোগ্রাম্যালি ভেরিয়েবল (গুলি) নির্বাচন করার দুটি উপায় :

  1. with = FALSE:

     DT = data.table(col1 = 1:3)
     colname = "col1"
     DT[, colname, with = FALSE] 
     #    col1
     # 1:    1
     # 2:    2
     # 3:    3
    
  2. 'ডট ডট' ( ..) উপসর্গ:

     DT[, ..colname]    
     #    col1
     # 1:    1
     # 2:    2
     # 3:    3
    

'ডট ডট' ( ..) স্বরলিপিটির আরও বিবরণের জন্য , 1.10.2 এ নতুন বৈশিষ্ট্যগুলি দেখুন (এটি বর্তমানে সহায়তা পাঠ্যে বর্ণিত নয়)।

করার দায়িত্ব অর্পণ পরিবর্তনশীল (গুলি), এর LHS মোড়ানো :=বন্ধনীর মধ্যে:

DT[, (colname) := 4:6]    
#    col1
# 1:    4
# 2:    5
# 3:    6

পরেরটি একটি কলাম চূড়া হিসাবে পরিচিত , কারণ আপনি রেফারেন্স দ্বারা পুরো কলাম ভেক্টর প্রতিস্থাপন। যদি কোনও উপসেট iউপস্থিত থাকে, তবে এটি রেফারেন্স সহ সাবসাইন করবে। ডান বন্ধনী কাছাকাছি (colname)একটি সাঁটে লেখার Cran অক্টোবর সংস্করণটি v1.9.4 চালু হয় 2014. এখানে সংবাদ আইটেম :

ব্যবহার with = FALSEসঙ্গে :=এখন সব ক্ষেত্রে নিন্দা করা হয়েছে, দেওয়া যে LHS মোড়কে :=বন্ধনী সহ কিছু সময়ের জন্য পছন্দসই হয়েছে।

colVar = "col1"
DT[, (colVar) := 1]                             # please change to this
DT[, c("col1", "col2") := 1]                    # no change
DT[, 2:4 := 1]                                  # no change
DT[, c("col1","col2") := list(sum(a), mean(b))]  # no change
DT[, `:=`(...), by = ...]                       # no change

বিস্তারিত বিভাগেও দেখুন ?`:=`:

DT[i, (colnamevector) := value]
# [...] The parens are enough to stop the LHS being a symbol

এবং মন্তব্যে আরও প্রশ্নের উত্তর দেওয়ার জন্য, এখানে একটি উপায় (যথারীতি অনেকগুলি উপায় রয়েছে):

DT[, colname := cumsum(get(colname)), with = FALSE]
#    col1
# 1:    4
# 2:    9
# 3:   15 

বা, আপনি সহজে পড়তে পারে, লিখুন এবং শুধু ডিবাগ evalএকটি paste, একটি গতিশীল SQL বক্তব্য নির্মাণের একটি সার্ভারে পাঠাতে অনুরূপ:

expr = paste0("DT[,",colname,":=cumsum(",colname,")]")
expr
# [1] "DT[,col1:=cumsum(col1)]"

eval(parse(text=expr))
#    col1
# 1:    4
# 2:   13
# 3:   28

যদি আপনি এটি অনেক কিছু করেন তবে আপনি কোনও সহায়ক ফাংশন সংজ্ঞায়িত করতে পারেন EVAL:

EVAL = function(...)eval(parse(text=paste0(...)),envir=parent.frame(2))

EVAL("DT[,",colname,":=cumsum(",colname,")]")
#    col1
# 1:    4
# 2:   17
# 3:   45

এখন যে data.table1.8.2 স্বয়ংক্রিয়ভাবে jদক্ষতার জন্য অনুকূলিত হয়েছে, এটি evalপদ্ধতিটি ব্যবহার করা ভাল । get()মধ্যে j, কিছু অপ্টিমাইজেশন বাধা দেয় উদাহরণস্বরূপ।

বা, আছে set()। একটি নিম্ন ওভারহেড, এর কার্যকরী ফর্ম :=, যা এখানে ঠিক থাকবে। দেখুন ?set

set(DT, j = colname, value = cumsum(DT[[colname]]))
DT
#    col1
# 1:    4
# 2:   21
# 3:   66

4
উত্তর ম্যাথিউ জন্য ধন্যবাদ। এর সাথে = মিথ্যাটি অবশ্যই আমার সমস্যার অংশটি সমাধান করে। বাস্তবে যদিও, আমি কলামটির কসমস দিয়ে কলামটি প্রতিস্থাপন করতে চাই। আমি কি কোনওভাবে অ্যাসাইনমেন্টের ডান হাতের স্থানে ভেরিয়েবল দ্বারা কলামের নামটি উল্লেখ করতে পারি?
ফ্র্যাঙ্কসি

একিউটালি, আমি কেবল মাত্র একটি আলাদা নামের সাথে সিউসামকে বাইরে রেখেছিলাম যা ডিটিটির ভিতরে নেই এবং এটি সূক্ষ্মভাবে কাজ করে।
ফ্র্যাঙ্কসি

4
তবে তা পুরো অতিরিক্ত লাইন হবে! খুব মার্জিত নয় :) তবে ঠিক আছে কখনও কখনও এটি দরকারী। এই ক্ষেত্রে পরিবর্তনশীল নামটি দিয়ে শুরু করা ভাল ., বা ভবিষ্যতে কোনও কলামের নাম হিসাবে ..যদি DTএই প্রতীকটি থাকে তবে কোনও সম্ভাব্য মুখোশ এড়ানোর জন্য (এবং এই সম্মেলনে আটকে থাকুন যে কলামের নামগুলি শুরু হয় না .)। এটিকে স্কোপ ইস্যুগুলিতে আরও শক্তিশালী করার জন্য কয়েকটি বৈশিষ্ট্য অনুরোধ রয়েছে যেমন যুক্ত করা .()এবং ..()
ম্যাট ডাউলে

আপনি উত্তরটি সম্পাদনা করার আগে আমি জবাব দিয়েছি। আমার প্রথম চিন্তাটি স্পষ্ট ছিল (পার্স ()) তবে কোনও কারণে আমাকে এটি কাজ করতে পেতে সমস্যা হয়েছিল, যখন এটি আমার উপর ছড়িয়ে পড়ে কেবল এটি বাহ্যিকভাবে করার জন্য। আমি ভাবিনি এমন প্রচুর জিনিস সহ এটি একটি দুর্দান্ত উত্তর। সাধারণভাবে ডেটা টেবিলের জন্য ধন্যবাদ, এটি দুর্দান্ত প্যাকেজ।
খোলামেলা

4
নোট যে আপনি আপাতদৃষ্টিতে Perl টাইপ স্ট্রিং ক্ষেপক ব্যবহার করতে পারে fn$gsubfn প্যাকেজ থেকে Eval সমাধান পাঠযোগ্যতা উন্নতি করতে: library(gsubfn); fn$EVAL( "DT[,$colname:=cumsum($colname)]" )
জি। গ্রোথেন্ডিক

8

* এটি সত্যই কোনও উত্তর নয়, তবে আমার কাছে মন্তব্য পোস্ট করার মতো স্ট্রিট ক্রেডিট নেই: /

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

colname <- as.name("users")
# Google Analytics query is run with chosen metric and resulting data is assigned to DT
DT2 <- DT[, sum(eval(colname, .SD)), by = country]
setnames(DT2, "V1", as.character(colname))

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


কেবলমাত্র কাজ করার জন্য +1: আমি সম্মতি জানাই এটি অবশ্যই এটি করার "উপায়" হতে হবে না, তবে এই বিষয়ে প্রতিটি এসও পোস্টের উপরে 45ালতে কেবল 45 মিনিটের মতো সময় ব্যয় করা হলেও এটিই কেবলমাত্র সমাধান যা আমি আসলে পেতে সক্ষম হয়েছি কাজ - সময় এটি নির্দেশ করার জন্য ধন্যবাদ!
নিউরোপসাইক

আমি সাহায্য করতে পেরে আনন্দিত! দুর্ভাগ্যক্রমে, আমি সরাসরি ডেটা. টেবিলগুলি ব্যবহার করে এর চেয়ে বেশি মার্জিত সমাধান পাইনি, যদিও এই 3 লাইনারটি ভয়ঙ্কর নয়। আমার দৃশ্যে, আমি বুঝতে পেরেছিলাম যে সহজ বিকল্পটি আমার ডেটাগুলিকে "প্রশস্ত" পরিবর্তে "দীর্ঘ" করার জন্য পরিপাটি ব্যবহার করা উচিত ছিল, যেহেতু ব্যবহারকারীর ইনপুটের উপর ভিত্তি করে, আমি সবসময় একটি সেট থেকে নির্বাচন না করে একটি কলামে ফিল্টার করতে পারি কলামের।
efh0888

4
V1নতুন নামটি ধরে নেওয়া নিরাপদ নয় । উদাহরণস্বরূপ, আপনি যদি সিএসভি সহ পড়েন freadএবং কোনও নামহীন কলাম থাকে তবে এর V1নাম থাকবে (এবং read.csvদেবে X)। সুতরাং এটি আপনার টেবিল ইতিমধ্যে একটি থাকতে পারে V1। সম্ভবত স্রেফ নামটি পেয়ে যানnames(DT)[length(names(DT))]
dracodoc

2

একাধিক কলাম এবং কলাম মানগুলিতে প্রয়োগ একটি ফাংশন জন্য।

কোনও ফাংশন থেকে মানগুলি আপডেট করার সময়, আরএইচএস অবশ্যই একটি লিস্ট অবজেক্ট হতে হবে, সুতরাং এর .SDসাথে একটি লুপ ব্যবহার করা lapplyকৌশলটি করবে।

নীচের উদাহরণটি সংখ্যার কলামগুলিতে পূর্ণসংখ্যা কলামগুলিকে রূপান্তর করে

a1 <- data.table(a=1:5, b=6:10, c1=letters[1:5])
sapply(a1, class)  # show classes of columns
#         a           b          c1 
# "integer"   "integer" "character" 

# column name character vector
nm <- c("a", "b")

# Convert columns a and b to numeric type
a1[, j = (nm) := lapply(.SD, as.numeric ), .SDcols = nm ]

sapply(a1, class)
#         a           b          c1 
# "numeric"   "numeric" "character" 

2

ভেরিয়েবল বা ফাংশনের মাধ্যমে ডেটা থেকে একাধিক কলাম পুনরুদ্ধার করুন: টেবিল:

library(data.table)

x <- data.table(this=1:2,that=1:2,whatever=1:2)

# === explicit call
x[, .(that, whatever)]
x[, c('that', 'whatever')]

# === indirect via  variable
# ... direct assignment
mycols <- c('that','whatever')
# ... same as result of a function call
mycols <- grep('a', colnames(x), value=TRUE)

x[, ..mycols]
x[, .SD, .SDcols=mycols]

# === direct 1-liner usage
x[, .SD, .SDcols=c('that','whatever')]
x[, .SD, .SDcols=grep('a', colnames(x), value=TRUE)]

যা সব ফলন

   that whatever
1:    1        1
2:    2        2

আমি .SDcolsসবচেয়ে মার্জিত উপায় খুঁজে ।


1

আপনি এটি চেষ্টা করতে পারে

কলাম <- as.name ("COL_NAME")

ডিটি 2 <- ডিটি [, তালিকা (COL_SUM = যোগফল (ইওওয়াল (কল্পনা, .এসডি))), = গ (গ্রুপ)] দ্বারা


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