data.table vs dplyr: 한 쪽이 다른 쪽이 할 수 없는 것을 잘 할 수 있습니까, 아니면 잘 할 수 없습니까?
개요
저는비교잘있다습니알고적ly▁familiar다에 비교적 익숙합니다.data.table
와는 별로 관계가 없는dplyr
저는 SO에 나타난 몇 가지 비넷과 예제를 읽었고, 지금까지 제 결론은 다음과 같습니다.
data.table
그리고.dplyr
속도 면에서 비교할 수 있습니다. 단, 그룹이 많은 경우(예: 10-100K 이상) 및 일부 다른 상황에서는 예외입니다(아래 벤치마크 참조).dplyr
보다 쉽게 액세스할 수 있는 구문을 사용합니다.dplyr
인 DB 추상화).- 몇 가지 사소한 기능 차이가 있습니다(아래 "예/사용" 참조).
에 2꽤 익숙하기 않습니다. 생에각때제 2. 꽤익기무많않나습다니가지이게가에문하숙제가▁in▁doesn다 않습니나지가▁because많▁much▁weight.data.table
처음 보는 사용자에게는 큰 요인이 될 것이라는 것은 이해합니다.는 어떤 . 잘 있는 한 저의 입니다. 왜냐하면 그것은 이미 익숙한 사람의 관점에서 질문한 제 특정 질문과 무관하기 때문입니다.data.table
또한 "더 직관적"인 분석이 어떻게 더 빠른 분석으로 이어지는지에 대한 논의는 피하고 싶습니다(확실히 사실이지만 여기서 가장 관심 있는 것은 아닙니다).
질문.
제가 알고 싶은 것은:
- 패키지에 익숙한 사용자를 위해 하나 또는 다른 패키지로 코딩하기 훨씬 쉬운 분석 작업이 있습니까? (즉, 필요한 키 입력과 필요한 비밀 수준의 조합이 있습니다. 각각의 키 입력이 적은 것이 좋습니다.)
- 다른 패키지보다 한 패키지에서 실질적으로(즉, 2배 이상) 더 효율적으로 수행되는 분석 작업이 있습니까?
최근의 SO 질문 하나가 저로 하여금 이것에 대해 조금 더 생각하게 했습니다. 왜냐하면 그 시점까지 저는 생각하지 않았기 때문입니다.dplyr
할 수보다 훨씬 더 많은 것을 제공할 수 있을 것입니다.data.table
에 여기다니습있이 있습니다.dplyr
솔루션(Q 끝의 데이터):
dat %.%
group_by(name, job) %.%
filter(job != "Boss" | year == min(year)) %.%
mutate(cumu_job2 = cumsum(job2))
내가 해킹을 시도한 것보다 훨씬 더 나은 것은data.table
해결책그렇긴 하지만, 좋습니다.data.table
솔루션도 매우 우수합니다(Jean-Robert, Arun에게 감사드리며, 여기서 저는 가장 완벽한 솔루션보다 단일 진술을 선호했습니다).
setDT(dat)[,
.SD[job != "Boss" | year == min(year)][, cumjob := cumsum(job2)],
by=list(id, job)
]
후자에 대한 구문은 매우 난해해 보일 수 있지만, 실제로 익숙하다면 꽤 간단합니다.data.table
(즉, 좀 더 난해한 속임수를 사용하지 않습니다.)
이상적으로 제가 보고 싶은 것은 몇 가지 좋은 예들입니다.dplyr
또는data.table
방법이 훨씬 더 간결하거나 훨씬 더 잘 수행됩니다.
예
Usagedplyr
임의의 행 수를 반환하는 그룹화된 작업을 허용하지 않습니다(eddi의 질문에서, 참고: 이것은 dplyr 0.5에서 구현될 것으로 보입니다. 또한, @beginneR은 다음을 사용하여 잠재적인 해결 방법을 보여줍니다.do
@eddi의 질문에 대한 대답에서).data.table
중첩 조인뿐만 아니라 롤링 조인(감사 @dholstius)도 지원합니다.data.table
▁form▁ofions 형태의 합니다.DT[col == value]
또는DT[col %in% values]
동일한 기본 R 구문을 사용하면서 이진 검색을 사용하는 자동 인덱싱을 통해 속도를 향상시킵니다.자세한 내용과 작은 벤치마크는 여기를 참조하십시오.dplyr
는 표준 는표 평버예기제공니합다을능의전가준예(▁of:다▁(니▁offers▁standard제합공▁eval▁versionsuatione▁functions을).regroup
,summarize_each_
의 프로그래밍 방식 사용을 단순화할 수 있습니다.dplyr
의 프로그래밍 참고)data.table
확실히 가능합니다. 적어도 제가 아는 한 신중한 생각, 대체/해결 등이 필요합니다.)
- 자체 벤치마크를 실행한 결과 두 패키지 모두 "분할 적용 결합" 스타일 분석에서 비교 가능한 것으로 나타났습니다. 단, 그룹 수가 매우 많은 경우(100K 이상)는 제외합니다.
data.table
속도가 상당히 빨라집니다. - @Arun은 조인에 대한 몇 가지 벤치마크를 실행하여 다음을 보여주었습니다.
data.table
성이뛰남보다 더 잘 됩니다.dplyr
그룹 수가 증가함에 따라(두 패키지의 최신 향상된 기능과 R의 최신 버전으로 업데이트됨).또한, 고유한 가치를 얻기 위해 노력할 때 벤치마크는data.table
최대 6배 더 빨라집니다. - has (확인되지 않음) 보
data.table
의 그룹/그룹 더 속도를 하는 반면, /그룹/그룹/그룹은 75% 더 빠른 속도를 제공합니다.dplyr
작은 것보다 40% 더 빨랐습니다(댓글에서 나온 또 다른 SO 질문, 고마워요 다나스). - 의
data.table
에서 그룹화 작업을 벤치마크했으며 최대 20억 행(RAM의 경우 최대 100GB)의 python에서 그룹화 작업을 수행했습니다. - 80K 그룹에 대한 오래된 벤치마크는
data.table
최대 8배 빠른 속도
데이터.
이것은 제가 질문 섹션에서 보여드린 첫 번째 예입니다.
dat <- structure(list(id = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L), name = c("Jane", "Jane", "Jane", "Jane",
"Jane", "Jane", "Jane", "Jane", "Bob", "Bob", "Bob", "Bob", "Bob",
"Bob", "Bob", "Bob"), year = c(1980L, 1981L, 1982L, 1983L, 1984L,
1985L, 1986L, 1987L, 1985L, 1986L, 1987L, 1988L, 1989L, 1990L,
1991L, 1992L), job = c("Manager", "Manager", "Manager", "Manager",
"Manager", "Manager", "Boss", "Boss", "Manager", "Manager", "Manager",
"Boss", "Boss", "Boss", "Boss", "Boss"), job2 = c(1L, 1L, 1L,
1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L)), .Names = c("id",
"name", "year", "job", "job2"), class = "data.frame", row.names = c(NA,
-16L))
포괄적인 답변/비교를 제공하려면 적어도 다음과 같은 측면을 다루어야 합니다(특별한 순서는 아님). Speed
,Memory usage
,Syntax
그리고.Features
.
제 의도는 data.table 관점에서 이들 각각을 가능한 한 명확하게 다루는 것입니다.
참고: 명시적으로 언급하지 않는 한 dplyr을 참조하여 Rcpp를 사용하여 내부가 C++인 dplyr의 data.frame 인터페이스를 참조합니다.
datadata.table 형식으로 됩니다.DT[i, j, by]
하기.유지하기 위해i
,j
그리고.by
함께 하는 것은 의도적인 것입니다.관련 작업을 함께 보관함으로써 속도와 메모리 사용에 대한 작업을 쉽게 최적화할 수 있으며 구문의 일관성을 유지하면서도 강력한 기능을 제공할 수 있습니다.
속도
이미 data를 보여주는 질문에 상당히 많은 벤치마크(대부분 그룹화 작업)가 추가되었습니다. 표는 그룹화할 그룹 및/또는 행의 수가 증가함에 따라 dplyr보다 빨라집니다. 여기에는 1억 - 1천만 그룹에 대한 Matton의 벤치마크가 20억 행(RAM 100GB)으로 증가하고 다양한 그룹화 열이 포함됩니다.그것은 또한 비교됩니다.pandas
다음을 포함하는 업데이트된 벤치마크도 참조하십시오.Spark
그리고.pydatatable
뿐만 아니라.
벤치마크에서 다음과 같은 나머지 측면도 다루는 것이 좋습니다.
행의 하위 집합을 포함하는 그룹화 작업 - 즉,
DT[x > val, sum(y), by = z]
활자 조작업데이트 및 조인과 같은 다른 작업을 벤치마킹합니다.
또한 런타임뿐만 아니라 각 작업에 대한 메모리 설치 공간도 벤치마크합니다.
메모리 사용량
작업
filter()
또는slice()
inplyr은 메모리 효율성이 떨어질 수 있습니다(data.frames 및 data.vmdk 모두에서).이 게시물을 참조하십시오.Hadley의 코멘트는 속도에 대해 말하고 있지만(dplyr는 그에게 매우 빠른 속도입니다), 여기서 주요 관심사는 기억입니다.
현재 data.table 인터페이스를 사용하면 참조를 통해 열을 수정/업데이트할 수 있습니다(결과를 변수로 다시 변환할 필요가 없음).
# sub-assign by reference, updates 'y' in-place DT[x >= 1L, y := NA]
하지만 dplyr은 절대 참조로 업데이트하지 않습니다.dplyr 등가물은 다음과 같습니다(결과를 다시 할당해야 함).
# copies the entire 'y' column ans <- DF %>% mutate(y = replace(y, which(x >= 1L), NA))
이것에 대한 우려는 참조 투명성입니다.특히 함수 내에서 참조로 data.table 개체를 업데이트하는 것이 항상 바람직한 것은 아닙니다.그러나 이것은 매우 유용한 기능입니다. 흥미로운 사례는 이 글과 이 게시물을 참조하십시오.그리고 우리는 그것을 유지하고 싶습니다.
는 수출을 .
shallow()
사용자에게 두 가지 가능성을 모두 제공하는 data.table의 함수입니다.예를 들어 함수 내에서 입력 data.table을 수정하지 않는 것이 바람직하다면 다음을 수행할 수 있습니다.foo <- function(DT) { DT = shallow(DT) ## shallow copy DT DT[, newcol := 1L] ## does not affect the original DT DT[x > 2L, newcol := 2L] ## no need to copy (internally), as this column exists only in shallow copied DT DT[x > 2L, x := 3L] ## have to copy (like base R / dplyr does always); otherwise original DT will ## also get modified. }
사용하지 으로써.
shallow()
이전 기능은 그대로 유지됩니다.bar <- function(DT) { DT[, newcol := 1L] ## old behaviour, original DT gets updated by reference DT[x > 2L, x := 3L] ## old behaviour, update column x in original DT. }
다음을 사용하여 얕은 복사본을 작성합니다.
shallow()
원래 개체를 수정하지 않으려는 것으로 알고 있습니다.우리는 내부적으로 모든 것을 처리하여 열을 복사하는 동시에 꼭 필요한 경우에만 수정할 수 있도록 합니다.구현될 때, 이것은 사용자에게 두 가지 가능성을 제공하면서 참조 투명성 문제를 완전히 해결해야 합니다.한 번 한또, 한번.
shallow()
는 거의 copydplyrl data.table을 .따라서 dplyr의 구문을 선호하는 사용자는 data.tables와 함께 사용할 수 있습니다.그러나 참조에 의한 (하위) 할당을 포함하여 data.table이 제공하는 많은 기능이 여전히 부족합니다.
가입 중 집계:
다음과 같이 두 개의 data.table이 있다고 가정합니다.
DT1 = data.table(x=c(1,1,1,1,2,2,2,2), y=c("a", "a", "b", "b"), z=1:8, key=c("x", "y")) # x y z # 1: 1 a 1 # 2: 1 a 2 # 3: 1 b 3 # 4: 1 b 4 # 5: 2 a 5 # 6: 2 a 6 # 7: 2 b 7 # 8: 2 b 8 DT2 = data.table(x=1:2, y=c("a", "b"), mul=4:3, key=c("x", "y")) # x y mul # 1: 1 a 4 # 2: 2 b 3
그리고 당신은 당신이 얻고 싶어합니다.
sum(z) * mul
행에대해의 각DT2
.x,y
다음 중 하나를 수행할 수 있습니다.-
DT1
갖기 위해sum(z)
(또는2) 합장을 하고 3) 합장을 .data.테이블웨이
DT1[, .(z = sum(z)), 키 기준 = .(x,y)][DT2][, z:= z*mul][]
dplyr 당량
DF1 %>% group_by(x, y) %>% 요약(z = sum(z)) %>% right_join(DF2) %>% 돌연변이(z = z * mul)
-
에 다 (한번에사수행모(용두) 사용)
by = .EACHI
기능):DT1[DT2, 목록(z=sum(z)) * mul, by = .EACHI]
장점은 무엇입니까?
중간 결과를 위해 메모리를 할당할 필요가 없습니다.
그룹화/해시를 두 번(하나는 집계용, 다른 하나는 가입용)할 필요가 없습니다.
그리고 더 중요한 것은, 우리가 수행하고자 했던 작업이 명확하다는 것입니다.
j
( (2)항에서
자세한 설명은 이 게시물을 참조하십시오.
by = .EACHI
중간 결과가 구체화되지 않고 join+aggregate가 한 번에 수행됩니다.실제 사용 시나리오를 보려면 이 게시물, 이 게시물 및 이 게시물을 확인하십시오.
dplyr
먼저 가입하고 집계 또는 집계한 다음에 가입해야 합니다. 메모리 측면에서 어느 쪽도 효율적이지 않습니다(이는 곧 속도로 변환됩니다).-
업데이트 및 가입:
아래에 표시된 data.table 코드를 고려합니다.
DT1[DT2, col := i.mul]
/추가
DT1
의 열 의럼col
와 함께mul
DT2
▁▁those서▁on의.DT2
의 키 이 의키 일열니다합치와 일치합니다DT1
나는 이 수술과 정확히 동등한 것이 있다고 생각하지 않습니다.dplyr
즉, 피하지 않고*_join
를 입니다.DT1
새 열을 추가할 필요가 없습니다.
요약하자면, 모든 최적화가 중요하다는 것을 깨닫는 것이 중요합니다.그레이스 호퍼가 말했듯이, 나노초를 조심하세요!
구문
이제 구문을 살펴보겠습니다.해들리는 여기에 언급했습니다.
데이터 테이블은 매우 빠르지만 정확성 때문에 배우기가 더 어렵고 작성 후에 읽기가 더 어렵습니다.
나는 이 말이 매우 주관적이기 때문에 의미가 없다고 생각합니다.우리가 시도할 수 있는 것은 아마도 구문의 일관성을 대조하는 것입니다.data.table과 dplyr 구문을 나란히 비교해 보겠습니다.
아래에 표시된 더미 데이터로 작업합니다.
DT = data.table(x=1:10, y=11:20, z=rep(1:2, each=5))
DF = as.data.frame(DT)
기본 집계/업데이트 작업.
# case (a) DT[, sum(y), by = z] ## data.table syntax DF %>% group_by(z) %>% summarise(sum(y)) ## dplyr syntax DT[, y := cumsum(y), by = z] ans <- DF %>% group_by(z) %>% mutate(y = cumsum(y)) # case (b) DT[x > 2, sum(y), by = z] DF %>% filter(x>2) %>% group_by(z) %>% summarise(sum(y)) DT[x > 2, y := cumsum(y), by = z] ans <- DF %>% group_by(z) %>% mutate(y = replace(y, which(x > 2), cumsum(y))) # case (c) DT[, if(any(x > 5L)) y[1L]-y[2L] else y[2L], by = z] DF %>% group_by(z) %>% summarise(if (any(x > 5L)) y[1L] - y[2L] else y[2L]) DT[, if(any(x > 5L)) y[1L] - y[2L], by = z] DF %>% group_by(z) %>% filter(any(x > 5L)) %>% summarise(y[1L] - y[2L])
data.table 구문은 압축적이고 dplyr은 상당히 장황합니다.(a)의 경우 사물은 다소 동등합니다.
(b)의 경우, 우리는 사용해야 했습니다.
filter()
요약하는 동안 dplyr.하지만 업데이트하는 동안 논리를 내부로 이동해야 했습니다.mutate()
data에서는 두 논리로 합니다. 즉, data.table이 있는 합니다.x > 2
첫 하만첫번경우는에째지,는경에우▁get▁but▁case▁first,,sum(y)
에는 이 합니다.y
그 누계로이것이 우리가 말할 때 의미하는 것입니다.
DT[i, j, by]
형식이 일치합니다.로 (에도 마찬가지로, (c)의 경우에도, (c)의 경우에도, (c)의 경우에도, (c)의 경우에도 마찬가지입니다.
if-else
조건은 data.table과 dplyr 모두에서 "있는 그대로" 논리를 표현할 수 있습니다.하지만, 만약 우리가 그 행들을 되돌리고 싶다면,if
는 조이충족않건너뜁다니으면그렇지고되건▁use를 사용할 수 . 사용할 수 없습니다.summarise()
직접af((AFAICT).는 리는한다 해야 .filter()
처음에 그리고 그 다음에 요약합니다 왜냐하면summarise()
는 항상 단일 값을 예상합니다.를 반환하는 , 동한결반환사만용지하를 입니다.
filter()
여기서 실제 작업이 덜 분명해집니다.그것을 사용하는 것이 매우 가능할 것입니다.
filter()
첫 번째 경우에도 마찬가지로 (나에게는 명백하게 보이지 않지만), 내 요점은 우리가 그럴 필요가 없다는 것입니다.
여러 열에 대한 집계/업데이트
# case (a) DT[, lapply(.SD, sum), by = z] ## data.table syntax DF %>% group_by(z) %>% summarise_each(funs(sum)) ## dplyr syntax DT[, (cols) := lapply(.SD, sum), by = z] ans <- DF %>% group_by(z) %>% mutate_each(funs(sum)) # case (b) DT[, c(lapply(.SD, sum), lapply(.SD, mean)), by = z] DF %>% group_by(z) %>% summarise_each(funs(sum, mean)) # case (c) DT[, c(.N, lapply(.SD, sum)), by = z] DF %>% group_by(z) %>% summarise_each(funs(n(), mean))
의 경우 , data 함수(a)를 하며, data.table은 함수를 사용합니다.
lapply()
에, 면에반에.dplyr
소합니다를 합니다.*_each()
기하위많기함께과능은한▁to▁along함께▁with▁of▁a▁functions과▁bunch능기.funs()
.의 data.table의
:=
에서는 열 이름을 제공해야 하지만 dplyr은 열 이름을 자동으로 생성합니다.(b)의 경우, dplyr의 구문은 비교적 간단합니다.여러 함수에 대한 집계/업데이트 개선은 data.table의 목록에 있습니다.
은 하만지 (c) dplyr이돌아올경우경우▁return올▁in돌을 반환합니다.
n()
열을 한 번만 사용하는 대신 몇 배나 사용할 수 있습니다.data에서는 data.table의 .j
목록의 각 요소는 결과에서 열이 됩니다.그래서, 우리는 다시 한번 익숙한 기본 함수를 사용할 수 있습니다.c()
을.N
list
은 것은를반다니합환이▁a를 합니다.list
.
번 data에서, 할 은 참고: 다한번시 data.table의 입니다.
j
목록의 각 요소는 결과적으로 열이 됩니다.사용할 수 있습니다.c()
,as.list()
,lapply()
,list()
기타 기본 기능을 사용하여 새로운 기능을 학습할 필요 없이 이를 달성할 수 있습니다.특수변배됩니다우면만수▁just▁the▁-다됩만 배워야 할 입니다.
.N
그리고..SD
적어도.등가 인플라이어는 희귀합니다.n()
그리고..
조인
은 각 한 구문 dplyr 각 조 인 유 형 data . table을 합니다.
DT[i, j, by]
(그리고 이유가 있습니다).또한 동등한 기능을 제공합니다.merge.data.table()
대안으로서 기능합니다.setkey(DT1, x, y) # 1. normal join DT1[DT2] ## data.table syntax left_join(DT2, DT1) ## dplyr syntax # 2. select columns while join DT1[DT2, .(z, i.mul)] left_join(select(DT2, x, y, mul), select(DT1, x, y, z)) # 3. aggregate while join DT1[DT2, .(sum(z) * i.mul), by = .EACHI] DF1 %>% group_by(x, y) %>% summarise(z = sum(z)) %>% inner_join(DF2) %>% mutate(z = z*mul) %>% select(-mul) # 4. update while join DT1[DT2, z := cumsum(z) * i.mul, by = .EACHI] ?? # 5. rolling join DT1[DT2, roll = -Inf] ?? # 6. other arguments to control output DT1[DT2, mult = "first"] ??
은 각 을 훨씬 더 잘 수 반, 반, 등), 다른 를 좋아할 수 있습니다.table's 일왼각조대별기능의도을한에는인찾다부만니있있을수좋수, 습반세등미내부일, ▁some을왼▁for'),▁etc▁much다table▁a있니수습left▁data좋▁semi▁each▁others할▁joins아▁might▁find▁(데등▁nicer기,▁likes일▁function를▁separate는▁might부일터,세이표
DT[i, j, by]
또는merge()
기본 R과 유사합니다.하지만 dplyr join은 그렇게 합니다.그 이상은 아닙니다.그에 못지 않습니다.
는 (에 가입하는 할 수 , 합니다. (2) 데이터가 필요합니다.
select()
두 data.frame 모두에서 먼저 시작한 후 위와 같이 결합합니다.그렇지 않으면 불필요한 열로 조인을 구체화하여 나중에 제거하기만 하면 되므로 비효율적입니다.data.dll은 (3)에 가입하는 동안 집계할 수 있으며 (4)에 가입하는 동안 업데이트할 수도 있습니다. 이 경우 = .EACHI 기능을 사용합니다.전체 조인 결과를 몇 개의 열만 추가/업데이트하는 이유는 무엇입니까?
data.table은 join을 굴릴 수 있습니다(5) - 앞으로 굴림, LOCF, 뒤로 굴림, NOCB, 가장 가까운.
에도 data.table 파일이 있습니다.
mult =
첫 번째, 마지막 또는 모든 일치 항목(6)을 선택하는 인수입니다.data.table에 실수로 잘못된 조인이 발생하지 않도록 보호하는 인수가 있습니다.
한 번,은 한다번말만지, 은다같습다니음과하와 합니다.
DT[i, j, by]
추가 인수를 사용하여 출력을 추가로 제어할 수 있습니다.
do()
...되었습니다.dplyr 요 약 단 값 반 함 특 설 었 습 되 니 다 계 히 별 해 위 를 수 은 는 하 환 을 일 ▁d ▁that습 니함수가 여러 개/비균등 값을 반환하는 경우 다음을 수행해야 합니다.
do()
당신은 당신의 모든 기능 반환 값에 대해 미리 알아야 합니다.DT[, list(x[1], y[1]), by = z] ## data.table syntax DF %>% group_by(z) %>% summarise(x[1], y[1]) ## dplyr syntax DT[, list(x[1:2], y[1]), by = z] DF %>% group_by(z) %>% do(data.frame(.$x[1:2], .$y[1])) DT[, quantile(x, 0.25), by = z] DF %>% group_by(z) %>% summarise(quantile(x, 0.25)) DT[, quantile(x, c(0.25, 0.75)), by = z] DF %>% group_by(z) %>% do(data.frame(quantile(.$x, c(0.25, 0.75)))) DT[, as.list(summary(x)), by = z] DF %>% group_by(z) %>% do(data.frame(as.list(summary(.$x))))
.SD
의 등가물은 의등물은입니다.
data.table에서, 당신은 거의 모든 것을 던질 수 있습니다.
j
목록의 각 요소가 열로 변환되도록 목록을 반환해야 합니다.Dplyr에서는 그렇게 할 수 없습니다.에 의지해야 합니다.
do()
함수가 항상 단일 값을 반환하는지 여부에 대한 확신도에 따라 달라집니다.그리고 그것은 꽤 느립니다.
table의 은 다한번말만, data.table의 구문과 합니다.
DT[i, j, by]
우리는 그냥 계속해서 표현을 할 수 있습니다.j
이런 것들에 대해 걱정할 필요 없이.
이 SO 질문과 이 질문을 살펴 보십시오.dplyr의 구문을 사용하여 답을 직접적으로 표현할 수 있는지 궁금합니다...
요약하자면, 저는 특히 dplyr의 구문이 비효율적이거나 제한적이거나 운영을 단순화하지 못하는 몇 가지 사례를 강조했습니다.이는 특히 data.table이 "읽기/학습하기 더 어려운" 구문(위에 붙여넣기/연결된 구문)에 대해 상당히 반발하기 때문입니다.dplyr을 다루는 대부분의 게시물은 가장 간단한 작업에 대해 말합니다.그리고 그것은 훌륭합니다.그러나 구문과 기능의 한계를 인식하는 것도 중요하며, 아직 게시물을 보지 못했습니다.
data.table에도 고유한 특성이 있습니다(그 중 일부는 수정을 시도하고 있다고 지적했습니다).여기서 강조한 바와 같이 data.table의 조인도 개선하려고 합니다.
그러나 dplyr이 data.table과 비교하여 부족한 기능의 수도 고려해야 합니다.
특징
저는 여기와 이 게시물에서 대부분의 특징을 지적했습니다.추가:
fread - fast 파일 리더는 오랫동안 사용할 수 있었습니다.
fwrite - 이제 병렬화된 빠른 파일 작성기를 사용할 수 있습니다.구현에 대한 자세한 설명을 보려면 이 게시물을 참조하고 추가 개발을 추적하려면 #1664를 참조하십시오.
자동 인덱싱 - 내부적으로 기본 R 구문을 있는 그대로 최적화할 수 있는 또 다른 편리한 기능입니다.
임시 그룹화:
dplyr
다음 기간 동안 변수를 그룹화하여 결과를 자동으로 정렬합니다.summarise()
항상 바람직한 것은 아닐 수도 있습니다.위에서 언급한 data.table join(속도/메모리 효율성 및 구문에 대한)의 다양한 이점.
등각이 아닌 조인:다른 연산자를 사용하여 조인 허용
<=, <, >, >=
joins.data.table join의 .중복 범위 조인이 최근 data.table에 구현되었습니다.벤치마크에 대한 개요를 보려면 이 게시물을 확인하십시오.
setorder()
사용하면 reference..table을 를 매우 할 수 .dplyr은 현재 data.table이 제공하지 않는 동일한 구문을 사용하여 데이터베이스에 대한 인터페이스를 제공합니다.
data.table
더 빠른 세트 작업 속도 제공(Jan Gorecki 지음) -fsetdiff
,fintersect
,funion
그리고.fsetequal
로 로가추▁▁with.all
인수(예: SQL)입니다.data.table은 마스킹 경고 없이 깨끗하게 로드되며 다음을 위해 여기에 설명된 메커니즘을 가지고 있습니다.
[.data.frame
R은 기본 함수 dplyr을 합니다. 함수 dplyr을 변경합니다.filter
,lag
그리고.[
문제를 일으킬 수 있습니다. 예를 들어, 여기와 여기.
마지막으로:
데이터베이스 - data.table이 유사한 인터페이스를 제공할 수 없는 이유는 없지만, 지금은 우선 순위가 아닙니다.만약 사용자들이 그 기능을 매우 좋아한다면, 그것은 실패할 수도 있습니다.확실하진 않다.
평행선에서 - 누군가가 앞으로 나아가서 그것을 하기 전까지는 모든 것이 어렵습니다.물론 (실 안전을 위해) 노력이 필요합니다.
- ▁progress▁forance▁gainsmental▁time▁perform▁using▁consuming다현▁incre▁being있▁(니재▁is▁parts▁parallel1ising▁known를 사용하여 시간이 많이 걸리는 알려진 부분을 병렬화하여 성능 향상시키는 방향으로 .
OpenMP
.
- ▁progress▁forance▁gainsmental▁time▁perform▁using▁consuming다현▁incre▁being있▁(니재▁is▁parts▁parallel1ising▁known를 사용하여 시간이 많이 걸리는 알려진 부분을 병렬화하여 성능 향상시키는 방향으로 .
여기 Arun의 답변의 개요를 따르는 dplyr 관점에서 포괄적인 답변을 시도합니다(그러나 다른 우선순위에 따라 다소 재배열됨).
구문
구문에는 다소 주관적인 부분이 있지만, data.table의 간결함으로 인해 배우기가 더 어렵고 읽기가 더 어려워진다는 제 진술을 고수합니다.이것은 부분적으로 dplyr이 훨씬 더 쉬운 문제를 해결하고 있기 때문입니다!
dplyr가 제공하는 한 가지 정말 중요한 것은 옵션을 제한한다는 것입니다.저는 대부분의 단일 표 문제는 "그룹별" 부사와 함께 다섯 개의 핵심 동사를 필터링하고, 선택하고, 변형하고, 배열하고, 요약하는 것만으로 해결할 수 있다고 주장합니다.이러한 제약은 데이터 조작을 배울 때 큰 도움이 됩니다. 문제에 대한 생각을 정리하는 데 도움이 되기 때문입니다.dplyr에서 이들 동사는 각각 하나의 함수에 매핑됩니다.각 기능은 하나의 작업을 수행하며, 분리되어 이해하기 쉽습니다.
이러한 간단한 작업을 다음과 같이 파이프로 연결하여 복잡성을 만듭니다.%>%
다음은 Arun이 다음에 연결된 게시물 중 하나의 예입니다.
diamonds %>%
filter(cut != "Fair") %>%
group_by(cut) %>%
summarize(
AvgPrice = mean(price),
MedianPrice = as.numeric(median(price)),
Count = n()
) %>%
arrange(desc(Count))
비록 여러분이 dplyr을 전에 본 적이 없더라도, 함수가 모두 영어 동사이기 때문에, 여러분은 여전히 무슨 일이 일어나고 있는지의 요지를 알 수 있습니다.영어 동사의 단점은 타이핑이 더 많이 필요하다는 것입니다.[
더 나은 자동 완성으로 크게 완화될 수 있다고 생각합니다.
다음은 동등한 data.table 코드입니다.
diamondsDT <- data.table(diamonds)
diamondsDT[
cut != "Fair",
.(AvgPrice = mean(price),
MedianPrice = as.numeric(median(price)),
Count = .N
),
by = cut
][
order(-Count)
]
table.data.table에 익숙하지 경우 이이 더 . 된 (반복된)을 구별해야 하는지도 알 수 없었습니다.[
내 눈에는 좋아 보이는 방식으로).개인적으로 제가 6개월 전에 작성한 코드를 보면 마치 낯선 사람이 작성한 코드를 보는 것 같아서, 저는 직설적이지만 장황한 코드를 선호하게 되었습니다.
가독성을 약간 떨어뜨리는 두 가지 다른 작은 요인:
은 거의모데테터이이작다때음사에을용문을 사용하기
[
무슨 일이 일어나고 있는지 알아내기 위해서는 추가적인 맥락이 필요합니다.를 들어, 를들 어예, 는x[y]
두 개의 데이터 테이블을 결합하거나 데이터 프레임에서 열을 추출합니까?잘 작성된 코드에서는 변수 이름이 무슨 일이 일어나고 있는지 암시하기 때문에 이것은 작은 문제일 뿐입니다.는 그것을 .
group_by()
는 dplyr에서 별도의 작업입니다.그것은 근본적으로 계산을 변화시키기 때문에 코드를 스킴할 때 분명해야 하고 더 쉽게 발견할 수 있다고 생각합니다.group_by()
보다 더by
에 대한 인수입니다.[.data.table
.
파이프가 한 패키지에만 국한되지 않는다는 점도 마음에 듭니다.tidyr로 데이터를 정리하는 것으로 시작하여 ggvis로 그래프를 작성할 수 있습니다.그리고 여러분은 제가 작성하는 패키지에 국한되지 않습니다. 누구나 데이터 조작 파이프의 매끄러운 부분을 형성하는 기능을 작성할 수 있습니다.사실, 나는 오히려 이전의 data.table code를 더 좋아합니다.%>%
:
diamonds %>%
data.table() %>%
.[cut != "Fair",
.(AvgPrice = mean(price),
MedianPrice = as.numeric(median(price)),
Count = .N
),
by = cut
] %>%
.[order(-Count)]
그리고 파이핑을 한다는 생각은%>%
데이터 프레임에만 국한되지 않고 대화형 웹 그래픽, 웹 스크래핑, 지스트, 런타임 계약 등 다른 컨텍스트로 쉽게 일반화됩니다.
메모리 및 성능
저는 이것들을 함께 분류했습니다. 왜냐하면, 저에게, 그것들은 그렇게 중요하지 않기 때문입니다.대부분의 R 사용자는 100만 행 미만의 데이터를 처리하며, dplyr은 처리 시간을 모르는 데이터 크기에 충분히 빠릅니다.우리는 중간 데이터에 대한 표현력을 위해 공급자를 최적화했습니다. 더 큰 데이터에 대한 원시 속도를 위해 data.table을 자유롭게 사용하십시오.
또한 dplyr의 유연성은 동일한 구문을 사용하여 성능 특성을 쉽게 조정할 수 있음을 의미합니다.데이터 프레임 백엔드에서 dplyr의 성능이 충분하지 않으면 data.table 백엔드를 사용할 수 있습니다(기능 집합이 다소 제한되어 있음에도 불구하고).작업 중인 데이터가 메모리에 맞지 않으면 데이터베이스 백엔드를 사용할 수 있습니다.
즉, dplyr의 성능은 장기적으로 향상될 것입니다.우리는 radix 주문 및 조인 및 필터에 동일한 인덱스를 사용하는 것과 같은 data.table의 훌륭한 아이디어 중 일부를 확실히 구현할 것입니다.또한 여러 코어를 활용할 수 있도록 병렬화 작업도 진행하고 있습니다.
특징들
2015년에 작업할 예정인 몇 가지 사항:
그자리의
readr
이동할 수 위해 지패키디, 에쉽메가파와 합니다.fread()
.비균등 결합 지원을 포함하여 보다 유연한 결합.
부트스트랩 샘플, 롤업 등 보다 유연한 그룹화
저는 또한 R의 데이터베이스 커넥터를 개선하고 웹 아피스와 대화할 수 있으며 HTML 페이지를 쉽게 스크랩할 수 있도록 하는 데 시간을 투자하고 있습니다.
질문 제목에 대한 직접적인 응답...
dplyr
분명히 하는 일들을 합니다.data.table
수 없다.
당신의 요점 #3
dplyr은 잠재적인 DB 상호 작용을 추상화(또는 추상화)합니다.
자신의 질문에 대한 직접적인 대답이지만 충분히 높은 수준으로 올라가지 않았습니다. dplyr
다양한 데이터 스토리지 메커니즘으로 확장 가능한 프런트 엔드입니다.data.table
는 단일 항목의 확장입니다.
를 .dplyr
모든 대상이 동일한 문법을 사용하여 원하는 대로 대상과 핸들러를 확장할 수 있는 백엔드 독립 인터페이스입니다. data.table
는에서, 서에입니다.dplyr
원근법, 그 대상 중 하나.
은 절대로 그런 볼 수 .data.table
에서는 쿼리를 변환하여 온 디스크 또는 네트워크 데이터 저장소에서 작동하는 SQL 문을 생성하려고 합니다.
dplyr
수 일이 있을 수도 있습니다.data.table
그렇지 않을 수도 있고 그렇지 않을 수도 있습니다.
in memory의 을 바탕으로 ,data.table
이 쿼의 병처 확는더 어있수 다습니울려보다 더 수 있습니다.dplyr
.
체내 질문에 대한 답변은...
사용.
패키지에 익숙한 사용자를 위해 하나 또는 다른 패키지로 코딩하기 훨씬 쉬운 분석 작업이 있습니까? (즉, 필요한 키 입력과 필요한 비밀 수준의 조합이 있습니다. 각각의 키 입력이 적은 것이 좋습니다.)
이것은 말장난처럼 보일지 모르지만 진짜 대답은 아니오입니다.도구에 익숙한 사람들은 가장 친숙한 것이나 실제로 당면한 작업에 적합한 것을 사용하는 것 같습니다.이와 같이, 때로는 특정 가독성, 때로는 성능 수준을 제시하고 싶을 때, 두 가지 모두에 대해 충분히 높은 수준이 필요할 때, 이미 더 명확한 추상화를 수행해야 하는 것과 함께 다른 도구가 필요할 수도 있습니다.
성능
다른 패키지보다 한 패키지에서 실질적으로(즉, 2배 이상) 더 효율적으로 수행되는 분석 작업이 있습니까?
다시, 아니. data.table
모든 일에서 효율적이라는 점에서 뛰어납니다.dplyr
기본 데이터 저장소 및 등록된 처리기로 제한되는 부담이 있습니다.
즉, 다음과 같은 성능 문제가 발생할 경우data.table
당신은 그것이 당신의 쿼리 기능에 있고 그것이 실제로 병목 현상인지 꽤 확신할 수 있습니다.data.table
그러면 당신은 보고서를 제출하는 기쁨을 얻었습니다.이는 다음과 같은 경우에도 해당됩니다.dplyr
중입니다.data.table
백엔드로서; 당신은 약간의 간접비를 볼 수 있습니다.dplyr
하지만 당신의 질문일 가능성이 높습니다.
때dplyr
에서는 하이브리드 평가를 위해 기능을 등록하거나(데이터베이스의 경우) 실행 전에 생성된 쿼리를 조작하여 해결할 수 있는 백엔드 관련 성능 문제가 있습니다.
또한 언제가 data.table보다 나은지에 대한 승인된 답변을 보십시오.
해들리와 아룬의 대답을 읽으면 선호하는 사람들이 있다는 인상을 받습니다.dplyr
의구은경따다전음환됩니다로로 data.table
또는 장시간 실행 시 성능 저하가 발생할 수 있습니다.
몇몇 했듯이, 하만몇몇사이언미이듯급했이람들지,,dplyr
사용할 수 있습니다.data.table
백엔드로서이 작업은 다음을 사용하여 수행됩니다.dtplyr
최근 버전 1.0.0 릴리스의 패키지입니다.학습dtplyr
실질적으로 추가적인 노력이 전혀 필요하지 않습니다.
을 할 때dtplyr
는 기을사용니다합 기능을 합니다.lazy_dt()
table을 그에 standard가 data.table을 배치했습니다.dplyr
구문은 해당 구문에 대한 작업을 지정하는 데 사용됩니다.이는 다음과 같습니다.
new_table <- mtcars2 %>%
lazy_dt() %>%
filter(wt < 5) %>%
mutate(l100k = 235.21 / mpg) %>% # liters / 100 km
group_by(cyl) %>%
summarise(l100k = mean(l100k))
new_table
#> Source: local data table [?? x 2]
#> Call: `_DT1`[wt < 5][, `:=`(l100k = 235.21/mpg)][, .(l100k = mean(l100k)),
#> keyby = .(cyl)]
#>
#> cyl l100k
#> <dbl> <dbl>
#> 1 4 9.05
#> 2 6 12.0
#> 3 8 14.9
#>
#> # Use as.data.table()/as.data.frame()/as_tibble() to access results
그new_table
.as.data.table()
/as.data.frame()
/as_tibble()
그 기초가 되는 지점에서.data.table
작업이 실행됩니다.
벤치마크 분석을 다시 작성했습니다.data.table
작가 맷 다우는 2018년 12월에 많은 수의 그룹에 대한 운영 사례를 다루었습니다.나는 그것을 발견했습니다.dtplyr
실제로 대부분의 부분에서 그것을 선호하는 사람들을 가능하게 합니다.dplyr
에서 제공하는 속도를 즐기는 동안 계속 사용하는 구문data.table
.
저는 data.table로 시작했지만, dplyr을 사용하여 작업 팀을 수용했습니다(그리고 구문이 더 좋기 때문입니다).둘 다 체인 때문에 디버깅하기가 어렵습니다.중요한 제한 사항은 두 가지 모두 두 개 이상의 행 또는 열에서 정보를 필요로 하는 계산과 씨름한다는 것입니다.data.table의 경우 mapply, map 또는 lapply와 함께 추가된 인수를 사용하여 둘 이상의 열의 함수를 수행할 수 있습니다.저는 dplyr에서 그것을 추구하지는 않았지만, 가능하다고 생각합니다.하지만 다른 행에 있는 정보를 직접 가리켜서 계산할 수 있는 응용 프로그램 방법을 찾지 못하고 있습니다.이 작업은 data.table에서 DT[, DDspawn := DD - .와 같이 수행할 수 있습니다.예를 들어 SD[jday==Jday.spaw, 'DD'], by=by]를 사용합니다.저는 데이터베이스 용어로 이 기능을 '직접 액세스'라고 생각하지만, 저는 전문가 아닙니다.어플라이드 방법이 있나요?lag 기능이 있어서 가능해야 하는데, 이 inplyr을 할 구문을 찾지 못하고 있습니다.
언급URL : https://stackoverflow.com/questions/21435339/data-table-vs-dplyr-can-one-do-something-well-the-other-cant-or-does-poorly
'programing' 카테고리의 다른 글
Core Animation으로 사용자 지정 완화 기능을 만드는 방법은 무엇입니까? (0) | 2023.07.06 |
---|---|
연속 어레이와 비연속 어레이의 차이점은 무엇입니까? (0) | 2023.07.06 |
유성에서 mongodb skip()와 limit()를 사용하는 방법은 무엇입니까? (0) | 2023.07.06 |
루비로 된 디렉토리에서 모든 파일을 요구하는 가장 좋은 방법은 무엇입니까? (0) | 2023.07.06 |
MySqlariaDB CREATE FUNCTION DELMITER가 작동하지 않습니다.근처에 오류가 있습니다. (0) | 2023.07.06 |