วิธีการใช้รายการใน R อย่างถูกต้อง?


320

พื้นหลังโดยย่อ: ภาษาการเขียนโปรแกรมร่วมสมัยส่วนใหญ่ (มากที่สุด) ที่ใช้กันอย่างแพร่หลายมีอย่างน้อยหนึ่ง ADTs [ประเภทข้อมูลนามธรรม] โดยทั่วไปโดยเฉพาะ

  • สตริง (ลำดับประกอบด้วยอักขระ)

  • รายการ (ชุดของค่าสั่ง) และ

  • ชนิดที่ยึดตามแผนที่ (อาร์เรย์ที่ไม่ได้เรียงลำดับที่จับคู่คีย์กับค่า)

ในภาษาการเขียนโปรแกรม R ทั้งสองจะถูกนำมาใช้เป็นcharacterและvectorตามลำดับ

เมื่อฉันเริ่มเรียนรู้ R มีสองสิ่งที่เห็นได้ชัดเจนตั้งแต่เริ่มต้น: listเป็นประเภทข้อมูลที่สำคัญที่สุดใน R (เพราะเป็นคลาสผู้ปกครองสำหรับ R data.frame) และที่สองฉันไม่เข้าใจวิธีการทำงานอย่างน้อย ไม่ดีพอที่จะใช้อย่างถูกต้องในรหัสของฉัน

สำหรับสิ่งหนึ่งที่ดูเหมือนว่าlistประเภทข้อมูลของ R คือการใช้แผนที่ ADT ( dictionaryใน Python, NSMutableDictionaryObjective C, hashPerl และ Ruby, object literalJavascript และอื่น ๆ )

ตัวอย่างเช่นคุณสร้างพวกเขาเช่นเดียวกับที่คุณทำกับพจนานุกรม Python โดยส่งผ่านคู่ของคีย์ - ค่าไปยังตัวสร้าง (ซึ่งใน Python dictไม่ใช่list):

x = list("ev1"=10, "ev2"=15, "rv"="Group 1")

และคุณเข้าถึงรายการของ R x['ev1']รายการเช่นเดียวกับที่คุณต้องการผู้ที่มีพจนานุกรมหลามเช่น ในทำนองเดียวกันคุณสามารถเรียกคืนเพียง'กุญแจ'หรือเพียงแค่'ค่า'โดย:

names(x)    # fetch just the 'keys' of an R list
# [1] "ev1" "ev2" "rv"

unlist(x)   # fetch just the 'values' of an R list
#   ev1       ev2        rv 
#  "10"      "15" "Group 1" 

x = list("a"=6, "b"=9, "c"=3)  

sum(unlist(x))
# [1] 18

แต่ R lists ก็ไม่เหมือนกับ ADT ประเภทแผนที่อื่น ๆ (จากภาษาที่ฉันได้เรียนรู้อยู่แล้ว) ฉันเดาว่านี่เป็นผลมาจากสเป็คเริ่มต้นสำหรับ S คือความตั้งใจในการออกแบบข้อมูล / สถิติ DSL [ภาษาเฉพาะโดเมน] จากพื้นฐาน

สามความแตกต่างที่สำคัญระหว่าง R lists และประเภทการแมปในภาษาอื่น ๆ ที่ใช้กันอย่างแพร่หลาย (เช่น Python, Perl, JavaScript):

ครั้งแรก , lists ใน R เป็นสั่งซื้อคอลเลกชันเช่นเดียวกับเวกเตอร์แม้ว่าค่าที่มีความสำคัญ (เช่นปุ่มจะถูกจำนวนเต็มค่า hashable ใด ๆ ที่ไม่ได้เป็นเพียงตามลำดับ) เกือบทุกชนิดข้อมูลแผนที่ในภาษาอื่น ๆเรียงลำดับ

สอง , lists สามารถกลับมาจากการทำงานแม้ว่าคุณจะไม่เคยผ่านในlistเมื่อคุณเรียกว่าฟังก์ชั่นและแม้ฟังก์ชั่นที่กลับมาlistไม่ได้มี (อย่างชัดเจน) listคอนสตรัค (แน่นอนคุณสามารถจัดการกับเรื่องนี้ในทางปฏิบัติโดย การตัดผลลัพธ์ที่ส่งคืนในการเรียกไปที่unlist):

x = strsplit(LETTERS[1:10], "")     # passing in an object of type 'character'

class(x)                            # returns 'list', not a vector of length 2
# [1] list

สามคุณลักษณะเฉพาะของอาร์เอสlistS: มันไม่ได้ดูเหมือนว่าพวกเขาสามารถเป็นสมาชิกของ ADT listอีกและถ้าคุณพยายามที่จะทำแล้วภาชนะหลักคือบังคับให้ไป เช่น,

x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=TRUE)

class(x)
# [1] list

ความตั้งใจของฉันที่นี่ไม่ได้เป็นการวิพากษ์วิจารณ์ภาษาหรือวิธีการจัดทำเอกสาร; ฉันไม่แนะนำให้มีสิ่งผิดปกติกับlistโครงสร้างข้อมูลหรือลักษณะการทำงาน สิ่งที่ฉันต้องทำก็คือเข้าใจว่ามันทำงานอย่างไรเพื่อที่ฉันจะได้ใช้มันอย่างถูกต้องในโค้ดของฉัน

นี่คือสิ่งต่าง ๆ ที่ฉันต้องการทำความเข้าใจ:

  • อะไรคือกฎที่กำหนดว่าเมื่อใดที่การเรียกใช้ฟังก์ชันจะส่งคืน a list(เช่นstrsplitนิพจน์ที่อ่านด้านบน)?

  • หากฉันไม่ได้กำหนดชื่ออย่างชัดเจนให้กับlist(เช่น, list(10,20,30,40)) ชื่อเริ่มต้นเป็นจำนวนเต็มตามลำดับที่ขึ้นต้นด้วย 1 หรือไม่ (ฉันถือว่า แต่ฉันยังไม่แน่ใจว่าคำตอบคือใช่ไม่เช่นนั้นเราจะไม่สามารถบังคับให้listเวกเตอร์ประเภทนี้มีการเรียกunlistได้)

  • เหตุใดผู้ประกอบการสองรายนี้จึงต่างกัน[]และ[[]]ส่งคืนผลลัพธ์เดียวกัน

    x = list(1, 2, 3, 4)

    ทั้งสองนิพจน์คืนค่า "1":

    x[1]

    x[[1]]

  • เหตุใดนิพจน์ทั้งสองนี้จึงไม่ส่งคืนผลลัพธ์เดียวกัน

    x = list(1, 2, 3, 4)

    x2 = list(1:4)

โปรดอย่านำฉันไปที่เอกสารประกอบ R ( ?list, R-intro) - ฉันได้อ่านอย่างละเอียดและไม่ได้ช่วยตอบคำถามประเภทที่ฉันอ่านข้างต้น

(ในที่สุดฉันเพิ่งเรียนรู้และเริ่มใช้แพ็คเกจ R (มีให้บริการบน CRAN) hashซึ่งเรียกว่าใช้พฤติกรรมการพิมพ์แผนที่ทั่วไปผ่านคลาส S4 ฉันสามารถแนะนำแพ็คเกจนี้ได้อย่างแน่นอน)


3
กับx = list(1, 2, 3, 4)ทั้งสองเหล่านี้ไม่ได้ส่งกลับผลเดียวกัน: และx[1] x[[1]]รายการแรกส่งคืนรายการและรายการที่สองส่งคืนค่าเวกเตอร์เป็นตัวเลข เมื่อเลื่อนด้านล่างฉันเห็นว่าเดิร์คเป็นผู้ตอบเพียงคนเดียวที่ตอบคำถามนี้อย่างถูกต้อง
IRTFM

2
ฉันไม่ได้สังเกตเห็นว่ามีใครเพิ่มขึ้นในรายการของคุณlistใน R ที่ไม่เหมือนแฮช ฉันมีอีกหนึ่งที่ฉันคิดว่าควรค่าแก่การบันทึก listใน R สามารถมีสมาชิกสองคนที่มีชื่ออ้างอิงเดียวกัน พิจารณาว่าobj <- c(list(a=1),list(a=2))ถูกต้องและส่งคืนรายการที่มีค่าสองชื่อคือ 'a' ในกรณีนี้การเรียกobj["a"]จะส่งกลับเฉพาะองค์ประกอบรายการแรกที่ตรงกัน คุณสามารถทำให้พฤติกรรมคล้ายกัน (อาจเหมือนกัน) กับแฮชที่มีเพียงหนึ่งไอเท็มต่อชื่อที่อ้างอิงโดยใช้สภาพแวดล้อมในอาร์เช่นx <- new.env(); x[["a"]] <- 1; x[["a"]] <- 2; x[["a"]]
russellpierce

1
ฉันได้อ่านโพสต์นี้อีกครั้งพร้อมคำตอบสามครั้งในช่วง 6 เดือนที่ผ่านมาและพบการตรัสรู้มากขึ้นในแต่ละครั้ง คำถามที่ดีและคำตอบที่ดี ขอบคุณ.
Rich Lysakowski ระดับปริญญาเอก

คำตอบ:


150

เพียงเพื่อตอบคำถามสุดท้ายของคุณเนื่องจากสิ่งนั้นชี้ให้เห็นความแตกต่างระหว่าง a listและvectorR:

เหตุใดนิพจน์ทั้งสองนี้จึงไม่ส่งคืนผลลัพธ์เดียวกัน

x = รายการ (1, 2, 3, 4); x2 = รายการ (1: 4)

รายการสามารถมีคลาสอื่น ๆ ตามแต่ละองค์ประกอบ ดังนั้นคุณสามารถมีรายการที่องค์ประกอบแรกเป็นเวกเตอร์ตัวละครที่สองคือกรอบข้อมูล ฯลฯ ในกรณีนี้คุณได้สร้างรายการที่แตกต่างกันสองรายการ xมีสี่เวกเตอร์แต่ละความยาว 1 x2มี 1 เวกเตอร์ของความยาว 4:

> length(x[[1]])
[1] 1
> length(x2[[1]])
[1] 4

ดังนั้นนี่คือรายการที่แตกต่างอย่างสิ้นเชิง

รายการ R นั้นมีลักษณะคล้ายกับโครงสร้างข้อมูลแฮชมากซึ่งแต่ละค่าดัชนีสามารถเชื่อมโยงกับวัตถุใด ๆ ได้ นี่คือตัวอย่างง่ายๆของรายการที่มี 3 คลาสที่แตกต่างกัน (รวมถึงฟังก์ชั่น):

> complicated.list <- list("a"=1:4, "b"=1:3, "c"=matrix(1:4, nrow=2), "d"=search)
> lapply(complicated.list, class)
$a
[1] "integer"
$b
[1] "integer"
$c
[1] "matrix"
$d
[1] "function"

ระบุว่าองค์ประกอบสุดท้ายคือฟังก์ชั่นการค้นหาฉันสามารถเรียกมันว่า:

> complicated.list[["d"]]()
[1] ".GlobalEnv" ...

ในฐานะที่เป็นความเห็นสุดท้ายเกี่ยวกับเรื่องนี้: มันควรจะสังเกตว่า a data.frameเป็นรายการจริงๆ (จากdata.frameเอกสารประกอบ):

กรอบข้อมูลคือรายการของตัวแปรของจำนวนแถวเดียวกันที่มีชื่อแถวที่ไม่ซ้ำกันซึ่งได้รับคลาส '"data.frame"'

นั่นเป็นสาเหตุที่คอลัมน์ใน a data.frameสามารถมีชนิดข้อมูลที่แตกต่างกันในขณะที่คอลัมน์ในเมทริกซ์ไม่สามารถทำได้ ตัวอย่างเช่นที่นี่ฉันพยายามสร้างเมทริกซ์ที่มีตัวเลขและตัวอักษร:

> a <- 1:4
> class(a)
[1] "integer"
> b <- c("a","b","c","d")
> d <- cbind(a, b)
> d
 a   b  
[1,] "1" "a"
[2,] "2" "b"
[3,] "3" "c"
[4,] "4" "d"
> class(d[,1])
[1] "character"

สังเกตว่าฉันไม่สามารถเปลี่ยนชนิดข้อมูลในคอลัมน์แรกเป็นตัวเลขได้เนื่องจากคอลัมน์ที่สองมีอักขระ:

> d[,1] <- as.numeric(d[,1])
> class(d[,1])
[1] "character"

4
สิ่งนี้ช่วยได้ขอบคุณ (โดยวิธีตัวอย่างของคุณ 'รายการที่ซับซ้อน' ดังที่คุณอาจทราบแล้วว่าเป็นวิธีมาตรฐานในการทำซ้ำคำสั่ง 'switch' ใน C ++, Java และอื่น ๆ ในภาษาที่ไม่มีอยู่อาจเป็นวิธีที่ดี ทำเช่นนี้ใน R เมื่อฉันต้องการ) 1
ดั๊ก

8
ถูกต้องแม้ว่าจะมีswitchฟังก์ชั่นที่มีประโยชน์ใน R ที่สามารถใช้เพื่อวัตถุประสงค์นั้นได้ (ดูhelp(switch))
เชน

63

เกี่ยวกับคำถามของคุณให้ฉันพูดตามลำดับและยกตัวอย่าง:

1 ) รายการจะถูกส่งคืนถ้าและเมื่อคำสั่งส่งคืนเพิ่มหนึ่งรายการ พิจารณา

 R> retList <- function() return(list(1,2,3,4)); class(retList())
 [1] "list"
 R> notList <- function() return(c(1,2,3,4)); class(notList())
 [1] "numeric"
 R> 

2 ) ชื่อไม่ได้ถูกตั้งค่า:

R> retList <- function() return(list(1,2,3,4)); names(retList())
NULL
R> 

3 ) พวกเขาไม่ส่งคืนสิ่งเดียวกัน ตัวอย่างของคุณให้

R> x <- list(1,2,3,4)
R> x[1]
[[1]]
[1] 1
R> x[[1]]
[1] 1

ที่x[1]ส่งกลับองค์ประกอบแรกของx- xซึ่งเป็นเช่นเดียวกับ สเกลาร์ทุกตัวเป็นเวกเตอร์ที่มีความยาวหนึ่งอัน ในทางx[[1]]กลับกันองค์ประกอบแรกของรายการ

4 ) สุดท้ายทั้งสองจะแตกต่างกันระหว่างที่พวกเขาสร้างตามลำดับรายการที่มีสี่เซนต์คิตส์และรายการที่มีองค์ประกอบเดียว (ที่เกิดขึ้นเป็นเวกเตอร์ของสี่องค์ประกอบ)


1
มีประโยชน์มากขอบคุณ (Re รายการ # 1 ในคำตอบของคุณ - ฉันเห็นด้วย แต่สิ่งที่ฉันมีอยู่ในใจคือบิวด์อินเช่น 'strsplit' ไม่ใช่ฟังก์ชั่นที่ผู้ใช้สร้างขึ้น) ไม่ว่าในกรณีใด +1 จากฉัน
ดั๊ก

2
@doug เกี่ยวกับรายการที่ 1 Valueผมคิดว่าวิธีเดียวคือการตรวจสอบความช่วยเหลือสำหรับการทำงานเฉพาะส่วน กด?strsplitไลค์ใน: "รายการที่มีความยาวเท่ากันกับ x" แต่คุณควรพิจารณาว่าอาจมีฟังก์ชั่นคืนค่าที่แตกต่างกันขึ้นอยู่กับข้อโต้แย้ง
Marek

34

เพียงใช้คำถามชุดย่อยของคุณ:

บทความนี้เกี่ยวกับการจัดทำดัชนีที่อยู่ในคำถามของความแตกต่างระหว่างและ[][[]]

ในระยะสั้น [[]] เลือกรายการเดียวจากรายการและ[]ส่งกลับรายการของรายการที่เลือก ในตัวอย่างของคุณx = list(1, 2, 3, 4)'รายการ 1 เป็นจำนวนเต็มเดียว แต่x[[1]]ส่งคืน 1 เดียวและx[1]ส่งคืนรายการที่มีค่าเดียวเท่านั้น

> x = list(1, 2, 3, 4)
> x[1]
[[1]]
[1] 1

> x[[1]]
[1] 1

โดยวิธีการA = array( 11:16, c(2,3) ); A[5]คือ 15 ในอาร์เรย์แบนหรือไม่!
เดนิส

13

เหตุผลหนึ่งที่แสดงรายการทำงานตามที่ทำ (สั่งซื้อ) คือการระบุถึงความจำเป็นในการสั่งซื้อคอนเทนเนอร์ที่สามารถมีประเภทใดก็ได้ที่โหนดใด ๆ ซึ่งเวกเตอร์ไม่ได้ทำ รายการถูกนำมาใช้ใหม่เพื่อวัตถุประสงค์ที่หลากหลายใน R รวมถึงการสร้างฐานของ a data.frameซึ่งเป็นรายการของเวกเตอร์ประเภทใดก็ได้ (แต่ความยาวเท่ากัน)

เหตุใดนิพจน์ทั้งสองนี้จึงไม่ส่งคืนผลลัพธ์เดียวกัน

x = list(1, 2, 3, 4); x2 = list(1:4)

หากต้องการเพิ่มคำตอบของ @ Shane หากคุณต้องการผลลัพธ์แบบเดียวกันลอง:

x3 = as.list(1:4)

ซึ่งรวมเวกเตอร์1:4ลงในรายการ


11

เพียงเพิ่มจุดอีกหนึ่งจุดนี้:

R จะมีเทียบเท่าโครงสร้างข้อมูลไปยัง Dict หลามในแพคเกจ คุณสามารถอ่านเกี่ยวกับเรื่องนี้ในบล็อกโพสต์นี้จากการเปิดข้อมูลกลุ่ม นี่คือตัวอย่างง่ายๆ:hash

> library(hash)
> h <- hash( keys=c('foo','bar','baz'), values=1:3 )
> h[c('foo','bar')]
<hash> containing 2 key-value pairs.
  bar : 2
  foo : 1

ในแง่ของการใช้งานhashคลาสจะคล้ายกับรายการ แต่ประสิทธิภาพจะดีกว่าสำหรับชุดข้อมูลขนาดใหญ่


1
ฉันทราบแพ็คเกจแฮช - มันถูกกล่าวถึงในคำถามเดิมของฉันว่าเป็นพร็อกซีที่เหมาะสมสำหรับประเภทแฮชแบบดั้งเดิม
doug

นอกจากนี้ยังทราบว่าการใช้กัญชากัญชา :: เป็นยูทิลิตี้ที่น่าสงสัยเมื่อเทียบกับสภาพแวดล้อมที่แฮชrpubs.com/rpierce/hashBenchmarks
russellpierce

9

คุณพูด:

สำหรับอีกรายการหนึ่งสามารถส่งคืนจากฟังก์ชันได้แม้ว่าคุณจะไม่เคยส่งผ่านในรายการเมื่อคุณเรียกใช้ฟังก์ชันและแม้ว่าฟังก์ชันนั้นจะไม่มีตัวสร้างรายการเช่น

x = strsplit(LETTERS[1:10], "") # passing in an object of type 'character'
class(x)
# => 'list'

และฉันคิดว่าคุณแนะนำว่านี่เป็นปัญหา (?) ฉันมาที่นี่เพื่อบอกคุณว่าทำไมมันไม่เป็นปัญหา :-) ตัวอย่างของคุณค่อนข้างเรียบง่ายเมื่อคุณทำการแยกสตริงคุณจะมีรายการที่มีองค์ประกอบที่มีความยาว 1 องค์ประกอบดังนั้นคุณจึงรู้ว่าx[[1]]เป็นเช่นunlist(x)[1]นั้น แต่จะเกิดอะไรขึ้นถ้าผลลัพธ์ของstrsplitผลลัพธ์ที่ส่งคืนมีความยาวต่างกันในแต่ละถัง เพียงแค่คืนค่าเวกเตอร์ (เทียบกับรายการ) จะไม่ทำเลย

ตัวอย่างเช่น

stuff <- c("You, me, and dupree",  "You me, and dupree",
           "He ran away, but not very far, and not very fast")
x <- strsplit(stuff, ",")
xx <- unlist(strsplit(stuff, ","))

ในกรณีแรก ( x: ซึ่งจะส่งกลับรายการ) คุณสามารถบอกได้ว่าครั้งที่ 2 "ส่วนหนึ่ง" ของสตริงที่ 3 x[[3]][2]เป็นเช่น: คุณสามารถทำสิ่งเดียวกันโดยใช้xxตอนนี้ผลลัพธ์ที่ได้รับ "unraveled" ( unlist-ed)?


5
x = list(1, 2, 3, 4)
x2 = list(1:4)
all.equal(x,x2)

ไม่เหมือนกันเพราะ 1: 4 เหมือนกับ c (1,2,3,4) หากคุณต้องการให้พวกเขาเหมือนกัน:

x = list(c(1,2,3,4))
x2 = list(1:4)
all.equal(x,x2)

4

นี่เป็นคำถามที่เก่ามาก แต่ฉันคิดว่าคำตอบใหม่อาจเพิ่มคุณค่าบางอย่างเนื่องจากในความคิดของฉันไม่มีใครตอบข้อกังวลบางอย่างใน OP โดยตรง

แม้จะมีสิ่งที่คำตอบที่ได้รับการยอมรับแนะนำlistวัตถุใน R ไม่ใช่แผนที่แฮ ถ้าคุณต้องการสร้างคู่ขนานกับไพ ธlistอนคุณก็เดาได้ว่าไพ ธ อนlist(หรือtupleจริง ๆ )

เป็นการดีกว่าที่จะอธิบายว่าวัตถุ R ส่วนใหญ่ถูกจัดเก็บภายใน (ประเภท C ของวัตถุ R คืออะไรSEXP) พวกเขาทำโดยพื้นฐานสามส่วน:

  • ส่วนหัวซึ่งประกาศชนิด R ของวัตถุความยาวและข้อมูลเมตาอื่น ๆ
  • ส่วนข้อมูลซึ่งเป็นอาร์เรย์ C ที่จัดสรรฮีปมาตรฐาน (บล็อกหน่วยความจำต่อเนื่อง);
  • แอ็ตทริบิวต์ซึ่งเป็นรายการที่เชื่อมโยงชื่อของตัวชี้ไปยังวัตถุ R อื่น ๆ (หรือNULLถ้าวัตถุไม่มีแอตทริบิวต์)

จากมุมมองภายในมีความแตกต่างเล็กน้อยระหว่าง a listและnumericเวกเตอร์ ค่าที่เก็บไว้นั้นแตกต่างกัน ลองแบ่งสองวัตถุเป็นกระบวนทัศน์ที่เราอธิบายไว้ก่อนหน้านี้:

x <- runif(10)
y <- list(runif(10), runif(3))

สำหรับx:

  • ส่วนหัวจะบอกว่าเป็นประเภทnumeric( REALSXPในด้าน C) ความยาวคือ 10 และสิ่งอื่น ๆ
  • ส่วนข้อมูลจะเป็นอาร์เรย์ที่มี 10 doubleค่า
  • มีคุณสมบัติNULLเนื่องจากวัตถุไม่มี

สำหรับy:

  • ส่วนหัวจะบอกว่าเป็นประเภทlist( VECSXPในด้าน C) ความยาวคือ 2 และสิ่งอื่น ๆ
  • ส่วนข้อมูลจะเป็นอาร์เรย์ที่มี 2 พอยน์เตอร์เป็น SEXP สองประเภทโดยชี้ไปที่ค่าที่ได้รับจากrunif(10)และrunif(3)ตามลำดับ
  • คุณลักษณะที่มีความเป็นสำหรับNULLx

ดังนั้นความแตกต่างเพียงอย่างเดียวระหว่างnumericเวกเตอร์และ a listคือnumericส่วนข้อมูลทำจากdoubleค่าในขณะlistที่ส่วนข้อมูลคืออาร์เรย์ของพอยน์เตอร์ไปยังวัตถุ R อื่น ๆ

เกิดอะไรขึ้นกับชื่อ ชื่อเป็นเพียงคุณสมบัติบางอย่างที่คุณสามารถกำหนดให้กับวัตถุได้ ลองดูวัตถุด้านล่าง:

z <- list(a=1:3, b=LETTERS)
  • ส่วนหัวจะบอกว่าเป็นประเภทlist( VECSXPในด้าน C) ความยาวคือ 2 และสิ่งอื่น ๆ
  • ส่วนข้อมูลจะเป็นอาร์เรย์ที่มี 2 พอยน์เตอร์เป็น SEXP สองประเภทโดยชี้ไปที่ค่าที่ได้รับจาก1:3และLETTERSตามลำดับ
  • แอตทริบิวต์อยู่ในขณะนี้ในปัจจุบันและเป็นnamesส่วนประกอบซึ่งเป็นวัตถุที่มีค่าcharacter Rc("a","b")

จากระดับ R คุณสามารถดึงคุณสมบัติของวัตถุด้วยattributesฟังก์ชั่น

คีย์ - ค่าทั่วไปของแฮชแม็พใน R เป็นเพียงภาพลวงตา เมื่อคุณพูดว่า:

z[["a"]]

นี่คือสิ่งที่เกิดขึ้น:

  • [[ฟังก์ชั่นชุดย่อยที่เรียกว่า;
  • ข้อโต้แย้งของฟังก์ชั่น ( "a") เป็นประเภทcharacterดังนั้นวิธีการได้รับคำสั่งให้ค้นหาค่าดังกล่าวจากnamesคุณลักษณะ (ถ้ามี) ของวัตถุz;
  • หากไม่มีnamesแอตทริบิวต์ก็NULLจะถูกส่งคืน
  • หากมีอยู่"a"ค่าจะถูกค้นหาในนั้น หาก"a"ไม่ใช่ชื่อของวัตถุNULLจะถูกส่งคืน
  • ถ้ามีอยู่ตำแหน่งจะถูกกำหนด (1 ในตัวอย่าง) z[[1]]ดังนั้นองค์ประกอบแรกของรายการจะถูกส่งกลับคือเทียบเท่า

การค้นหาคีย์ - ค่าค่อนข้างทางอ้อมและเป็นตำแหน่งเสมอ นอกจากนี้ควรคำนึงถึง:

  • ในกัญชาแผนที่เท่านั้น จำกัด ที่สำคัญจะต้องมีก็คือว่ามันจะต้องเป็นhashable namesใน R จะต้องเป็นสตริง ( characterเวกเตอร์);
  • ในแผนที่แฮชคุณไม่สามารถมีคีย์เหมือนกันสองปุ่ม ใน R คุณสามารถกำหนดให้namesกับวัตถุด้วยค่าซ้ำ ตัวอย่างเช่น

    names(y) <- c("same", "same")

    ถูกต้องสมบูรณ์ใน R เมื่อคุณลองy[["same"]]เรียกคืนค่าแรก คุณควรรู้ว่าทำไมถึงมาถึงจุดนี้

โดยสรุปความสามารถในการให้คุณสมบัติตามอำเภอใจกับวัตถุนั้นทำให้คุณมีลักษณะที่แตกต่างจากมุมมองภายนอก แต่อาร์listเอสไม่ได้แฮชแผนที่ในทางใดทางหนึ่ง


2

เกี่ยวกับพาหะและแนวคิดแฮช / อาเรย์จากภาษาอื่น:

  1. เวกเตอร์คืออะตอมของอาร์อีกรัมrpois(1e4,5)(5 ตัวเลขสุ่ม), numeric(55)(ความยาว 55- ศูนย์เวกเตอร์มากกว่าคู่) และcharacter(12)(12 สตริงว่าง) ทั้งหมดเป็น "พื้นฐาน"

  2. namesอย่างใดอย่างหนึ่งรายการหรือพาหะสามารถมี

    > n = numeric(10)
    > n
     [1] 0 0 0 0 0 0 0 0 0 0
    > names(n)
    NULL
    > names(n) = LETTERS[1:10]
    > n
    A B C D E F G H I J 
    0 0 0 0 0 0 0 0 0 0
  3. เวกเตอร์ต้องการให้ทุกอย่างเป็นชนิดข้อมูลเดียวกัน ดูนี้:

    > i = integer(5)
    > v = c(n,i)
    > v
    A B C D E F G H I J           
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    > class(v)
    [1] "numeric"
    > i = complex(5)
    > v = c(n,i)
    > class(v)
    [1] "complex"
    > v
       A    B    C    D    E    F    G    H    I    J                          
    0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i
  4. รายการสามารถมีประเภทข้อมูลที่แตกต่างกันดังที่เห็นในคำตอบอื่น ๆ และคำถามของ OP เอง

ฉันเคยเห็นภาษา (ruby, javascript) ซึ่ง "อาร์เรย์" อาจมีประเภทข้อมูลตัวแปร แต่ตัวอย่างเช่นใน C ++ "อาร์เรย์" ต้องเป็นประเภทข้อมูลเดียวกันทั้งหมด ผมเชื่อว่านี่เป็นสิ่งที่ความเร็ว / ประสิทธิภาพ: ถ้าคุณมีnumeric(1e6)คุณทราบขนาดและตำแหน่งของทุกองค์ประกอบของตนเบื้องต้น ; หากสิ่งนั้นอาจมี"Flying Purple People Eaters"อยู่ในส่วนที่ไม่รู้จักคุณต้องวิเคราะห์สิ่งที่ต้องรู้ข้อเท็จจริงพื้นฐาน

การดำเนินงานมาตรฐาน R บางอย่างนั้นสมเหตุสมผลมากขึ้นเมื่อรับประกันประเภท ยกตัวอย่างเช่นไม่มีcumsum(1:9)เหตุผลcumsum(list(1,2,3,4,5,'a',6,7,8,9))ใด ๆ หากไม่มีประเภทที่รับประกันว่าจะเป็นสองเท่า


ตามคำถามที่สองของคุณ:

สามารถส่งคืนรายการจากฟังก์ชันแม้ว่าคุณจะไม่เคยส่งผ่านในรายการเมื่อคุณเรียกใช้ฟังก์ชัน

ฟังก์ชั่นคืนค่าชนิดข้อมูลที่แตกต่างจากที่ป้อนตลอดเวลา plotส่งคืนพล็อตแม้ว่าจะไม่ใช้พล็อตเป็นอินพุต Argส่งกลับแม้ว่ามันจะได้รับการยอมรับnumeric complexเป็นต้น

(และสำหรับstrsplit: ซอร์สโค้ดอยู่ที่นี่ )


2

นี่เป็นคำถามที่ค่อนข้างเก่าฉันต้องบอกว่ามันสัมผัสกับความรู้ที่ฉันหายไปในระหว่างขั้นตอนแรกของฉันใน R - นั่นคือวิธีการแสดงข้อมูลในมือของฉันเป็นวัตถุใน R หรือวิธีการเลือกจากวัตถุที่มีอยู่ มันไม่ใช่เรื่องง่ายสำหรับมือใหม่ที่จะคิดว่า "ในกล่อง R" ตั้งแต่ต้น

ดังนั้นตัวฉันเองจึงเริ่มใช้ไม้ค้ำด้านล่างซึ่งช่วยฉันได้มากในการค้นหาว่าวัตถุใดที่จะใช้สำหรับข้อมูลใดและโดยพื้นฐานแล้วจินตนาการถึงการใช้งานจริง

แม้ว่าฉันจะไม่ได้ให้คำตอบที่ถูกต้องกับคำถาม แต่ข้อความสั้น ๆ ด้านล่างอาจช่วยให้ผู้อ่านที่เพิ่งเริ่มใช้ R และถามคำถามที่คล้ายกัน

  • เวกเตอร์อะตอม ... ฉันเรียกว่า "ลำดับ" สำหรับตัวเองไม่มีทิศทางเพียงเรียงลำดับประเภทเดียวกัน [ส่วนย่อย
  • Vector ... ลำดับที่มีทิศทางเดียวจาก 2D [ชุดย่อย
  • เมทริกซ์ ... กลุ่มของเวกเตอร์ที่มีความยาวเท่ากันเป็นแถวหรือคอลัมน์, [ชุดย่อยตามแถวและคอลัมน์, หรือตามลำดับ
  • อะเรย์ ... เมทริกซ์ชั้นขึ้นรูปเป็น 3D
  • Dataframe ... ตาราง 2D เหมือนใน excel ที่ฉันสามารถเรียงลำดับเพิ่มหรือลบแถวหรือคอลัมน์หรือสร้าง arit การดำเนินการกับพวกเขาเท่านั้นหลังจากที่บางเวลาผมจำได้ว่า dataframe คือการดำเนินการฉลาดของlistที่ฉันสามารถย่อยใช้[โดยแถวและคอลัมน์ [[แต่แม้กระทั่งการใช้
  • รายการ ... เพื่อช่วยตัวเองฉันคิดถึงรายการtree structureที่[i]เลือกและส่งคืนทั้งสาขาและ[[i]]ส่งคืนรายการจากสาขา และเพราะมันเป็นสิ่งที่tree like structureคุณยังสามารถใช้index sequenceเพื่อแก้ไขทุกใบเดี่ยวบนที่ซับซ้อนมากใช้มันlist [[index_vector]]รายการสามารถเรียบง่ายหรือซับซ้อนมากและสามารถผสมวัตถุประเภทต่างๆเข้าด้วยกันเป็นหนึ่งเดียว

ดังนั้นสำหรับlistsคุณสามารถจบลงด้วยวิธีการเลือกleafขึ้นอยู่กับสถานการณ์เช่นในตัวอย่างต่อไปนี้

l <- list("aaa",5,list(1:3),LETTERS[1:4],matrix(1:9,3,3))
l[[c(5,4)]] # selects 4 from matrix using [[index_vector]] in list
l[[5]][4] # selects 4 from matrix using sequential index in matrix
l[[5]][1,2] # selects 4 from matrix using row and column in matrix

วิธีคิดนี้ช่วยฉันได้มาก


1

หากช่วยได้ฉันมักจะเข้าใจ "รายการ" ใน R เป็น "บันทึก" ในภาษาพรีโอ OO อื่น ๆ :

  • พวกเขาไม่ได้ตั้งสมมุติฐานใด ๆ เกี่ยวกับประเภทที่ครอบคลุม (หรือเป็นประเภทของระเบียนที่เป็นไปได้ทั้งหมดของชื่อ arity และชื่อฟิลด์ใด ๆ )
  • เขตข้อมูลของพวกเขาสามารถไม่ระบุชื่อ (จากนั้นคุณเข้าถึงพวกเขาตามคำจำกัดความที่เข้มงวด)

ชื่อ "บันทึก" จะขัดแย้งกับความหมายมาตรฐานของ "บันทึก" (แถว aka) ในสำนวนฐานข้อมูลและอาจเป็นสาเหตุที่ชื่อของพวกเขาแนะนำตัวเอง: เป็นรายการ (ของเขตข้อมูล)


1

เหตุใดตัวดำเนินการทั้งสองแตกต่างกัน[ ]และ[[ ]]ส่งคืนผลลัพธ์เดียวกัน

x = list(1, 2, 3, 4)
  1. [ ]ให้การตั้งค่าย่อย โดยทั่วไปชุดย่อยของวัตถุใด ๆ จะมีชนิดเดียวกันกับวัตถุต้นฉบับ ดังนั้นx[1] ให้รายการ ในทำนองเดียวกันx[1:2]เป็นส่วนย่อยของรายการต้นฉบับดังนั้นจึงเป็นรายการ อดีต

    x[1:2]
    
    [[1]] [1] 1
    
    [[2]] [1] 2
  2. [[ ]]ใช้สำหรับการแยกองค์ประกอบออกจากรายการ x[[1]]ถูกต้องและแยกองค์ประกอบแรกจากรายการ x[[1:2]]ไม่ถูกต้องตามที่ไม่ได้ให้การตั้งค่าย่อยเช่น[[ ]] [ ]

     x[[2]] [1] 2 
    
    > x[[2:3]] Error in x[[2:3]] : subscript out of bounds
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.