data.frame 또는 행렬을 사용해야합니까?


152

언제을 사용해야하고 언제을 사용하는 data.frame것이 더 낫 matrix습니까?

둘 다 데이터를 직사각형 형식으로 유지하기 때문에 때때로 불분명합니다.

언제 어떤 데이터 유형을 사용해야하는지에 대한 일반적인 규칙이 있습니까?


행렬은 특정 유형의 데이터에 더 적합 할 수 있지만, 해당 행렬을 분석하는 데 사용하려는 패키지가 데이터 프레임을 기대하는 경우 항상 불필요하게 변환해야합니다. 어떤 패키지가 어떤 패키지를 사용하는지 기억하지 못하는 방법이 없다고 생각합니다.
xApple

답변:


176

답변의 일부는 이미 귀하의 질문에 포함되어 있습니다 : 열 (변수)이 다른 유형 (숫자 / 문자 / 논리 등) 일 것으로 예상되는 경우 데이터 프레임을 사용하십시오. 행렬은 같은 유형의 데이터를위한 것입니다.

결과적으로, matrix / data.frame 선택은 동일한 유형의 데이터가있는 경우에만 문제가됩니다.

답은 data.frame / matrix의 데이터로 수행하려는 작업에 따라 다릅니다. 다른 함수로 전달 될 경우 이러한 함수의 예상 인수 유형이 선택을 결정합니다.

또한:

행렬은 더 메모리 효율적입니다.

m = matrix(1:4, 2, 2)
d = as.data.frame(m)
object.size(m)
# 216 bytes
object.size(d)
# 792 bytes

선형 대수 유형의 연산을 수행하려는 경우 행렬이 필요합니다.

데이터 프레임은 이름으로 열을 자주 참조하는 경우 (콤팩트 $ 연산자를 통해) 더 편리합니다.

각 열에 개별적으로 서식을 적용 할 수 있으므로 테이블 형식 정보를보고 (인쇄)하는 데 데이터 프레임이 더 좋습니다.


5
이 답변에 추가 할 한 가지는 ggplot2 패키지를 사용하여 그래프를 만들 계획이라면 ggplot2는 행렬이 아닌 data.frames에서만 작동한다는 것입니다. 알아야 할 것!
Bajcz

77

@Michal이 언급하지 않은 것은 동등한 데이터 프레임보다 작은 매트릭스 일뿐 만 아니라 행렬을 사용하면 데이터 프레임을 사용하는 것보다 훨씬 효율적으로 코드를 훨씬 효율적으로 만들 수 있다는 것입니다. 이것이 내부적으로 많은 R 함수가 데이터 프레임에있는 행렬 데이터로 강제되는 이유입니다.

데이터 프레임은 종종 훨씬 더 편리합니다. 항상 원자 적으로 만 존재하는 것은 아닙니다.

문자 행렬을 가질 수 있습니다. R로 행렬을 만들기 위해 숫자 데이터를 가질 필요는 없습니다.

데이터 프레임을 행렬 data.matrix()로 변환 할 때는 내부 수준에 따라 요소를 숫자 값으로 변환하여 적절히 처리 하는 함수 가 있습니다. as.matrix()인자 레이블이 숫자가 아닌 경우 비아 를 강제 변환 하면 문자 행렬이 생성됩니다. 비교:

> head(as.matrix(data.frame(a = factor(letters), B = factor(LETTERS))))
     a   B  
[1,] "a" "A"
[2,] "b" "B"
[3,] "c" "C"
[4,] "d" "D"
[5,] "e" "E"
[6,] "f" "F"
> head(data.matrix(data.frame(a = factor(letters), B = factor(LETTERS))))
     a B
[1,] 1 1
[2,] 2 2
[3,] 3 3
[4,] 4 4
[5,] 5 5
[6,] 6 6

나는 종종 숫자 변수 이상을 가지고 있기 때문에 거의 항상 데이터 분석 작업에 데이터 프레임을 사용합니다. 패키지의 함수를 코딩 할 때는 거의 항상 행렬로 강제 변환 한 다음 결과를 데이터 프레임으로 다시 형식화합니다. 데이터 프레임이 편리하기 때문입니다.


data.matrix ()와 as.matrix ()의 차이점도 궁금합니다. 그것들과 프로그래밍 팁을 명확히 해주셔서 감사합니다.
미생물

@Gavin Simpson을 공유해 주셔서 감사합니다! 1-6에서 af로 돌아가는 방법에 대해 조금 더 소개해 주시겠습니까?
YJZ

1
@YZhang 각 요인에 대한 레이블과 행렬의 어떤 열이 요인인지를 나타내는 논리 형 벡터를 저장해야합니다. 그런 다음 요소 인 열만 올바른 레이블이있는 요소로 다시 변환하는 것은 상대적으로 쉽지 않습니다. 주석은 코드를 작성하기에 좋은 장소가 아니므로 Q가 이전에 질문 및 답변을 받았는지 여부와 새로운 질문을하지 않는지 확인하십시오.
개빈 심슨

47

@Michal : 행렬은 실제로 더 효율적인 메모리는 아닙니다.

m <- matrix(1:400000, 200000, 2)
d <- data.frame(m)
object.size(m)
# 1600200 bytes
object.size(d)
# 1600776 bytes

... 열 수가 많은 경우가 아니면 :

m <- matrix(1:400000, 2, 200000)
d <- data.frame(m)
object.size(m)
# 1600200 bytes
object.size(d)
# 22400568 bytes

메모리 효율성 논쟁은 실제로 data.frames열 유형보다 더 많은 유연성을 제공하는 것입니다. 강제 변환으로 인해 버전 data.frame(a = rnorm(1e6), b = sample(letters, 1e6, TRUE))보다 메모리에서 훨씬 작습니다 (빠른 계산으로 6 배) matrix.
MichaelChirico

9

행렬은 실제로 추가 방법이있는 벡터입니다. data.frame은 목록입니다. 차이점은 벡터 대리스트입니다. 계산 효율성을 위해 매트릭스를 사용하십시오. 필요한 경우 data.frame을 사용하십시오.


3
흠, 행렬은 차원이있는 벡터입니다. 어떻게 메소드가 나오는지 모르겠습니까?
Gavin Simpson

0

행렬과 데이터 프레임은 사각형 2D 배열이며 행과 열로 이기 종일 수 있습니다 . 그것들은 일부 메소드와 속성을 공유하지만 전부는 아닙니다.

예 :

M <- list(3.14,TRUE,5L,c(2,3,5),"dog",1i)  # a list
dim(M) <- c(2,3)                           # set dimensions
print(M)                                   # print result

#      [,1]  [,2]      [,3]
# [1,] 3.14  5         "dog"
# [2,] TRUE  Numeric,3 0+1i

DF <- data.frame(M)                   # a data frame
print(DF)                             # print result

#      X1      X2   X3
#  1 3.14       5  dog
#  2 TRUE 2, 3, 5 0+1i

M <- matrix(c(1,1,1,1,2,3,1,3,6),3)   # a numeric matrix
DF <- data.frame(M)                   # a all numeric data frame

solve(M)                              # obtains inverse matrix
solve(DF)                             # obtains inverse matrix
det(M)                                # obtains determinant
det(DF)                               # error

0

나는 둘 사이의 효율성 차이를 더 강조 할 수 없다! DF가 특히 데이터 분석 사례에서 더 편리하다는 것은 사실이지만, 이기종 데이터도 허용하고 일부 라이브러리는 이러한 데이터 만 허용하지만 특정 작업에 대한 일회성 코드를 작성하지 않는 한 이러한 라이브러리는 모두 보조입니다.

예를 들어 보겠습니다. MCMC 방법의 2D 경로를 계산하는 기능이있었습니다. 기본적으로 이것은 초기 지점 (x, y)을 취하고 특정 알고리즘을 반복하여 각 단계에서 새로운 지점 (x, y)을 찾아 전체 경로를 구성합니다. 알고리즘은 매우 복잡한 함수를 계산하고 각 반복에서 임의의 변수를 생성하는 것을 포함하므로 12 초 동안 실행될 때 각 단계에서 얼마나 많은 작업을 수행하는 것이 좋을 것이라고 생각했습니다. 즉, 함수는 3 열 데이터 프레임에서 목적 함수의 값과 함께 구성된 경로의 모든 포인트를 수집했습니다. 따라서 3 열은 그다지 크지 않으며 단계 수도 10,000보다 합리적입니다 (이러한 문제에서 길이 1,000,000의 경로는 일반적이므로 10,000은 아무것도 아닙니다). 그래서 저는 DF 10을 생각했습니다. 000x3은 확실히 문제가되지 않습니다. DF가 사용 된 이유는 간단합니다. 함수를 호출 한 후 ggplot ()이 호출되어 결과 (x, y) 경로를 그립니다. 그리고 ggplot ()은 행렬을 허용하지 않습니다.

그런 다음 호기심을 벗어난 시점에서 행렬에서 경로를 수집하도록 함수를 변경하기로 결정했습니다. 다행스럽게도 DF와 행렬의 구문은 비슷하지만 df를 data.frame으로 지정하는 행을 행렬로 초기화하는 행으로 변경하는 것이 전부였습니다. 여기서 초기 코드에서 DF가 최종 크기를 갖도록 초기화되었으므로 나중에 함수 코드에서 새로운 값만 이미 할당 된 공간에 기록되었으며 새 행을 추가하는 오버 헤드가 없었습니다. DF. 이것은 비교를 더욱 공정하게 만들고 함수에서 더 이상 아무것도 다시 쓸 필요가 없으므로 작업을 더 단순하게 만들었습니다. 필요한 크기의 data.frame의 초기 할당에서 동일한 크기의 행렬로 한 줄만 변경됩니다. 새 버전의 함수를 ggplot ()에 적용하기 위해, 이제 반환 된 행렬을 데이터로 변환했습니다.

코드를 다시 실행 한 후 결과를 믿을 수 없었습니다. 코드는 순식간에 실행됩니다! 약 12 초 대신. 다시 말하지만, 10,000 회 반복 동안의 함수는 DF (및 이제는 매트릭스)의 이미 할당 된 공간에 대한 값만 읽고 씁니다. 그리고이 차이는 합리적인 (또는 다소 작은) 크기 10000x3에도 적용됩니다.

따라서 DF를 사용하는 유일한 이유가 ggplot ()과 같은 라이브러리 함수와 호환되도록하는 것이라면 마지막 순간에 언제든지 DF로 변환 할 수 있습니다. 편리하다고 느끼는 한 행렬로 작업하십시오. 반면에 행렬에서 DF로 또는 그 반대로 상수 변환해야하는 일부 데이터 분석 패키지를 사용하거나 집중 계산을 직접 수행하지 않고 표준 만 사용하는 등 DF를 사용해야하는보다 실질적인 이유가있는 경우 패키지 (많은 것들이 실제로 DF를 매트릭스로 내부적으로 변환하고, 작업을 수행 한 다음 결과를 다시 변환하여 모든 효율성 작업을 수행합니다) 또는 일회성 작업을 수행하므로 걱정하지 않아도됩니다. DF에 더 편안하면 효율성에 대해 걱정할 필요가 없습니다.

또는 다른 실제 규칙 : OP와 같은 질문이있는 경우 행렬을 사용하십시오. 따라서 그러한 질문이없는 경우에만 DF를 사용하십시오 (이미 DF를 사용해야한다는 것을 알고 있기 때문에 또는 코드가 일회성이므로 실제로 신경 쓰지 않습니다.)

그러나 일반적으로이 효율성 지점을 항상 우선 순위로 유지하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.