R) 전처리 - 마트 데이터 전처리-01

R) 전처리 - 마트 데이터 전처리-01

매출 DB에서 프로모션 대상 상품을 구매한 고객을 찾아내고자 한다. R을 활용해서 어떻게 해결할 수 있는지 알아보자.

데이터 준비

다음과 같이 데이터가 있다고 하자.

ID: 고객 ID
Prod: 구매 제품명

1
2
3
4
5
6
7
8
9
10
11
12
df = data.frame(ID = c("3912A41", "3912A41", "4353B21", "4353B21", "4353B21", "REG1242", "REG1242", "ADM1239"),
Prod = c("사과", "바나나", "사과", "바나나", "토마토", "사과", "바나나", "바나나"))
df
## ID Prod
## 1 3912A41 사과
## 2 3912A41 바나나
## 3 4353B21 사과
## 4 4353B21 바나나
## 5 4353B21 토마토
## 6 REG1242 사과
## 7 REG1242 바나나
## 8 ADM1239 바나나

문제 상황

프로모션 대상 상품인 사과바나나라고 해당 제품을 구매한 사람을 찾아내고자 한다.

풀이

단순히 특정 상품을 구매한 경우를 생각할 수 있으나 이는 다음과 같이 세 가지 경우의 수가 있다.

● 프로모션 상품을 하나라도 구매한 경우
● 프로모션 상품을 모두 구매한 경우
● 프로모션 상품만 구매한 경우

각 상황에 따라 어떻게 코드를 작성하는지 알아보자.

프로모션 상품을 하나라도 구매한 경우

먼저 프로모션 상품인지 아닌지 구분하는 “is_target” 변수를 만들어보자. 이 때 ifelse() 함수를 활용할 수 있지만 논리값(TRUE, FALSE)의 속성을 활용해 결과에 0을 더해 숫자로 자동 형변환이 되도록 했다.

1
2
3
4
5
6
7
8
9
10
11
df[, "is_target"] = (df$Prod %in% c("사과", "바나나")) + 0
df
## ID Prod is_target
## 1 3912A41 사과 1
## 2 3912A41 바나나 1
## 3 4353B21 사과 1
## 4 4353B21 바나나 1
## 5 4353B21 토마토 0
## 6 REG1242 사과 1
## 7 REG1242 바나나 1
## 8 ADM1239 바나나 1

상품을 하나라도 구매했으면 1만 있고, 그렇지 않은 경우 0만 있기 때문에 최대값을 알아보는 방식으로 접근할 수 있으며 코드는 다음과 같다.

1
2
3
4
5
6
aggregate(data = df, is_target ~ ID, FUN = "max")
## ID is_target
## 1 3912A41 1
## 2 4353B21 1
## 3 ADM1239 1
## 4 REG1242 1

프로모션 상품을 모두 구매한 경우

프로모션 상품이 2개이기 때문에 “is_target” 변수의 합이 2인 경우를 확인하면 되고, 코드는 다음과 같다.

1
2
3
4
5
6
aggregate(data = df, is_target ~ ID, FUN = "sum")
## ID is_target
## 1 3912A41 2
## 2 4353B21 2
## 3 ADM1239 1
## 4 REG1242 2

lambda 함수로 한 번에 처리하는 코드는 다음과 같다.

1
2
3
4
5
6
aggregate(data = df, is_target ~ ID, FUN = function(x){(sum(x) == 2) + 0})
## ID is_target
## 1 3912A41 1
## 2 4353B21 1
## 3 ADM1239 0
## 4 REG1242 1

단, 현재 데이터가 특정 상품을 한 번만 구매한것과 같은 형식이기 때문에 실제 데이터에서 이 형식으로 만들고자 할 경우 unique() 같은 함수로 중복제거를 먼저 실시해야 하겠다.

프로모션 상품만 구매한 경우

문제 해결을 위한 여러 버전의 코드가 있을 수 있는데 핵심은 각 고객의 row 개수와 프로모션 상품을 구매한 개수가 같아야 한다는 것이다. 파생변수를 활용한 방법을 먼저 알아보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
df[, "cnt"] = 1
head(df, 2)
## ID Prod is_target cnt
## 1 3912A41 사과 1 1
## 2 3912A41 바나나 1 1
df_agg = aggregate(data = df[, -2], . ~ ID, FUN = "sum")
df_agg
## ID is_target cnt
## 1 3912A41 2 2
## 2 4353B21 2 3
## 3 ADM1239 1 1
## 4 REG1242 2 2
df_agg[, "p_check"] = ifelse(test = (df_agg$is_target >= 2) & (df_agg$is_target == df_agg$cnt),
yes = 1, no = 0)
df_agg
## ID is_target cnt p_check
## 1 3912A41 2 2 1
## 2 4353B21 2 3 0
## 3 ADM1239 1 1 0
## 4 REG1242 2 2 1

상기 코드 중 ifelse() 함수의 “test” 인자에 조건을 2개 지정했는데 이 부분을 잘 보아야 한다. 첫 번째 조건을 생략한다면 프로모션 상품만 구매한 것을 골라낼 수 있긴 하지만 모든 프로모션 상품을 구매한 사람을 걸러낼 수 없다.

이번엔 “is_target” 변수를 활용하지 않고 사용자 정의 함수를 활용하여 해결해보자.

1
2
3
4
5
6
7
8
9
10
11
12
target_checker = function(x){
ifelse(test = (length(x) >= 2) & (length(x) == sum(x %in% c("사과", "바나나"))),
yes = 1,
no = 0)
}

aggregate(data = df, Prod ~ ID, FUN = "target_checker")
## ID Prod
## 1 3912A41 1
## 2 4353B21 0
## 3 ADM1239 0
## 4 REG1242 1

사용자 정의 함수를 좀 더 고도화 해보자. 프로모션 상품이 반드시 2개라는 보장이 없기 때문에 사용자 정의 함수의 입력에 “prods” 인자를 추가하여 프로모션 상품 정보를 입력받도록 한 target_checker_v2() 함수를 사용한 예제는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
target_checker_v2 = function(x, prods){
ifelse(test = (length(x) >= length(prods)) & (length(x) == sum(x %in% prods)),
yes = 1,
no = 0)
}


aggregate(data = df, Prod ~ ID, FUN = "target_checker_v2",
prods = c("사과", "바나나"))
## ID Prod
## 1 3912A41 1
## 2 4353B21 0
## 3 ADM1239 0
## 4 REG1242 1
Your browser is out-of-date!

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

×