R) 전처리 - 게임 케릭터 픽 데이터 정제

R) 전처리 - 게임 케릭터 픽 데이터 정제

게임에서 유저가 어떤 케릭터를 골랐을까? 주어진 데이터 정제 실습을 초급/중급/고급 으로 나누어 알아보자.

본 내용은 임의로 생성한 두 데이터를 사용한다. 첫 번째는 정제 대상 데이터이고, 두 번째는 정제 후 데이터이다.
preprocessing_counting_character_pick.csv 다운받기 [클릭]
preprocessing_counting_character_pick_count.csv 다운받기 [클릭]

다음과 같은 데이터가 주어졌다고 하자.

1
2
3
4
5
6
7
8
df = read.csv("preprocessing_counting_character_pick.csv")
head(df)
## name yyyymm round_1 round_2 round_3 round_4 round_5 round_6 round_7
## 1 김승욱 202001 C B A C C A C
## 2 송유진 202001 C A C C C D A
## 3 박준교 202001 C B D A D D C
## 4 김용훈 202001 B C B D A C B
## 5 김승욱 202002 C D C C C A D

각 round별로 유저가 특정 일자에 픽한 케릭터가 A 부터 D 까지 있다. 여기서 각 유저가 월별로 어떤 케릭터를 몇 번 골랐는지 정제를 해보려고 한다. 물론 실제 로그 파일은 JSON 형식에 훨씬 복잡한 상태가 되겠다. 여기서 사용하는 데이터는 해당 JSON에서 가공되었고 특수한 형태로 이쁘게 테이블 형태를 유지하고 있는 것이라고 가정한다.

참고로 본 코드는 초급부터 초급 수준이라고 하기에는 약간 난이도가 있는 편이다.

초급

우선 첫 번째 row의 케릭터 픽만 정제해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
table(as.character(df[1, 3:9])) # 1
## A B C
## 2 1 4

table(unlist(df[1, 3:9])) # 2
## A B C
## 2 1 4

as.data.frame(table(unlist(df[1, 3:9]))) # 3
## Var1 Freq
## 1 A 2
## 2 B 1
## 3 C 4

1번 코드와 2번 코드는 결과가 같은데 데이터프레임은 list의 특수한 형태이기 때문에 2번 코드처럼 unlist() 함수를 사용할 수 있다. 1번 코드의 경우 강제로 문자로 변환하기 때문에 어떻게 보면 unlist() 함수를 사용하는 2번 코드가 더 적절할 수 있다. 아무튼 3번 코드의 경우 이를 데이터프레임으로 바꾼 결과이다. 3번 코드를 기반으로 다음의 코드를 작성하고자 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
df_cnt = data.frame()
for(n in 1:nrow(df)){
df_cnt_sub = as.data.frame(table(unlist(df[n, 3:9])))
df_cnt_sub[, "name" ] = df[n, "name" ]
df_cnt_sub[, "yyyymm"] = df[n, "yyyymm"]
df_cnt = rbind(df_cnt, df_cnt_sub)
}
head(df_cnt, 2)
## Var1 Freq name yyyymm
## 1 A 2 김승욱 202001
## 2 B 1 김승욱 202001

df_cnt = df_cnt[, c(3, 4, 1, 2)]
colnames(df_cnt)[3:4] = c("char", "count")
head(df_cnt)
## name yyyymm char count
## 1 김승욱 202001 A 2
## 2 김승욱 202001 B 1
## 3 김승욱 202001 C 4
## 4 송유진 202001 A 2
## 5 송유진 202001 C 4
## 6 송유진 202001 D 1

for 반복문으로 한 줄씩 표로 정제하여 그 결과를 rbind() 함수로 하나씩 이어붙인 코드이다. 그리고 모양새를 맞추기 위해서 변수이동을 하고 변수명을 변경하였다.

중급

초급 보다 코드는 좀 더 길다. 여기서는 apply() 함수, 람다함수, 피보팅을 섞어서 난이도가 조금 더 높은 편이라고 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
df = read.csv("preprocessing_counting_character_pick.csv")
head(df)
## name yyyymm round_1 round_2 round_3 round_4 round_5 round_6 round_7
## 1 김승욱 202001 C B A C C A C
## 2 송유진 202001 C A C C C D A
## 3 박준교 202001 C B D A D D C
## 4 김용훈 202001 B C B D A C B
## 5 김승욱 202002 C D C C C A D

list_char = unique(unlist(df[, 3:ncol(df)]))
list_char = list_char[order(list_char)]
for(char in list_char){
df[, paste0("char_", char)] = apply(df[, 3:ncol(df)],
MARGIN = 1,
FUN = function(x){sum(x == char)})
}
head(df, 2)
## name yyyymm round_1 round_2 round_3 round_4 round_5 round_6 round_7 char_A char_B char_C char_D
## 1 김승욱 202001 C B A C C A C 2 1 4 0
## 2 송유진 202001 C A C C C D A 2 0 4 1

library("reshape2")
df_melt = melt(data = df[, -(3:9)], id.vars = c("name", "yyyymm"),
variable.name = "char", value.name = "count")
df_melt[, "char"] = gsub(pattern = "char_", replacement = "", df_melt$char)
head(df_melt)
## name yyyymm char count
## 1 김승욱 202001 A 2
## 2 송유진 202001 A 2
## 3 박준교 202001 A 1
## 4 김용훈 202001 A 1
## 5 김승욱 202002 A 1
## 6 송유진 202002 A 2

초급과 조금 다른 점은 반복문을 각 row가 아니라 케릭터의 개수에 초점을 두었다. 케릭터 별로 개수 apply() 함수를 활용하여 세고 케릭터 개수 만큼 새로운 변수를 만들었다. 이 때, 케릭터 개수가 매우 많다면 column 개수가 많아지기 때문에 실무에서는 메모리 관리에 주의해야 한다.

melt() 함수를 사용한 시점에서는 각 케릭터별 픽 횟수가 있는 “char_” 접두사의 변수를 타겟으로 피보팅을 하였다.

고급

코드가 복잡하고 어려운 함수를 사용한다고 해서 마냥 난이도가 높은 것은 아니다. 여기에서는 melt() 함수와 aggregate() 함수만으로 처리하는데 이게 가능하게 해주는 것이 중간 즈음의 코드에서 새로 만드는 변수 “count” 이다. 이를 추가함으로써 각 케릭터 픽의 셈이 수월해진다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
df = read.csv("preprocessing_counting_character_pick.csv")
head(df)
## name yyyymm round_1 round_2 round_3 round_4 round_5 round_6 round_7
## 1 김승욱 202001 C B A C C A C
## 2 송유진 202001 C A C C C D A
## 3 박준교 202001 C B D A D D C
## 4 김용훈 202001 B C B D A C B
## 5 김승욱 202002 C D C C C A D

df_melt = melt(data = df, id.vars = c("name", "yyyymm"))
df_melt[, "count"] = 1
head(df_melt)
## name yyyymm variable value count
## 1 김승욱 202001 round_1 C 1
## 2 송유진 202001 round_1 C 1
## 3 박준교 202001 round_1 C 1
## 4 김용훈 202001 round_1 B 1
## 5 김승욱 202002 round_1 C 1
## 6 송유진 202002 round_1 B 1

df_melt_agg = aggregate(data = df_melt, count ~ name + yyyymm + value, FUN = "sum")
head(df_melt_agg)
## name yyyymm value count
## 1 김승욱 202001 A 2
## 2 김용훈 202001 A 1
## 3 박준교 202001 A 1
## 4 송유진 202001 A 2
## 5 김승욱 202002 A 1
## 6 김용훈 202002 A 2

다음은 dplyr 패키지 활용 버전이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
df = read.csv("preprocessing_counting_character_pick.csv")
head(df)
## name yyyymm round_1 round_2 round_3 round_4 round_5 round_6 round_7
## 1 김승욱 202001 C B A C C A C
## 2 송유진 202001 C A C C C D A
## 3 박준교 202001 C B D A D D C
## 4 김용훈 202001 B C B D A C B
## 5 김승욱 202002 C D C C C A D

df_melt = melt(data = df, id.vars = c("name", "yyyymm"))

library("dplyr")
df_melt %>%
group_by(name, yyyymm, value) %>%
summarise(count = n()) -> df_group_cnt

head(df_group_cnt)
## # A tibble: 6 x 4
## # Groups: name, yyyymm [2]
## name yyyymm value count
## <chr> <int> <chr> <int>
## 1 김승욱 202001 A 2
## 2 김승욱 202001 B 1
## 3 김승욱 202001 C 4
## 4 김승욱 202002 A 1
## 5 김승욱 202002 C 4
## 6 김승욱 202002 D 2
Your browser is out-of-date!

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

×