Links
Archives
บล็อกเพื่อแลกเปลี่ยนเรียนรู้ สำหรับนักพัฒนาฟังก์ชันสำหรับ R ในประเทศไทย
สนับสนุนโดย สำนักงานกองทุนสนับสนุนการวิจัย (สกว)
06 พฤษภาคม 2548
การนำชื่อ data frame และ variable มาใช้
พึงสังเกตว่าการนำชื่อวัตถุใดๆ มาใช้นั้น เราไม่สามารถเรียกได้จากฟังก์ชัน names เพราะชื่อวัตถุใดๆ ไม่ได้เป็น attribute ดังนั้นในการนำชื่อวัตถุออกมา จึงต้องใช้วิธีที่อ้อมเล็กน้อย โดยใช้ฟังก์ชัน substitute ซึ่งทำหน้าที่ค้นหาชื่อของวัตถุนั้นในเส้นทางค้นหาในสิ่งแวดล้อมขณะนั้น
1. การนำชื่อ data frame มาใช้ เมื่อส่งผ่าน data frame เป็น argument
เมื่อต้องการนำชื่อ data frame มาใช้ เช่นในกรณีที่ส่งผ่าน data เป็น argument ของฟังก์ชัน data.name เราสามารถใช้ฟังก์ชัน substitute เพื่อนำชื่อ data ออกมาได้ดังนี้
library(epican)
data(cca)
data.name <- function (data, ...)
{
data.name <- substitute(data)
cat(data.name,"\n")
}
data.name(cca)
เนื่องจากฟังก์ชัน substitute ทำหน้าที่ค้นหาชื่อของวัตถุนั้นในเส้นทางค้นหาในสิ่งแวดล้อมขณะนั้น ดังนั้นเมื่อออกคำสั่ง substitute(cca) จะได้ชื่อ cca กลับออกมาดังนี้
cca
นั่นคือเราสามารถใช้ฟังก์ชัน substitute เพื่อหาชื่อของวัตถุนั้นได้ ผลลัพธ์ที่ได้จากการเรียกฟังก์ชั่น data.name() จะเป็นดังนี้
cca
2. การนำชื่อ variable ใน data frame มาใช้ เมื่อส่งผ่าน data frame และชื่อ variable เป็น argument
ในกรณีที่ส่งผ่าน variable เป็น argument ในลักษณะที่เป็น vector เราสามารถนำชื่อ variable ใน data frame ออกมาได้ด้วยการใช้ฟังก์ชัน substitute เช่นกัน แต่ควรใช้ร่วมกับฟังก์ชัน deparse ด้วย ดังในตัวอย่างฟังก์ชัน var.name ดังนี้
var.name <- function (data, var)
{
data.name <- substitute(data)
var.name <- deparse(substitute(var))
cat(data.name,var.name,"\n")
}
var.name(cca,status)
ฟังก์ชัน deparse ทำหน้าที่จับข้อความที่ใส่ใน argument ออกมาเป็น string ข้อดีของการใช้ deparse ร่วมด้วยก็คือ หากมีการ subset variable นั้นด้วย ก็จะได้ข้อความที่ถูกต้องกลับมา มิฉะนั้นการใช้ substitute เฉยๆ จะได้ผลลัพธ์เป็นข้อความว่าง
ผลลัพธ์ที่ได้จากการเรียกฟังก์ชั่น data.name() จะเป็นดังนี้
cca status
อีกวิธีหนึ่งในการหาชื่อของ variable ใน data frame มาใช้ ในกรณีที่รู้ลำดับของ variable นั้นใน data frame คือการใช้ฟังก์ชัน names เนื่องจากในขณะนี้ variable อยู่ภายใน data frame จึงเป็น attribute หนึ่งใน data frame นั้น เราจึงใช้ฟังก์ชัน names เพื่อหาชื่อ variable ภายใน data frame ได้ดังนี้
var.name <- function (data, var.order)
{
data.name <- substitute(data)
var.name <- names(data)[var.order] #<--
cat(data.name,var.name,"\n")
}
var.name(cca,1)
var.name(cca,2)
ผลที่ได้เป็นดังนี้
cca status
> var.name(cca,2)
cca ovab
แต่สังเกตว่าในกรณีนี้เราต้องรู้ลำดับตัวแปรใน data frame จึงจะหาชื่อ variable ได้ เราสามารถรวมสองวิธีนี้เข้าเป็นฟังก์ชันเดียวกันได้ โดยการตรวจสอบว่า argument ลำดับที่สองที่ส่งเข้ามาเป็น vector หรือเป็นตัวเลขเดี่ยวๆ ซึ่งทำได้อย่างน้อยสองวิธี วิธีหนึ่งคือ ตรวจความยาว (length) ของ argument นั้น ถ้าความยาวเป็น 1 ก็ (คาดได้ว่า) เป็นตัวเลขลำดับ การตรวจสอบความยาวเช่นนี้จะผิดพลาดได้ถ้า data frame นั้นมี variable เพียงตัวเดียว แต่คงเป็นไปไม่ได้ที่จะมี data frame ที่มีตัวแปรเดียวเช่นนั้น ถ้าสร้าง data frame อย่างถูกต้องตามหลักการของฐานข้อมูลที่ดี คือจะต้องมี primary key เป็น identifier อยู่ด้วย ซึ่งจะทำให้ data frame ต้องมี variable อย่างน้อยสองตัวเสมอ การตรวจสอบอีกวิธีหนึ่งที่ไม่น่าจะเกิดความผิดพลาดไม่ว่ากรณีใดๆ คือใช้ฟังก์ชัน is.vector ซึ่งถึงแม้ variable นั้นจะเป็น factor ก็จะให้ผลเป็น TRUE เช่นกัน แต่ถ้าเป็นตัวเลขเดี่ยวๆ จะให้ผลเป็น FALSE ในที่นี้จะไม่แสดงให้ดู ลองทำเองเป็นการทดสอบความรู้ได้
3. การนำชื่อ data frame กับชื่อ variable มาต่อกันด้วย "$"
สามารถทำได้อย่างง่ายด้วยการใช้ฟังก์ชัน paste แล้วใช้ sep = "$" ดังตัวอย่างฟังก์ชัน var.name ในข้อ 2 สามารถเขียนใหม่ได้ดังนี้
var.name <- function (data, var)
{
data.name <- substitute(data)
var.name <- deparse(substitute(var))
data.and.var <- paste(data.name,var.name,sep="$")
cat(data.and.var,"\n")
}
ผลลัพธ์ที่ได้จากการเรียกฟังก์ชั่น var.name() จะเป็นดังนี้
cca$status
ลองส่งค่ากลับออกมาให้ var.name แล้วเรียกดู type และ class ของผลลัพธ์
var.name <- function (data, var)
{
data.name <- substitute(data)
var.name <- deparse(substitute(var))
data.and.var <- paste(data.name,var.name,sep="$")
cat(data.and.var,"\n")
return(var.name)
}
x <- var.name(cca,status)
typeof(x)
class(x)
จะได้ผลที่น่าพอใจดังนี้
cca$status
> typeof(x)
[1] "symbol"
> class(x)
[1] "name"
สังเกตว่าในขณะนี้เราใช้ฟังก์ชัน paste เพื่อนำผลลัพธ์มาเก็บไว้ในวัตถุหนึ่ง ค่า default ของตัวแยก string ของ paste เป็นช่องว่าง 1 ช่อง แต่ในที่นี้เราจะแทนที่ด้วย "$" ก็จะทำให้ชื่อทั้งสองต่อกันทันทีด้วยเครื่องหมาย $
เราอาจสั่งให้พิมพ์ชื่อออกมาบน console โดยตรงโดยใช้ cat เลยก็ได้ แต่ต้องระวังว่าด้วยค่า default ของ cat นั้น string จะถูกแยกด้วยช่องว่าง 1 ช่องเช่นกัน จึงต้องระบุ sep="" ดังนี้
var.name <- function (data, var)
{
data.name <- substitute(data)
var.name <- deparse(substitute(var))
cat(data.name,"$",var.name,"\n", sep="")
}
หรืออาจใช้ sep="$" ได้เช่นกัน ผลลัพธ์จะยังไม่ได้ดังที่ต้องการ คือมี "$" ติดมาตอนท้ายด้วยดังนี้
> var.name(cca,status)
cca$status$
ที่เป็นเช่นนี้เพราะ cat จะมองว่า "\n" เป็น string อีกอันหนึ่ง ที่ต้องคั่นด้วย "$" เช่นกัน จึงต้องแยก "\n" ออกมาต่างหาก ก็จะได้ผลอย่างที่ต้องการ ดังนี้
> var.name(cca,status)
cca$status
สนับสนุนโดย สำนักงานกองทุนสนับสนุนการวิจัย (สกว)
