R มีสองวิธีที่แตกต่างกันสำหรับการเข้าถึงองค์ประกอบของรายการหรือ data.frame ที่: และ[]
[[]]
อะไรคือความแตกต่างระหว่างสองสิ่งในสถานการณ์ที่ฉันควรใช้สถานการณ์หนึ่งกับอีกสถานการณ์หนึ่ง
R มีสองวิธีที่แตกต่างกันสำหรับการเข้าถึงองค์ประกอบของรายการหรือ data.frame ที่: และ[]
[[]]
อะไรคือความแตกต่างระหว่างสองสิ่งในสถานการณ์ที่ฉันควรใช้สถานการณ์หนึ่งกับอีกสถานการณ์หนึ่ง
คำตอบ:
นิยามภาษา R มีประโยชน์ในการตอบคำถามประเภทนี้:
R มีโอเปอเรเตอร์การทำดัชนีพื้นฐานสามรายการโดยมีไวยากรณ์ที่แสดงโดยตัวอย่างต่อไปนี้
x[i] x[i, j] x[[i]] x[[i, j]] x$a x$"a"
สำหรับเวกเตอร์และเมทริกซ์
[[
นั้นไม่ค่อยมีการใช้แบบฟอร์มแม้ว่าจะมีความแตกต่างทางความหมายเล็กน้อยจาก[
แบบฟอร์ม (เช่นมันลดชื่อหรือแอตทริบิวต์ชื่อติ่มซำและใช้การจับคู่บางส่วนสำหรับดัชนีตัวละคร) เมื่อจัดทำดัชนีโครงสร้างหลายมิติที่มีดัชนีเดียวx[[i]]
หรือx[i]
จะกลับองค์ประกอบตามลำดับวันของi
x
สำหรับรายการหนึ่งโดยทั่วไปใช้
[[
เพื่อเลือกองค์ประกอบเดียวใด ๆ ในขณะที่[
ส่งกลับรายการขององค์ประกอบที่เลือก
[[
รูปแบบช่วยให้เพียงองค์ประกอบเดียวที่จะเลือกใช้จำนวนเต็มหรือตัวอักษรดัชนีในขณะที่[
ช่วยให้การจัดทำดัชนีโดยเวกเตอร์ โปรดทราบว่าสำหรับรายการดัชนีสามารถเป็นเวกเตอร์และแต่ละองค์ประกอบของเวกเตอร์จะถูกนำไปใช้กับรายการส่วนประกอบที่เลือกองค์ประกอบที่เลือกของส่วนประกอบนั้นและอื่น ๆ ผลลัพธ์ยังคงเป็นองค์ประกอบเดียว
[
เสมอกลับรายการหมายความว่าคุณจะได้รับการส่งออกระดับเดียวกันโดยไม่คำนึงถึงความยาวของx[v]
v
ตัวอย่างเช่นหนึ่งอาจต้องการมากกว่าย่อยของรายการนี้:lapply
lapply(x[v], fun)
ถ้า[
จะดรอปลิสต์ของเวกเตอร์ที่มีความยาวหนึ่งนี่จะส่งคืนข้อผิดพลาดเมื่อใดก็ตามที่v
มีความยาวหนึ่งอัน
ความแตกต่างอย่างมีนัยสำคัญระหว่างสองวิธีคือคลาสของวัตถุที่ส่งคืนเมื่อใช้สำหรับการแยกและอาจยอมรับช่วงของค่าหรือเพียงค่าเดียวระหว่างการกำหนด
พิจารณากรณีของการดึงข้อมูลในรายการต่อไปนี้:
foo <- list( str='R', vec=c(1,2,3), bool=TRUE )
สมมติว่าเราต้องการดึงค่าที่จัดเก็บโดยบูลจาก foo และใช้มันในif()
คำสั่ง สิ่งนี้จะแสดงให้เห็นถึงความแตกต่างระหว่างค่าส่งคืนของ[]
และ[[]]
เมื่อใช้สำหรับการแยกข้อมูล []
วิธีการส่งกลับวัตถุของรายการระดับ (หรือ data.frame ถ้า foo เป็น data.frame) ในขณะที่[[]]
วัตถุวิธีการผลตอบแทนที่มีระดับจะถูกกำหนดโดยประเภทของค่าของพวกเขา
ดังนั้นการใช้[]
เมธอดจะส่งผลต่อไปนี้:
if( foo[ 'bool' ] ){ print("Hi!") }
Error in if (foo["bool"]) { : argument is not interpretable as logical
class( foo[ 'bool' ] )
[1] "list"
นี่เป็นเพราะ[]
วิธีการส่งคืนรายการและรายการนั้นเป็นวัตถุที่ไม่ถูกต้องในการส่งผ่านไปยังif()
คำสั่ง ในกรณีนี้เราต้องใช้[[]]
เพราะมันจะคืนค่าวัตถุ "เปล่า" ที่เก็บใน 'บูล' ซึ่งจะมีคลาสที่เหมาะสม:
if( foo[[ 'bool' ]] ){ print("Hi!") }
[1] "Hi!"
class( foo[[ 'bool' ]] )
[1] "logical"
ความแตกต่างที่สองคือการที่[]
ผู้ประกอบการอาจจะถูกใช้ในการเข้าถึงช่วงของช่องในรายการหรือคอลัมน์ในกรอบข้อมูลในขณะที่[[]]
ผู้ประกอบการจะถูก จำกัด การเข้าถึงเดียวสล็อตหรือคอลัมน์ พิจารณากรณีของการกำหนดค่าโดยใช้รายการที่สองbar()
:
bar <- list( mat=matrix(0,nrow=2,ncol=2), rand=rnorm(1) )
สมมติว่าเราต้องการเขียนทับ foo สองช่องสุดท้ายด้วยข้อมูลที่อยู่ในแถบ หากเราพยายามใช้[[]]
โอเปอเรเตอร์นี่คือสิ่งที่เกิดขึ้น:
foo[[ 2:3 ]] <- bar
Error in foo[[2:3]] <- bar :
more elements supplied than there are to replace
นี่เป็นเพราะ[[]]
ถูก จำกัด ให้เข้าถึงองค์ประกอบเดียว เราจำเป็นต้องใช้[]
:
foo[ 2:3 ] <- bar
print( foo )
$str
[1] "R"
$vec
[,1] [,2]
[1,] 0 0
[2,] 0 0
$bool
[1] -0.6291121
โปรดทราบว่าในขณะที่การมอบหมายนั้นสำเร็จสล็อตใน foo ยังคงชื่อเดิมไว้
วงเล็บคู่จะเข้าถึงองค์ประกอบรายการในขณะที่วงเล็บเดี่ยวจะให้รายการกลับพร้อมองค์ประกอบเดียว
lst <- list('one','two','three')
a <- lst[1]
class(a)
## returns "list"
a <- lst[[1]]
class(a)
## returns "character"
[]
แยกรายการ[[]]
แยกองค์ประกอบภายในรายการ
alist <- list(c("a", "b", "c"), c(1,2,3,4), c(8e6, 5.2e9, -9.3e7))
str(alist[[1]])
chr [1:3] "a" "b" "c"
str(alist[1])
List of 1
$ : chr [1:3] "a" "b" "c"
str(alist[[1]][1])
chr "a"
เพียงแค่เพิ่มที่นี่[[
ยังมีความพร้อมสำหรับการจัดทำดัชนี recursive
นี่เป็นคำใบ้ในคำตอบโดย @JijoMatthew แต่ไม่ได้สำรวจ
ตามที่ระบุไว้ใน?"[["
ไวยากรณ์เช่นx[[y]]
ที่ซึ่งlength(y) > 1
ถูกตีความว่า:
x[[ y[1] ]][[ y[2] ]][[ y[3] ]] ... [[ y[length(y)] ]]
ทราบว่านี้ไม่ได้เปลี่ยนสิ่งที่ควรจะ Takeaway หลักของคุณบนความแตกต่างระหว่าง[
และ[[
- คือว่าอดีตจะใช้สำหรับการSubsettingและหลังจะใช้สำหรับการแยกองค์ประกอบของรายการเดียว
ตัวอย่างเช่น,
x <- list(list(list(1), 2), list(list(list(3), 4), 5), 6)
x
# [[1]]
# [[1]][[1]]
# [[1]][[1]][[1]]
# [1] 1
#
# [[1]][[2]]
# [1] 2
#
# [[2]]
# [[2]][[1]]
# [[2]][[1]][[1]]
# [[2]][[1]][[1]][[1]]
# [1] 3
#
# [[2]][[1]][[2]]
# [1] 4
#
# [[2]][[2]]
# [1] 5
#
# [[3]]
# [1] 6
ในการรับค่า 3 เราสามารถทำ:
x[[c(2, 1, 1, 1)]]
# [1] 3
กลับไปที่คำตอบของ @jijoMatthew ด้านบนจำได้ว่าr
:
r <- list(1:10, foo=1, far=2)
โดยเฉพาะอย่างยิ่งสิ่งนี้จะอธิบายข้อผิดพลาดที่เรามักจะได้รับเมื่อใช้งานผิดพลาด[[
คือ:
r[[1:3]]
ข้อผิดพลาดใน
r[[1:3]]
: การทำดัชนีซ้ำซ้ำล้มเหลวที่ระดับ 2
เนื่องจากรหัสนี้พยายามที่จะประเมินผลจริงr[[1]][[2]][[3]]
และการซ้อนr
จุดหยุดที่ระดับหนึ่งความพยายามในการแยกผ่านการทำดัชนีแบบเรียกซ้ำล้มเหลวที่[[2]]
เช่นที่ระดับ 2
ข้อผิดพลาดใน
r[[c("foo", "far")]]
: ตัวห้อยไม่อยู่ในขอบเขต
ที่นี่ R กำลังมองหาr[["foo"]][["far"]]
ซึ่งไม่มีอยู่จริงดังนั้นเราจึงได้ข้อผิดพลาดจากตัวห้อย
อาจเป็นประโยชน์ / สอดคล้องกันมากกว่านี้หากข้อผิดพลาดทั้งสองข้อให้ข้อความเดียวกัน
ทั้งสองวิธีเป็นวิธีย่อย วงเล็บเดี่ยวจะส่งคืนชุดย่อยของรายการซึ่งในนั้นจะเป็นรายการ ie: มันอาจจะมีหรือไม่มีองค์ประกอบมากกว่าหนึ่งองค์ประกอบ ในทางกลับกันวงเล็บคู่จะส่งคืนเพียงองค์ประกอบเดียวจากรายการ
- วงเล็บเดียวจะให้รายการเรา นอกจากนี้เรายังสามารถใช้วงเล็บเดี่ยวได้หากต้องการคืนองค์ประกอบหลายรายการจากรายการ พิจารณารายการต่อไปนี้: -
>r<-list(c(1:10),foo=1,far=2);
ตอนนี้โปรดทราบวิธีการส่งคืนรายการเมื่อฉันพยายามที่จะแสดงมัน ฉันพิมพ์ r แล้วกด Enter
>r
#the result is:-
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
$foo
[1] 1
$far
[1] 2
ตอนนี้เราจะเห็นความมหัศจรรย์ของฉากยึดเดี่ยว: -
>r[c(1,2,3)]
#the above command will return a list with all three elements of the actual list r as below
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
$foo
[1] 1
$far
[1] 2
ซึ่งเหมือนกับเมื่อเราพยายามที่จะแสดงค่าของ r บนหน้าจอซึ่งหมายความว่าการใช้วงเล็บเดี่ยวได้ส่งคืนรายการที่ดัชนี 1 เรามีเวกเตอร์ 10 องค์ประกอบจากนั้นเรามีอีกสององค์ประกอบที่มีชื่อ foo และไกล นอกจากนี้เรายังอาจเลือกที่จะให้ดัชนีหรือชื่อองค์ประกอบเดียวเป็นอินพุตในวงเล็บเดี่ยว เช่น:
> r[1]
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
ในตัวอย่างนี้เราให้หนึ่งดัชนี "1" และในทางกลับกันได้รับรายการที่มีองค์ประกอบหนึ่ง (ซึ่งเป็นอาร์เรย์ของตัวเลข 10)
> r[2]
$foo
[1] 1
ในตัวอย่างข้างต้นเราให้หนึ่งดัชนี "2" และในทางกลับกันได้รับรายการที่มีองค์ประกอบหนึ่ง
> r["foo"];
$foo
[1] 1
ในตัวอย่างนี้เราผ่านชื่อขององค์ประกอบหนึ่งและในคืนรายการถูกส่งกลับด้วยองค์ประกอบหนึ่ง
คุณอาจส่งเวกเตอร์ชื่อองค์ประกอบเช่น: -
> x<-c("foo","far")
> r[x];
$foo
[1] 1
$far
[1] 2
ในตัวอย่างนี้เราผ่านเวกเตอร์ที่มีชื่อองค์ประกอบสองชื่อ "foo" และ "ไกล"
ในทางกลับกันเราได้รายการที่มีสององค์ประกอบ
ในวงเล็บเดี่ยวสั้น ๆ จะส่งคืนรายการอื่นที่มีจำนวนองค์ประกอบเท่ากับจำนวนองค์ประกอบหรือจำนวนดัชนีที่คุณส่งผ่านไปยังวงเล็บเหลี่ยมเดียวเสมอ
ในทางตรงกันข้ามวงเล็บคู่จะส่งคืนองค์ประกอบเดียวเท่านั้น ก่อนที่จะย้ายไปที่วงเล็บคู่ควรจดบันทึกไว้ด้วย
NOTE:THE MAJOR DIFFERENCE BETWEEN THE TWO IS THAT SINGLE BRACKET RETURNS YOU A LIST WITH AS MANY ELEMENTS AS YOU WISH WHILE A DOUBLE BRACKET WILL NEVER RETURN A LIST. RATHER A DOUBLE BRACKET WILL RETURN ONLY A SINGLE ELEMENT FROM THE LIST.
ฉันจะยกตัวอย่างสถานที่ โปรดจดคำที่เป็นตัวหนาและกลับมาที่คำศัพท์หลังจากคุณทำตามตัวอย่างด้านล่าง:
วงเล็บคู่จะคืนค่าจริงให้คุณที่ดัชนี (จะไม่ส่งคืนรายการ)
> r[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
>r[["foo"]]
[1] 1
สำหรับวงเล็บสองชั้นหากเราพยายามดูองค์ประกอบมากกว่าหนึ่งองค์ประกอบโดยการส่งเวกเตอร์มันจะส่งผลให้เกิดข้อผิดพลาดเพียงเพราะมันไม่ได้สร้างขึ้นเพื่อตอบสนองความต้องการนั้น แต่เพียงเพื่อส่งคืนองค์ประกอบเดียว
พิจารณาดังต่อไปนี้
> r[[c(1:3)]]
Error in r[[c(1:3)]] : recursive indexing failed at level 2
> r[[c(1,2,3)]]
Error in r[[c(1, 2, 3)]] : recursive indexing failed at level 2
> r[[c("foo","far")]]
Error in r[[c("foo", "far")]] : subscript out of bounds
เพื่อช่วยให้มือใหม่นำทางผ่านหมอกแบบแมนนวลมันจะมีประโยชน์ที่จะเห็น[[ ... ]]
สัญกรณ์เป็นฟังก์ชั่นการยุบ - กล่าวอีกนัยหนึ่งก็คือเมื่อคุณต้องการ 'รับข้อมูล' จากเวกเตอร์ชื่อรายการหรือกรอบข้อมูล เป็นการดีถ้าคุณต้องการใช้ข้อมูลจากวัตถุเหล่านี้เพื่อการคำนวณ ตัวอย่างง่ายๆเหล่านี้จะอธิบาย
(x <- c(x=1, y=2)); x[1]; x[[1]]
(x <- list(x=1, y=2, z=3)); x[1]; x[[1]]
(x <- data.frame(x=1, y=2, z=3)); x[1]; x[[1]]
ดังนั้นจากตัวอย่างที่สาม:
> 2 * x[1]
x
1 2
> 2 * x[[1]]
[1] 2
iris[[1]]
ส่งกลับเวกเตอร์ในขณะที่iris[1]
ผลตอบแทน data.frame
เป็นศัพท์, [[
ผู้ประกอบการแยกองค์ประกอบจากรายการในขณะที่[
ผู้ประกอบการใช้เวลาส่วนย่อยของรายการ
สำหรับกรณีการใช้อื่นที่เป็นรูปธรรมให้ใช้วงเล็บคู่เมื่อคุณต้องการเลือกกรอบข้อมูลที่สร้างขึ้นโดยsplit()
ฟังก์ชัน หากคุณไม่ทราบให้split()
จัดกลุ่มรายการ / กรอบข้อมูลเป็นชุดย่อยตามฟิลด์คีย์ มันมีประโยชน์ถ้าเมื่อคุณต้องการที่จะทำงานกับหลายกลุ่มพล็อตพวกเขา ฯลฯ
> class(data)
[1] "data.frame"
> dsplit<-split(data, data$id)
> class(dsplit)
[1] "list"
> class(dsplit['ID-1'])
[1] "list"
> class(dsplit[['ID-1']])
[1] "data.frame"
โปรดอ้างอิงคำอธิบายรายละเอียดด้านล่าง
ฉันใช้เฟรมข้อมูลในตัวใน R เรียกว่า mtcars
> mtcars
mpg cyl disp hp drat wt ...
Mazda RX4 21.0 6 160 110 3.90 2.62 ...
Mazda RX4 Wag 21.0 6 160 110 3.90 2.88 ...
Datsun 710 22.8 4 108 93 3.85 2.32 ...
............
บรรทัดบนสุดของตารางเรียกว่าส่วนหัวซึ่งมีชื่อคอลัมน์ แต่ละบรรทัดในแนวนอนหลังจากนั้นแสดงแถวข้อมูลซึ่งเริ่มต้นด้วยชื่อของแถวจากนั้นตามด้วยข้อมูลจริง สมาชิกข้อมูลแต่ละแถวเรียกว่าเซลล์
ในการดึงข้อมูลในเซลล์เราจะป้อนพิกัดของแถวและคอลัมน์ในเครื่องหมายวงเล็บเหลี่ยม "[]" พิกัดทั้งสองจะคั่นด้วยเครื่องหมายจุลภาค กล่าวอีกนัยหนึ่งพิกัดเริ่มต้นด้วยตำแหน่งแถวจากนั้นตามด้วยเครื่องหมายจุลภาคและลงท้ายด้วยตำแหน่งคอลัมน์ คำสั่งซื้อเป็นสิ่งสำคัญ
เช่น 1: - นี่คือค่าของเซลล์จากแถวแรกคอลัมน์ที่สองของ mtcars
> mtcars[1, 2]
[1] 6
เช่น 2: - นอกจากนี้เราสามารถใช้ชื่อแถวและคอลัมน์แทนพิกัดตัวเลข
> mtcars["Mazda RX4", "cyl"]
[1] 6
เราอ้างอิงคอลัมน์เฟรมข้อมูลด้วยเครื่องหมายวงเล็บคู่ "[[]]"
เช่น 1: - เพื่อดึงเวกเตอร์คอลัมน์ที่เก้าของ mtcars ชุดข้อมูลในตัวเราเขียน mtcars [[9]]
mtcars [[9]] [1] 1 1 1 0 0 0 0 0 0 0 0 0 ...
เช่น 2: - เราสามารถดึงเวกเตอร์คอลัมน์เดียวกันด้วยชื่อ
mtcars [["am"]] [1] 1 1 1 0 0 0 0 0 0 0 0 0 ...
นอกจากนี้:
นี่เป็นตัวอย่างเล็กน้อยที่กล่าวถึงประเด็นต่อไปนี้:
x[i, j] vs x[[i, j]]
df1 <- data.frame(a = 1:3)
df1$b <- list(4:5, 6:7, 8:9)
df1[[1,2]]
df1[1,2]
str(df1[[1,2]])
str(df1[1,2])