r - 이란 - 자료형 자료구조 차이




R에서 목록을 올바르게 사용하는 방법? (8)

귀하의 질문에 관해서는 순서대로 설명하고 몇 가지 예를 들겠습니다.

1 ) return 문에 명령문이 추가되면 목록이 반환됩니다. 중히 여기다

 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 와 같습니다. 모든 스칼라는 길이가 1 인 벡터입니다. 반면에 x[[1]] 는리스트의 첫번째 원소를 반환합니다.

4 ) 마지막으로, 두 개는 4 개의 스칼라가 포함 된 목록과 하나의 요소 (4 개의 요소로 구성된 벡터)가 포함 된 목록을 만드는 것과 다릅니다.

간략한 배경 : 널리 사용되는 많은 (대부분의) 현대 프로그래밍 언어는 공통적으로 적어도 소수의 ADT [추상 데이터 유형]를 가지고 있으며,

  • 문자열 (문자로 구성된 시퀀스)

  • list (정렬 된 값 모음) 및

  • 지도 기반 유형 (키를 값에 매핑하는 정렬되지 않은 배열)

R 프로그래밍 언어에서 처음 두 개는 각각 charactervector 로 구현됩니다.

R을 배우기 시작했을 때 처음부터 거의 두 가지가 분명했습니다. list 은 R에서 가장 중요한 데이터 유형 (R data.frame 의 상위 클래스이기 때문에)이었고 둘째, 적어도 내 코드에서 올바르게 사용하기에 충분하지 않습니다.

우선, R의 list 데이터 유형이 ADT (Python의 dictionary , Objective C의 NSMutableDictionary , Perl 및 Ruby의 hash , Javascript의 object literal 등)의 직접적인 구현이었습니다.

예를 들어, 키 - 값 쌍을 생성자에 전달하여 파이썬 사전과 마찬가지로 생성합니다 (파이썬에서는 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 list 은 다른지도 유형 ADT 와는 다릅니다 (어쨌든 배웠던 언어 중에서). 내 생각에 이것은 S에 대한 초기 사양, 즉 데이터 / 통계 DSL [도메인 특정 언어]을 근본부터 고안하려는 의도의 결과입니다.

R list 과 널리 사용되는 다른 언어의 매핑 유형 (예 : Python, Perl, JavaScript) 간의 세 가지 중요한 차이점은 list 과 같습니다.

첫째로 , R의 list s는 값이 키가 되어도 벡터처럼 순서지정된 콜렉션입니다 (즉, 키는 순차적 정수가 아닌 임의의 해시 가능 값이 될 수 있음). 거의 항상, 다른 언어의 매핑 데이터 유형은 정렬되지 않습니다 .

둘째로 , 함수를 호출 할 때 결코 list 넘지 않더라도 , 그리고 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

R의 세 번째 특이한 점은 다른 ADT의 멤버가 될 수없는 것처럼 보입니다. 그렇게하려고하면 기본 컨테이너가 list 강제 변환됩니다. 예를 들어,

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

class(x)
# [1] list

여기서 나의 의도는 언어를 비판하지 않거나 문서화 된 방법을 비판하는 것이 아닙니다. 마찬가지로, list 데이터 구조에 문제가 있거나 그것이 어떻게 작동하는지 제안하지 않습니다. 내가해야할 일은 올바른 방법 일 뿐이므로 코드를 올바르게 사용할 수 있습니다.

내가 더 잘 이해하고 싶은 종류의 것들이있다.

  • 함수 호출이 언제 list 를 반환 할 것인지를 결정하는 규칙은 무엇입니까 (예를 들어 위의 strsplit 표현식)?

  • list 명시 적으로 이름을 지정하지 않으면 (예 : list(10,20,30,40) ) 기본 이름은 1로 시작하는 순차 정수입니까? (나는 가정한다. 그러나 나는 그 대답이 '예'라고 확신 할 수 없다. 그렇지 않으면 우리는이 유형의 listunlist 대한 호출이있는 벡터로 강제 변환 할 수 없을 것이다.)

  • 이 두 연산자 [[]][[]]같은 결과를 반환하는 이유는 무엇입니까?

    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 )를 가르키지 마십시오. - 나는 그것을주의 깊게 읽었으므로 위에 언급 한 질문 유형에 답하는 데 도움이되지 않습니다.

(마지막으로, 나는 최근에 S4 클래스를 통해 전통적인 map-type 동작을 구현하는 hash ) 라 불리는 R 패키지 (CRAN에서 사용 가능)를 사용하는 것을 배웠고,이 패키지를 확실히 추천 할 수 있습니다.)


그들이 (주문한) 작업을 나열하는 한 가지 이유는 벡터가하지 않는 노드에서 모든 유형을 포함 할 수있는 정렬 된 컨테이너의 필요성을 해결하기위한 것입니다. 리스트는 임의의 유형 (그러나 같은 길이)의 벡터리스트 인 data.frame 의베이스를 형성하는 것을 포함하여 R에서 다양한 용도로 재사용됩니다.

이 두 표현식이 같은 결과를 반환하지 않는 이유는 무엇입니까?

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

@ Shane의 답변에 추가하려면 동일한 결과를 얻으려면 다음을 시도하십시오.

x3 = as.list(1:4)

벡터 1:4 를 목록으로 강제 변환합니다.


다른 언어의 벡터 및 해시 / 배열 개념과 관련하여 :

  1. 벡터는 rpois(1e4,5) , rpois(1e4,5) (5 개의 난수), numeric(55) (길이 55 제로 벡터, 2 개의 빈 문자열) 및 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의 질문 자체와 같이 다양한 데이터 유형이 포함될 수 있습니다.

"배열"변수 데이터 형식을 포함 할 수있는 언어 (루비, 자바 스크립트) 본 적이 있지만 C ++ 예를 들어 "배열"모든 동일한 데이터 형식이 있어야합니다. 나는 이것이 속도 / 효율 문제라고 생각한다 : 당신이 numeric(1e6) 를 가지고 있다면 당신은 그 크기와 모든 요소의 위치를 선험적으로 알 수있다 . 그 물건에 "Flying Purple People Eaters" 미지의 조각이 들어있을 수 있다면 실제로 그 물건에 대한 기본적인 사실을 알아 내야합니다.

특정 표준 R 작업은 유형이 보장 될 때 더 적합합니다. 예를 들어 cumsum(1:9) 은 의미가 있지만, cumsum(list(1,2,3,4,5,'a',6,7,8,9)) 은 유형이 이중으로 보장되지 않습니다.

두 번째 질문에 관해서 :

함수를 호출 할 때 List에 결코 전달하지 않은 경우에도 함수에서 목록을 반환 할 수 있습니다.

함수는 항상 입력하는 것보다 다른 데이터 형식을 반환합니다. plot 은 입력으로 플롯을 사용하지 않더라도 plot 반환합니다. Argcomplex 받아들이더라도 numeric 반환합니다. 기타.

(그리고 strsplit : 소스 코드가 here .)


도움이된다면, 나는 R에있는 "목록"을 다른 사전 OO 언어의 "레코드"로 생각하는 경향이있다.

  • 그들은 압도적 인 유형에 대한 어떠한 가정도하지 않는다. (또는 어떤 유형과 필드 명에 대한 가능한 모든 유형의 기록이 가능하다.)
  • 필드는 익명 일 수 있습니다 (엄격한 정의 순서에 따라 액세스 할 수 있습니다).

"레코드"라는 이름은 데이터베이스 용어로 "레코드"(일명 행)의 표준 의미와 충돌 할 수 있으며, 이것이 자신의 이름을 제안한 이유 일 수 있습니다 (필드의 목록).


이것에 하나 이상의 포인트를 추가하기 만하면됩니다.

R에는 hash 패키지 의 Python dict에 해당하는 데이터 구조가 있습니다. 오픈 데이터 그룹의이 블로그 포스트에서이 기사를 읽을 수 있습니다. 다음은 간단한 예입니다.

> 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 클래스는 목록과 매우 유사합니다. 그러나 대규모 데이터 세트의 경우 성능이 좋습니다.


이것은 꽤 오래된 질문입니다. R에서 첫 번째 단계에서 누락 된 지식 즉, R로 객체로 데이터를 표현하는 방법 또는 기존 객체에서 선택하는 방법과 정확히 일치하는 지식을 말하고 있어야합니다. R 초심자가 처음부터 "R 상자 안에"생각하는 것은 쉽지 않습니다.

그래서 저는 저 밑에있는 목발을 사용하기 시작했습니다.이 목발은 어떤 데이터를 어떤 물체에 사용할지를 발견하고 실제로는 실제 사용법을 상상해 보는 데 많은 도움이되었습니다.

질문에 대한 정확한 답을주지는 않았지만, 아래의 짧은 텍스트는 R로 시작한 독자에게 도움이 될 수 있으며 비슷한 질문을하고 있습니다.

  • 원자 벡터 ... 나는 그 자신을 위해 "순서"를, 어떤 방향으로도, 같은 유형의 순서라고 불렀다. [ 부분 집합.
  • 벡터 ... 2D에서 한 방향으로 시퀀스, [ 부분 집합.
  • 매트릭스 ... 행 또는 열을 형성하는 동일한 길이의 벡터, [ 행 및 열별로 또는 행렬에 의한 부분 집합].
  • 배열 ... 3D를 형성하는 계층화 된 행렬
  • Dataframe ... Excel에서와 같이 2D 테이블을 사용하여 행이나 열을 정렬, 추가 또는 제거하거나 arit을 만들 수 있습니다. 비록 데이터 프레임이 [ 행과 열을 사용하여 서브 세트 할 수있는 list 의 영리한 구현이지만 [[ .
  • 목록 ... 나 자신을 돕기 위해 [i] 가 전체 브랜치를 선택하여 반환하고 브랜치에서 항목을 반환하는 tree structure 의 목록을 생각했습니다. tree like structure 하기 때문에 index sequence 를 사용하여 [[index_vector]] 사용하여 매우 복잡한 list 모든 단일 리프를 처리 할 수도 있습니다. 목록은 간단하거나 매우 복잡 할 수 있으며 다양한 유형의 객체를 하나로 혼합 할 수 있습니다.

따라서 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

이 사고 방식은 나를 도왔습니다.


질문의 하위 집합을 가져 오는 것 :

색인 생성에 관한 이 기사[][[]] 의 차이에 대한 문제를 다룹니다.

짧은 [[]]에서는 목록에서 하나의 항목을 선택하고 [] 는 선택한 항목의 목록을 반환합니다. 귀하의 예제에서 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

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)




abstract-data-type