R) 전처리 - 상위 n개 데이터 추출

R) 전처리 - 상위 n개 데이터 추출

고객 구매 데이터에서 가장 비싼 상품순으로 n개를 뽑아내려면 어떻게 할까? 고객의 구매력 평가를 위해 구매물품의 평균을 구하는 것 보다 구매한 비싼 물건을 살펴보는 것이 유용할때가 있다.

문제 상황

특정 데이터프레임의 원소의 서열이 있고 복수개가 묶여있을 때 n번째 순위의 원소만 추출하는 전처리 예제를 알아보자.
테이블이 다음과 같이 두 개 주어져 있을 때 상위 n개의 원소를 추출하여 정리해야 한다고 하자.
조건

데이터 준비

먼저 각 타입별 순위 정보가 있는 데이터프레임을 만들어보자.

1
2
3
4
5
6
7
8
9
df_rank = data.frame(type = LETTERS[1:5],
rank = c(5, 3, 1, 4, 2))
df_rank
## type rank
## 1 A 5
## 2 B 3
## 3 C 1
## 4 D 4
## 5 E 2

다음으로 임의의 타입이 묶여있는 데이터프레임을 만들어보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vec_c = c()
set.seed(10)
for(n in 1:5){
vec_c_sub = sample(LETTERS[1:5],
size = sample(2:5, size = 1),
replace = FALSE)
vec_c = c(vec_c, paste(vec_c_sub, collapse = ","))
}
df_c = data.frame(log = vec_c)
df_c
## log
## 1 A,B,C,D
## 2 C,D,E
## 3 B,C,E,D
## 4 E,C,B,A,D
## 5 C,B,D,A

빠른 전처리를 위해 정렬을 해준다.

1
2
3
4
5
6
7
8
df_rank = df_rank[order(-df_rank$rank), ]
df_rank
## type rank
## 1 A 5
## 4 D 4
## 2 B 3
## 5 E 2
## 3 C 1

Unit Test

이 코드의 핵심은 상위 n개를 사용하기 위해 정렬을 사용하지 않고 factor의 특성을 활용하여 처리하는 것이다. factor() 함수에서 보통 lebel 인자를 사용하는데 여기서는 순위를 정확하게 지정하기 위해 levels 인자를 사용하며 미리 정렬을 한 데이터를 활용하였다.

1
2
3
4
5
vec_split = unlist(strsplit(df_c[1, 1], split = ","))
fac = factor(vec_split,
levels = df_rank$type[df_rank$type %in% vec_split])
paste(fac[as.numeric(fac) <= 2], collapse = ",")
## [1] "A,D"

반복문

조금 비효율적일 수 있으나 반복문을 적용하면 다음과 같다. 이 방법은 대용량 데이터의 경우 시간이 꽤 오래걸리니 주의하도록 하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
for(n in 1:nrow(df_c)){
vec_split = unlist(strsplit(df_c[n, 1], split = ","))
fac = factor(vec_split,
levels = df_rank$type[df_rank$type %in% vec_split])
df_c[n, "top_n"] = paste(fac[as.numeric(fac) <= 2], collapse = ",")
}
df_c
## log top_n
## 1 A,B,C,D A,D
## 2 C,D,E D,E
## 3 B,C,E,D B,D
## 4 E,C,B,A,D A,D
## 5 C,B,D,A D,A

apply() 함수

앞의 반복문의 속도를 더 올리기 위해서 사용자 정의 함수와 apply() 함수를 적용하면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ext_top_n = function(x, top = 2){
vec_split = unlist(strsplit(x, split = ","))
fac = factor(vec_split,
levels = df_rank$type[df_rank$type %in% vec_split])
return(paste(fac[as.numeric(fac) <= 2], collapse = ","))
}

df_c[, "top_n_udf"] = apply(df_c["log"], MARGIN = 1, FUN = "ext_top_n")
df_c
## log top_n top_n_udf
## 1 A,B,C,D A,D A,D
## 2 C,D,E D,E D,E
## 3 B,C,E,D B,D B,D
## 4 E,C,B,A,D A,D A,D
## 5 C,B,D,A D,A D,A

벤치마킹

상기 코드를 기반으로 100000만 row를 대상으로 벤치마크를 한 결과는 다음과 같다.
● 반복문: Time difference of 50.37027 secs
apply() 함수: Time difference of 8.172626 secs

apply() 함수가 약 7배 정도 빠르다는 것을 알 수 있다.

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×