r - 제목 - ggtitle




data.table에서 키를 설정하는 목적은 무엇입니까? (2)

키는 기본적으로 데이터 집합에 대한 인덱스이며 매우 빠르고 효율적인 정렬, 필터 및 조인 작업을 허용합니다. 이것은 아마도 데이터 프레임 대신 데이터 테이블을 사용하는 가장 좋은 이유입니다. 데이터 테이블을 사용하는 구문은 훨씬 더 사용자 친화적이지만 키와는 아무런 관련이 없습니다.

색인을 이해하지 못하면 다음을 고려하십시오. 전화 번호부는 이름으로 "색인"되어 있습니다. 누군가의 전화 번호를 조회하고 싶다면 매우 간단합니다. 그러나 전화 번호로 검색하려고한다고 가정합니다 (예 : 특정 전화 번호를 가진 사람 조회). 전화 번호부로 전화 번호부를 "다시 색인화"할 수 없다면 매우 오랜 시간이 걸릴 것입니다.

다음 예를 고려하십시오. 미국의 모든 우편 번호 (> 33,000)와 관련 정보 (시, 주, 인구, 중간 수입 등)가있는 가정하십시오. 특정 우편 번호에 대한 정보를 찾으려면 먼저 setkey(ZIP,zipcode) 하면 검색 (필터)이 약 1000 배 빠릅니다.

조인과 관련된 또 다른 이점이 있습니다. 데이터 테이블에 사람과 우편 번호 목록 ( "PPL"이라고 함)이 있고 ZIP 표 (예 : 도시, 주 등)에 정보를 추가하려고한다고 가정합니다. 다음 코드는 그것을 할 것입니다 :

setkey(ZIP,zipcode)
setkey(PPL,zipcode)
full.info <- PPL[ZIP, nomatch=F]

이것은 공통 필드 (zipcode)를 기반으로하는 2 개의 테이블 정보를 결합한다는 의미에서 "조인"입니다. 매우 큰 테이블에서 이와 같은 조인은 데이터 프레임의 경우 매우 느리며 데이터 테이블의 경우 매우 빠릅니다. 실생활의 예에서 저는 우편 번호의 전체 테이블에서 이와 같이 2 만 개 이상의 조인을해야했습니다. 데이터 테이블로 스크립트는 약 20 분이 걸렸습니다. 달리기. 2 주 이상 걸렸으므로 데이터 프레임으로 시도하지 않았습니다.

IMHO 당신은 단지 읽는 것이 아니라 FAQ와 소개 자료를 공부 해야합니다. 이것을 적용 할 실제 문제가 있는지 파악하는 것이 더 쉽습니다.

[@ Frank의 코멘트에 대한 응답]

이 질문 에 대한 답을 바탕으로, setkey(...) 는 실제로 테이블의 열 (예 : 물리적 정렬)을 재 배열하고 데이터베이스에 인덱스를 만들지 않는 것으로 나타납니다. 감각. setkey(...) 를 사용하여 테이블에 키를 설정하고 키 열의 값을 변경하면 data.table은 더 이상 테이블을 더 이상 정렬하지 않는다고 선언합니다 ( sorted 속성 끄기); 적절한 정렬 순서를 유지하기 위해 동적으로 색인을 다시 생성하지 않습니다 (데이터베이스 에서처럼). 또한 setky(DT,NULL) 사용하여 "키 제거"를 실행 setky(DT,NULL) 테이블이 원래의 정렬되지 않은 순서로 복원되지 않습니다 .

재 : 필터 대 조인 - 실제적인 차이점은 필터링이 단일 데이터 집합에서 부분 집합을 추출하는 반면 조인은 공통 필드를 기반으로 두 데이터 집합의 데이터를 결합한다는 것입니다. 조인에는 여러 가지 종류가 있습니다 (내부, 외부, 왼쪽). 위의 예제는 내부 조인입니다 (두 테이블에 공통된 키가있는 레코드 만 반환됩니다). 이는 필터링과 많은 유사점이 있습니다.

data.table을 사용하고 있으며 키를 설정해야하는 많은 기능이 있습니다 (예 : X[Y] ). 따라서 데이터 표에 키를 올바르게 설정하기 위해 키가 수행하는 작업을 이해하고 싶습니다.

내가 읽은 한가지 소스는 ?setkey .

setkey()data.table 정렬하고 정렬 된 data.table 표시합니다. 정렬 된 열이 키입니다. 키는 임의의 순서의 모든 열이 될 수 있습니다. 열은 항상 오름차순으로 정렬됩니다. 테이블은 참조에 의해 변경됩니다. 하나의 열만큼 큰 임시 작업 메모리 이외에는 복사가 전혀 이루어지지 않습니다.

여기에있는 테이크 어웨이는 key가 data.table을 "정렬"하여 order() 와 매우 비슷한 결과를 가져온다는 것입니다. 그러나 키를 가지고있는 목적을 설명하지는 않습니다.

data.table FAQ 3.2 및 3.3에서는 다음과 같은 내용을 설명합니다.

3.2 대형 테이블에 키가 없지만 그룹화는 여전히 빠릅니다. 왜 그런가요?

data.table은 기수 정렬을 사용합니다. 이것은 다른 정렬 알고리즘보다 훨씬 빠릅니다. 기수는 정수에만 사용됩니다 ?base::sort.list(x,method="radix") . 이것은 setkey() 가 빠르다는 또 하나의 이유이기도합니다. 키가 설정되지 않았거나 키의 순서와 다른 순서로 그룹화 할 때 우리는이를 임시로 호출합니다.

3.3 키의 열을 그룹별로 임시로 그룹화하는 이유는 무엇입니까?

왜냐하면 각 그룹은 RAM에서 연속적이기 때문에 페이지 가져 오기를 최소화하고 C에서 반복하지 않고 메모리를 대량으로 복사 할 수 있습니다 (C에서는 memcpy ).

여기에서 키를 어떻게 설정하면 R이 다른 알고리즘보다 "기수 정렬"을 사용할 수 있기 때문에 더 빠릅니다.

10 분 빠른 시작 안내서에는 키에 대한 안내서도 있습니다.

  1. 열쇠

data.frame, 특히 rownames (또는 영문, 행 이름)를 고려해 보겠습니다. 즉, 단일 행에 속하는 여러 이름. 단일 행에 속하는 여러 이름? 그것은 우리가 data.frame에서 익숙하지 않은 것입니다. 각 행에는 최대 하나의 이름 만 있습니다. 사람은 적어도 두 개의 이름, 첫 번째 이름과 두 번째 이름을가집니다. 이것은 전화 번호부를 구성하는 데 유용합니다 (예 : 성, 첫 번째 순으로 정렬). 그러나 data.frame의 각 행에는 하나의 이름 만있을 수 있습니다.

키는 rownames의 하나 이상의 열로 구성되며 정수, 요소, 문자 또는 단순히 문자가 아닌 다른 클래스 일 수 있습니다. 또한 행은 키순으로 정렬됩니다. 따라서 data.table은 여러 가지 방법으로 정렬 될 수 없으므로 하나의 키만 가질 수 있습니다.

고유성이 강제되지 않습니다. 즉, 중복 키 값이 허용됩니다. 행은 키순으로 정렬되므로 키의 중복 된 항목은 연속적으로 나타납니다.

전화 번호부는 키가 무엇인지 이해하는 데 도움이되었지만 요소 열과 비교할 때 키가 다르지 않은 것으로 보입니다. 또한 키가 필요한 이유 (특히 특정 기능 사용)와 키로 설정할 열을 선택하는 방법에 대해 설명하지 않습니다. 또한, 시간이있는 data.table에서 열이있는 것으로 보이는 경우 다른 열을 키로 설정하면 시간 열이 너무 엉망이되어 다른 열을 다른 열로 설정할 수 있는지 알 수 없기 때문에 혼란스럽게 보일 수 있습니다. 키. 누군가 제발 나를 밝힐 수 있습니까?


사소한 업데이트 : 새로운 HTML 비 네트 도 참조하십시오. 이 문제 는 우리가 계획하고있는 다른 비 네트를 강조합니다.

ad-hoc 조인을 허용하는 새로운 on= 기능을 고려하여이 답변을 다시 업데이트했습니다 (2016 년 2 월). 이전 (오래된) 답변에 대한 기록을보십시오.

setkey(DT, a, b) 는 정확히 무엇을합니까?

두 가지 작업을 수행합니다.

  1. 제공된 열 ( a , b )에 의해 data.table DT 의 행을 참조 로 항상 순서대로 재 배열합니다.
  2. sorted 속성을 DT 로 설정하여 해당 열을 열로 표시합니다.

재정렬은 ( data.table 의 내부 기수 정렬로 인해) 빠르고 효율적입니다 ( double 유형의 여분의 열 하나만 할당됩니다).

setkey() 필요한시기는 언제입니까?

그룹화 작업의 경우 setkey() 가 절대로 필요하지 않았습니다. 즉, 콜드 바이 또는 애드 호크 바이를 수행 할 수 있습니다.

## "cold" by
require(data.table)
DT <- data.table(x=rep(1:5, each=2), y=1:10)
DT[, mean(y), by=x] # no key is set, order of groups preserved in result

그러나 v1.9.6 이전에는 x[i] 형식의 조인에 x 로 설정되어야했습니다. v1.9.6 +의 새로운 on= 인수를 사용하면 더 이상 사실이 아니므로 설정 키는 여기서도 절대 필요 하지 않습니다 .

## joins using < v1.9.6 
setkey(X, a) # absolutely required
setkey(Y, a) # not absolutely required as long as 'a' is the first column
X[Y]

## joins using v1.9.6+
X[Y, on="a"]
# or if the column names are x_a and y_a respectively
X[Y, on=c("x_a" = "y_a")]

on= 인수는 keyed 조인에 대해서도 명시 적으로 지정할 수 있습니다.

key 를 절대적으로 설정해야하는 유일한 작업은 foverlaps() 함수입니다. 그러나 우리는이 요구 사항을 제거 할 수있는 몇 가지 기능을 추가로 연구하고 있습니다.

  • 그렇다면 on= 인수를 구현하는 이유는 무엇입니까?

    몇 가지 이유가 있습니다.

    1. 이를 통해 두 개의 데이터 테이블을 포함하는 작업으로 작업을 명확하게 구분할 수 있습니다. X[Y] 하는 것만으로 변수를 적절히 명명해도 명확 할 수 있지만 이것을 구별하지는 않습니다.

    2. 또한 해당 코드 행을보고 해당 setkey() 행으로 역 추적 할 필요없이 조인 / 하위 집합 이 수행되는 열을 즉시 이해할 수 있습니다.

    3. 참조의해 열이 추가되거나 업데이트 되는 작업에서 on= 작업은 열을 추가 / 업데이트하기 위해 전체 data.table을 다시 정렬 할 필요가 없으므로 훨씬 더 효율적입니다. 예를 들어,

      ## compare 
      setkey(X, a, b) # why physically reorder X to just add/update a column?
      X[Y, col := i.val]
      
      ## to
      X[Y, col := i.val, on=c("a", "b")]
      

      두 번째 경우에는 순서를 변경할 필요가 없었습니다. 시간 소모적 인 주문을 계산하는 것이 아니라 RAM에있는 data.table을 물리적으로 재주문하고이를 피함으로써 원래의 순서를 유지하며 성능도 우수합니다.

    4. 그렇지 않은 경우 조인을 반복적으로 수행하지 않으면 조인 과 임시 조 인간에 성능 차이가 눈에 띄지 않아야합니다.

이것은 질문에 이르게합니다. 데이터 테이블에 어떤 이점이 있습니까?

  • data.table을 키잉 할 때 이점이 있습니까?

    data.table을 키잉하면 RAM의 해당 열을 기반으로 물리적으로 재정렬됩니다. 순서를 계산하는 것은 일반적으로 시간 소모적 인 부분이 아니라 순서 변경 자체입니다. 그러나 일단 RAM에 저장된 데이터가 정렬되면 동일한 그룹에 속하는 행은 모두 RAM에서 연속적이므로 매우 효율적인 캐시입니다. 그것은 keyed data.tables에 대한 작업 속도를 높이는 정렬입니다.

    따라서 전체 data.table을 재정렬하는 데 소요되는 시간이 캐시 효율적인 조인 / 집계를 수행하는 데 가치가 있는지 파악하는 것이 중요합니다. 일반적으로 반복되는 그룹화 / 결합 작업이 동일한 키순 데이터 테이블에서 수행되는 경우가 아니면 눈에 띄는 차이가 없어야합니다.

따라서 대부분의 경우 키를 더 이상 설정할 필요가 없습니다. 가능하면 키 설정을 통해 성능을 크게 향상시키지 않는 한 on= 사용 on= 것이 좋습니다.

질문 : setorder() 를 사용하여 data.table의 순서를 바꾸고 on= 을 사용하면 결합과 비교할 때 성능이 어떻게 될 것이라고 생각하십니까? 지금까지 따라 해봤 으면 알아낼 수 있어야합니다 :-).







data.table