데이터 사이언스 100번의 노크(구조화 데이터 처리편) – R Part 3 (Q41 to Q60)의 해설입니다.
참고(Reference) : 「데이터 사이언티스트 협회 스킬 정의 위원」의 「데이터 사이언스 100번의 노크(구조화 데이터 처리편)」입니다.
처음에
- 먼저 다음 셀을 실행합니다.
- 필요한 라이브러리를 가져오고 데이터베이스에서 데이터를 읽습니다(PostgreSQL).
- 사용할 것으로 예상되는 라이브러리는 다음 셀에서 가져옵니다.
- 사용하려는 다른 라이브러리가 있는 경우 install.packages()를 사용하여 적절하게 설치합니다.
- 이름, 주소 등은 더미 데이터이며 실제 데이터가 아닙니다.
require("RPostgreSQL")
require("tidyr")
require("dplyr")
require("stringr")
require("caret")
require("lubridate")
require("rsample")
require("recipes")
require("themis")
host <- "db"
port <- Sys.getenv()["PG_PORT"]
dbname <- Sys.getenv()["PG_DATABASE"]
user <- Sys.getenv()["PG_USER"]
password <- Sys.getenv()["PG_PASSWORD"]
con <- dbConnect(PostgreSQL(), host=host, port=port, dbname=dbname, user=user, password=password)
df_customer <- dbGetQuery(con,"SELECT * FROM customer")
df_category <- dbGetQuery(con,"SELECT * FROM category")
df_product <- dbGetQuery(con,"SELECT * FROM product")
df_receipt <- dbGetQuery(con,"SELECT * FROM receipt")
df_store <- dbGetQuery(con,"SELECT * FROM store")
df_geocode <- dbGetQuery(con,"SELECT * FROM geocode")
Loading required package: RPostgreSQL Loading required package: DBI Loading required package: tidyr Loading required package: dplyr Attaching package: ‘dplyr’ The following objects are masked from ‘package:stats’: filter, lag The following objects are masked from ‘package:base’: intersect, setdiff, setequal, union Loading required package: stringr Loading required package: caret Loading required package: ggplot2 Loading required package: lattice Loading required package: lubridate Attaching package: ‘lubridate’ The following objects are masked from ‘package:base’: date, intersect, setdiff, union Loading required package: rsample Loading required package: recipes Attaching package: ‘recipes’ The following object is masked from ‘package:stringr’: fixed The following object is masked from ‘package:stats’: step Loading required package: themis Registered S3 methods overwritten by 'themis': method from bake.step_downsample recipes bake.step_upsample recipes prep.step_downsample recipes prep.step_upsample recipes tidy.step_downsample recipes tidy.step_upsample recipes tunable.step_downsample recipes tunable.step_upsample recipes Attaching package: ‘themis’ The following objects are masked from ‘package:recipes’: step_downsample, step_upsample
연습문제
R-041: 영수증 내역 데이터(df_receipt)의 매출 금액(amount)을 날짜(sales_ymd)별로 집계하여, 지난번 매출이 있었던 날로부터의 매출 금액 증감을 계산하라. 그리고 결과를 10건 표시하라.
df_receipt %>%
group_by(sales_ymd) %>%
summarise(sum_amount = sum(amount), .groups = "drop") %>%
mutate(lag_ymd = lag(sales_ymd), lag_amount = lag(sum_amount), diff_amount = sum_amount - lag_amount) %>%
slice(1:10)
sales_ymd | sum_amount | lag_ymd | lag_amount | diff_amount |
---|---|---|---|---|
<int> | <int> | <int> | <int> | <int> |
20170101 | 33723 | NA | NA | NA |
20170102 | 24165 | 20170101 | 33723 | -9558 |
20170103 | 27503 | 20170102 | 24165 | 3338 |
20170104 | 36165 | 20170103 | 27503 | 8662 |
20170105 | 37830 | 20170104 | 36165 | 1665 |
20170106 | 32387 | 20170105 | 37830 | -5443 |
20170107 | 23415 | 20170106 | 32387 | -8972 |
20170108 | 24737 | 20170107 | 23415 | 1322 |
20170109 | 26718 | 20170108 | 24737 | 1981 |
20170110 | 20143 | 20170109 | 26718 | -6575 |
설명:
이 코드는 R의 dplyr 패키지를 사용하여 df_receipt라는 데이터 프레임을 조작하고 있다. 아래는 이 코드가 수행하는 작업을 단계별로 설명한다.
df_receipt %>% - R의 파이프 연산자로 df_receipt 데이터 프레임을 파이프 라인의 다음 함수에 첫 번째 인수로 전달한다.
group_by(sales_ymd) %>% - sales_ymd 컬럼으로 데이터 프레임을 그룹화한다(날짜 또는 날짜 시간 데이터 포함). 연산자 %>%는 그룹화된 데이터 프레임을 파이프라인의 다음 함수로 보냅니다.
summarise(sum_amount = sum(amount), .groups = "drop") %>% - 그룹화된 데이터 프레임을 요약하고 고유한 sales_ymd 그룹별로 금액 열의 합계를 계산한다. 결과 데이터 프레임에는 sales_ymd와 sum_amount 두 개의 열이 있다. .groups = "drop" 인수는 group_by에서 추가한 그룹화 정보가 더 이상 필요하지 않으므로 이를 삭제하는 데 사용됩니다. 연산자 %>%는 이 요약된 데이터 프레임을 파이프라인의 다음 함수로 다시 파이프한다.
mutate(lag_ymd = lag(sales_ymd), lag_amount = lag(sum_amount), diff_amount = sum_amount - lag_amount) %>% - 요약된 데이터 프레임에 새로운 3개의 열을 추가한다. 처음 두 열인 lag_ymd와 lag_amount는 각각 sales_ymd와 sum_amount 열의 지연 값을 포함하고, 세 번째 열인 diff_amount는 sum_amount와 lag_amount 열의 차이를 저장한다. 연산자 %>%는 이 수정된 데이터 프레임을 파이프라인의 다음 함수로 보낸다.
slice(1:10) - 수정된 데이터 프레임의 처음 10개의 행을 선택한다. 결과 데이터 프레임은 sales_ymd, sum_amount, lag_ymd, lag_amount, diff_amount 열을 가지며, 원래의 df_receipt 데이터 프레임을 그룹화, 요약 및 수정한 후 처음 10개의 행을 포함하게 된다.
전체적으로 이 코드는 매출 데이터에 대해 일종의 시계열 분석을 수행하여 각 날짜의 매출 합계를 계산하고 각 날짜의 매출과 전날의 매출 차이를 계산한다. 결과 데이터 프레임은 일일 매출의 시간 경과에 따른 추세를 파악할 수 있어야 한다.
R-042: 영수증 내역 데이터(df_receipt)의 매출 금액(amount)을 날짜(sales_ymd)별로 집계하고, 각 날짜의 데이터에 대해 이전, 전전, 3회 전에 매출이 있었던 날의 데이터를 결합하라. 그리고 결과를 10건 표시하라.
# 코드 예시 1: 세로형 케이스
df_sum <-df_receipt %>%
group_by(sales_ymd) %>%
summarise(sum_amount = sum(amount), .groups = "drop")
for (i in 1:3) {
df_tmp <- df_sum %>%
mutate(lag_ymd = lag(sales_ymd, n = i),
lag_amount = lag(sum_amount, n = i))
if (i == 1) {
df_lag <- df_tmp
}
else {
df_lag <- rbind(df_lag, df_tmp)
}
}
df_lag %>%
drop_na(everything()) %>%
arrange(sales_ymd, lag_ymd) %>%
slice(1:10)
sales_ymd | sum_amount | lag_ymd | lag_amount |
---|---|---|---|
<int> | <int> | <int> | <int> |
20170102 | 24165 | 20170101 | 33723 |
20170103 | 27503 | 20170101 | 33723 |
20170103 | 27503 | 20170102 | 24165 |
20170104 | 36165 | 20170101 | 33723 |
20170104 | 36165 | 20170102 | 24165 |
20170104 | 36165 | 20170103 | 27503 |
20170105 | 37830 | 20170102 | 24165 |
20170105 | 37830 | 20170103 | 27503 |
20170105 | 37830 | 20170104 | 36165 |
20170106 | 32387 | 20170103 | 27503 |
설명:
이 코드도 R의 dplyr 패키지를 사용하여 df_receipt라는 데이터 프레임을 조작하는 코드입니다.
df_sum <-df_receipt %>% group_by(sales_ymd) %>% summarise(sum_amount = sum(amount), .groups = "drop") - 앞의 예제 코드의 첫 번째 줄과 유사하며, df_receipt 데이터 프레임 를 sales_ymd 열로 그룹화하고, 각 고유한 sales_ymd 그룹별로 금액 열의 합계를 계산하여 결과 데이터 프레임을 df_sum이라는 새로운 변수에 저장합니다.
for (i in 1:3) { - 3차례 반복되는 for 루프를 시작합니다.
df_tmp <- df_sum %>% mutate(lag_ymd = lag(sales_ymd, n = i), lag_amount = lag(sum_amount, n = i)) - df_sum 데이터 프레임의 sales_ymd와 sum_amount 열을 dplyr의 lag()를 사용하여 i일간 지연시킨 새로운 임시 데이터 프레임 df_tmp를 생성한다. 결과 데이터 프레임은 sales_ymd, sum_amount, lag_ymd, lag_amount의 세 개의 컬럼을 가지게 된다.
if (i == 1) { df_lag <- df_tmp }. - 이것이 루프의 첫 번째 반복인 경우, df_lag 데이터 프레임은 df_tmp와 동일하게 설정된다.
else { df_lag <- rbind(df_lag, df_tmp) }. - 루프의 첫 번째 반복이 아닌 경우 df_tmp는 dplyr의 rbind() 함수를 사용하여 기존 df_lag 데이터 프레임에 추가된다.
} - for 루프는 여기서 종료된다.
df_lag %>% drop_na(everything()) %>% arrange(sales_ymd, lag_ymd) %>% slice(1:10) - 루프 내에서 생성된 df_lag 데이터 프레임을 받아 drop_na()로 데이터가 누락된 행을 모두 제거한다. 제거하고, arrange()로 sales_ymd와 lag_ymd로 행을 정렬하고, slice()로 결과 데이터 프레임의 첫 10개의 행을 선택한다.
이 코드의 목적은 지난 3일간의 sales_ymd와 sum_amount 열의 지연 값을 포함하는 df_lag라는 새로운 데이터 프레임을 생성하는 것입니다. 이 데이터 프레임은 지난 3일간의 매출 추세를 조사하는 데 사용할 수 있으며, 향후 매출을 예측하는 데 도움이 될 수 있습니다. 마지막 코드는 표시 및 추가 분석을 위해 결과 데이터 프레임의 처음 10개의 행을 선택하는 코드입니다.
# 코드 예시 2: 가로형 케이스
df_sum <-df_receipt %>%
group_by(sales_ymd) %>%
summarise(sum_amount = sum(amount), .groups = "drop")
for (i in 1:3) {
col_name_1 <- paste("lag_ymd_", i , sep="_")
col_name_2 <- paste("lag_amount", i , sep="_")
df_tmp <- df_sum %>%
mutate(!!col_name_1 := lag(sales_ymd, n = i),
!!col_name_2 := lag(sum_amount, n = i))
if (i == 1) {
df_lag <- df_tmp
}
else {
df_lag <- cbind(df_lag, df_tmp[c(col_name_1, col_name_2)])
}
}
df_lag %>%
drop_na(everything()) %>%
arrange(sales_ymd) %>%
slice(1:10)
sales_ymd | sum_amount | lag_ymd__1 | lag_amount_1 | lag_ymd__2 | lag_amount_2 | lag_ymd__3 | lag_amount_3 |
---|---|---|---|---|---|---|---|
<int> | <int> | <int> | <int> | <int> | <int> | <int> | <int> |
20170104 | 36165 | 20170103 | 27503 | 20170102 | 24165 | 20170101 | 33723 |
20170105 | 37830 | 20170104 | 36165 | 20170103 | 27503 | 20170102 | 24165 |
20170106 | 32387 | 20170105 | 37830 | 20170104 | 36165 | 20170103 | 27503 |
20170107 | 23415 | 20170106 | 32387 | 20170105 | 37830 | 20170104 | 36165 |
20170108 | 24737 | 20170107 | 23415 | 20170106 | 32387 | 20170105 | 37830 |
20170109 | 26718 | 20170108 | 24737 | 20170107 | 23415 | 20170106 | 32387 |
20170110 | 20143 | 20170109 | 26718 | 20170108 | 24737 | 20170107 | 23415 |
20170111 | 24287 | 20170110 | 20143 | 20170109 | 26718 | 20170108 | 24737 |
20170112 | 23526 | 20170111 | 24287 | 20170110 | 20143 | 20170109 | 26718 |
20170113 | 28004 | 20170112 | 23526 | 20170111 | 24287 | 20170110 | 20143 |
설명:
이 코드도 R의 dplyr 패키지를 사용하여 df_receipt라는 데이터 프레임을 조작하는 코드입니다.a
df_sum <-df_receipt %>% group_by(sales_ymd) %>% summarise(sum_amount = sum(amount), .groups = "drop") - 앞의 예제 코드의 첫 번째 줄과 유사하며, df_receipt 데이터 프레임 를 sales_ymd 열로 그룹화하고, 각 고유한 sales_ymd 그룹별로 금액 열의 합계를 계산하여 결과 데이터 프레임을 df_sum이라는 새로운 변수에 저장합니다.
for (i in 1:3) { - 3차례 반복 실행하는 for 루프를 시작합니다.
col_name_1 <- paste("lag_ymd_", i , sep="_") - 접두사 "lag_ymd_"와 현재 i의 값을 연결한 col_name_1이라는 새로운 문자열 변수를 생성한다.
col_name_2 <- paste("lag_amount", i , sep="_") - 접두사 "lag_amount_"와 현재 i의 값을 연결한 col_name_2라는 새로운 문자열 변수를 생성한다.
df_tmp <- df_sum %>% mutate(! !col_name_1 := lag(sales_ymd, n = i), ! col_name_2 := lag(sum_amount, n = i)) - df_sum 데이터 프레임의 sales_ymd와 sum_amount 컬럼을 dplyr의 lag() 함수를 사용하여 i일 지연시켜 생성한 새로운 임시 데이터 프레임을 df_tmp라는 이름으로 생성한다. 데이터입니다. 하지만 앞의 예시처럼 정적인 이름으로 새로운 열을 추가하는 것이 아니라, 이 코드에서는 3과 4단계에서 생성한 문자열 변수를 사용하여 열 이름을 동적으로 생성하고 있습니다. 변수 이름이 열 이름으로 평가될 수 있도록 !!! 연산자를 사용하여 따옴표를 해제하고 있습니다.
if (i == 1) { df_lag <- df_tmp }. - 이것이 루프의 첫 번째 반복인 경우 df_lag 데이터 프레임은 df_tmp와 동일하게 설정된다.
else { df_lag <- cbind(df_lag, df_tmp[c(col_name_1, col_name_2)]) } - 루프의 첫 번째 반복이 아닌 경우, df_tmp 데이터 프레임은 cbind()를 사용하여 기존 df_lag 데이터 프레임에 추가된다. 하지만 이 코드에서는 앞의 예처럼 특정 열을 선택하는 것이 아니라 이름이 col_name_1과 col_name_2의 값과 일치하는 열을 동적으로 선택한다.
} - 여기서 for 루프가 종료된다.
df_lag %>% drop_na(everything()) %>% arrange(sales_ymd) %>% slice(1:10) - 루프 내에서 생성된 df_lag 데이터 프레임을 받아 drop_na()로 데이터가 누락된 행을 삭제하고, arrange ()로 sales_ymd에서 행을 정렬하고, slice()로 결과 데이터 프레임의 처음 10개의 행을 선택한다.
이 코드의 목적은 df_lag라는 새로운 데이터 프레임을 생성하고 sales_ymd와 sum_amount 열의 지난 3일간의 각 지연 값을 저장하는 것이다. 그러나 이 코드에서는 컬럼 이름을 하드코딩하는 대신 컬럼 이름을 동적으로 생성한다.
R-043: 영수증 내역 데이터(df_receipt)와 고객 데이터(df_customer)를 결합하여 성별 코드(gender_cd)와 연령(age에서 계산)별 매출 금액(amount)을 합산한 매출 요약 데이터를 생성한다. 성별 코드는 0은 남성, 1은 여성, 9는 알 수 없음을 나타낸다.
단, 항목 구성은 연령, 여성 매출금액, 남성 매출금액, 남성 매출금액, 성별 미상 매출금액의 4개 항목으로 구성한다(세로로 연령, 가로로 성별 교차 집계). 또한 연령은 10세 단위의 계급으로 한다.
df_sales_summary <- df_customer[c("customer_id", "gender_cd", "age")] %>%
mutate(era = trunc(age / 10) * 10) %>%
inner_join(df_receipt, by = "customer_id") %>%
group_by(gender_cd, era) %>%
summarise(sum_amount = sum(amount), .groups = "drop") %>%
spread( gender_cd, sum_amount, fill = 0) %>%
rename(male = "0", female = "1", unknown = "9")
df_sales_summary
era | male | female | unknown |
---|---|---|---|
<dbl> | <dbl> | <dbl> | <dbl> |
10 | 1591 | 149836 | 4317 |
20 | 72940 | 1363724 | 44328 |
30 | 177322 | 693047 | 50441 |
40 | 19355 | 9320791 | 483512 |
50 | 54320 | 6685192 | 342923 |
60 | 272469 | 987741 | 71418 |
70 | 13435 | 29764 | 2427 |
80 | 46360 | 262923 | 5111 |
90 | 0 | 6260 | 0 |
설명:
이 코드는 df_customer와 df_receipt 두 데이터 프레임의 데이터를 사용하여 고객의 성별과 연령대(즉, 10세)별 판매 금액 요약을 생성한다.
먼저 df_customer에서 3개의 열(customer_id, gender_cd, age)을 선택하고, age를 최근 10년으로 반올림하여 새로운 변수 era를 생성한다.
그런 다음 df_receipt 데이터 프레임을 customer_id로 결합하여 고객의 성별, 연령, 판매 금액에 대한 정보를 가진 새로운 데이터 프레임을 생성한다.
그런 다음 이 데이터를 gender_cd와 era로 그룹화하고 summarise()를 사용하여 총 매출액을 계산한다.
spread()를 사용하여 데이터를 피벗하여 각 시대별로 한 줄씩, 각 성별의 매출 금액의 합계를 나타내는 열을 생성합니다.
마지막으로 rename()을 사용하여 남성, 여성, 성별 미지정을 나타내는 열에 좀 더 설명적인 이름을 붙인다.
그 결과 df_sales_summary라는 데이터 프레임이 생성되어 성별과 시대별 총 판매액을 요약한 데이터 프레임이 완성되었습니다.
R-044: 043에서 만든 매출 요약 데이터(df_sales_summary)는 성별 매출을 가로로 나열한 데이터였다. 이 데이터에서 성별을 세로로 가져와서 연령, 성별 코드, 매출 금액의 세 가지 항목으로 변환하라. 단, 성별 코드는 남성을 ’00’, 여성을 ’01’, 알 수 없음을 ’99’로 한다.
df_sales_summary %>%
gather(key = gender_cd, value = sum_amount, male, female, unknown) %>%
mutate(gender_cd = case_when(
gender_cd == "male" ~ "00",
gender_cd == "female" ~ "01",
gender_cd == "unknown" ~ "99",
))
era | gender_cd | sum_amount |
---|---|---|
<dbl> | <chr> | <dbl> |
10 | 00 | 1591 |
20 | 00 | 72940 |
30 | 00 | 177322 |
40 | 00 | 19355 |
50 | 00 | 54320 |
60 | 00 | 272469 |
70 | 00 | 13435 |
80 | 00 | 46360 |
90 | 00 | 0 |
10 | 01 | 149836 |
20 | 01 | 1363724 |
30 | 01 | 693047 |
40 | 01 | 9320791 |
50 | 01 | 6685192 |
60 | 01 | 987741 |
70 | 01 | 29764 |
80 | 01 | 262923 |
90 | 01 | 6260 |
10 | 99 | 4317 |
20 | 99 | 44328 |
30 | 99 | 50441 |
40 | 99 | 483512 |
50 | 99 | 342923 |
60 | 99 | 71418 |
70 | 99 | 2427 |
80 | 99 | 5111 |
90 | 99 | 0 |
설명:
이 코드는 이전 코드 블록에서 생성된 df_sales_summary 데이터 프레임을 수정한다.
gather() 함수는 male, female, unknown 열을 sum_amount라는 하나의 열로 중첩하여 gender_cd라는 새로운 열을 생성하고 이전 열 이름(male, female, unknown)을 저장하여 데이터를 와이드 포맷에서 롱 포맷으로 변환 하는 데 사용된다.
mutate() 함수는 gender_cd 컬럼의 값을 다시 코딩하는 데 사용된다. 이는 case_when() 함수를 사용하여 세 가지 가능한 값을 가진 새로운 열을 생성한다. "00"은 남성, "01"은 여성, "99"는 성별을 알 수 없다.
전체적으로 이 코드는 df_sales_summary 데이터 프레임을 긴 형식으로 포맷하고 성별 값을 표준 형식으로 다시 코딩하여 다른 데이터 프레임과 병합할 준비를 하고 있다.
R-045: 고객 데이터(df_customer)의 생년월일(birth_day)은 날짜형으로 데이터를 보유하고 있다. 이를 YYYYMMDD 형식의 문자열로 변환하여 고객 ID(customer_id)와 함께 10건 표시하라.
df_tmp <- cbind(df_customer["customer_id"],
strftime(
df_customer$birth_day,
format = "%Y%m%d" ))
colnames(df_tmp) <- c("customer_id", "birth_day")
head(df_tmp,10)
customer_id | birth_day | |
---|---|---|
<chr> | <chr> | |
1 | CS021313000114 | 19810429 |
2 | CS037613000071 | 19520401 |
3 | CS031415000172 | 19761004 |
4 | CS028811000001 | 19330327 |
5 | CS001215000145 | 19950329 |
6 | CS020401000016 | 19740915 |
7 | CS015414000103 | 19770809 |
8 | CS029403000008 | 19730817 |
9 | CS015804000004 | 19310502 |
10 | CS033513000180 | 19620711 |
설명:
이 코드는 df_customer 데이터 프레임에서 customer_id와 birth_day 열을 선택하여 df_tmp라는 새로운 데이터 프레임을 생성합니다.
df_customer["customer_id"] 구문은 customer_id 열을 벡터가 아닌 데이터 프레임으로 선택하는데, 이는 cbind()를 사용하여 다른 열과 결합하기 위해 필요합니다.
strftime() 함수는 birth_day 열을 %Y%m%d 형식의 문자열로 포맷하는 데 사용된다.
connames() 함수는 데이터 프레임에 새로운 열 이름을 할당하는 데 사용되며, 열 이름은 "customer_id"와 "birth_day"이다.
마지막으로 head() 함수를 사용하여 df_tmp 데이터 프레임의 처음 10줄을 표시합니다.
전체적으로 이 코드는 고객 ID와 생일을 기준으로 다른 데이터 프레임과 병합하는 데 사용할 수 있는 두 개의 열을 가진 새로운 데이터 프레임을 생성하고 있습니다.
R-046: 고객 데이터(df_customer)의 신청일(application_date)은 YYYYMMDD 형식의 문자열 형태로 데이터를 보유하고 있다. 이를 날짜형으로 변환하여 고객 ID(customer_id)와 함께 10건씩 표시하라.
df_tmp <- cbind(df_customer["customer_id"],
strptime(df_customer$application_date, "%Y%m%d"))
colnames(df_tmp) <- c("customer_id", "application_date")
head(df_tmp, 10)
customer_id | application_date | |
---|---|---|
<chr> | <dttm> | |
1 | CS021313000114 | 2015-09-05 |
2 | CS037613000071 | 2015-04-14 |
3 | CS031415000172 | 2015-05-29 |
4 | CS028811000001 | 2016-01-15 |
5 | CS001215000145 | 2017-06-05 |
6 | CS020401000016 | 2015-02-25 |
7 | CS015414000103 | 2015-07-22 |
8 | CS029403000008 | 2015-05-15 |
9 | CS015804000004 | 2015-06-07 |
10 | CS033513000180 | 2015-07-28 |
설명:
이 코드는 df_customer 데이터 프레임에서 customer_id와 application_date 열을 선택하여 df_tmp라는 새로운 데이터 프레임을 생성한다.
df_customer["customer_id"] 구문은 customer_id 열을 벡터가 아닌 데이터 프레임으로 선택한다.
strptime() 함수는 application_date 열을 변환하는 데 사용되며, application_date 열은 연, 월, 일을 8자리 숫자로 표현하는 %Y%m%d 형식의 문자열을 R에서 날짜와 시간을 표현하는 POSIXlt 클래스 객체로 변환한다.
connames() 함수는 데이터 프레임에 새로운 열 이름을 할당하는 데 사용되며, 열 이름은 'customer_id'와 'application_date'로 지정한다.
마지막으로 head() 함수를 사용하여 df_tmp 데이터 프레임의 처음 10줄을 표시한다.
전체적으로 이 코드는 두 개의 열을 가진 새로운 데이터 프레임을 생성하고 고객 ID와 신청 날짜를 기준으로 다른 데이터 프레임과 결합하는 데 사용할 수 있다.
R-047: 영수증 내역 데이터(df_receipt)의 매출일(sales_ymd)은 YYYYMMDD 형식의 숫자형으로 데이터를 보유하고 있다. 이를 날짜형으로 변환하여 영수증 번호(receipt_no), 영수증 하위번호(receipt_sub_no)와 함께 10건씩 표시하라.
df_tmp <- cbind(df_receipt[c("receipt_no", "receipt_sub_no")], strptime(as.character(df_receipt$sales_ymd), "%Y%m%d"))
colnames(df_tmp) <- c("receipt_no", "receipt_sub_no", "sales_ymd")
head(df_tmp, 10)
receipt_no | receipt_sub_no | sales_ymd | |
---|---|---|---|
<int> | <int> | <dttm> | |
1 | 112 | 1 | 2018-11-03 |
2 | 1132 | 2 | 2018-11-18 |
3 | 1102 | 1 | 2017-07-12 |
4 | 1132 | 1 | 2019-02-05 |
5 | 1102 | 2 | 2018-08-21 |
6 | 1112 | 1 | 2019-06-05 |
7 | 1102 | 2 | 2018-12-05 |
8 | 1102 | 1 | 2019-09-22 |
9 | 1112 | 2 | 2017-05-04 |
10 | 1102 | 1 | 2019-10-10 |
설명:
이 코드는 df_receipt 데이터 프레임에서 receipt_no, receipt_sub_no, sales_ymd 열을 선택하고, sales_ymd 열을 yyyymmdd 형식의 정수에서 R의 날짜와 시간을 나타내는 POSIXlt 클래스 객체로 변환하여 df_tmp 라는 새로운 데이터 프레임을 생성합니다.
df_receipt[c("receipt_no", "receipt_sub_no")] 구문은 cbind()에서 다른 열과 결합하기 위해 필요한 receipt_no와 receipt_sub_no 열을 벡터가 아닌 데이터 프레임으로 선택합니다. 입니다.
as.character()는 strptime() 함수에 전달하기 전에 sales_ymd 컬럼을 정수에서 문자 벡터로 변환하는 데 사용됩니다.
strptime() 함수는 문자 벡터 sales_ymd를 R의 날짜와 시간을 나타내는 POSIXlt 클래스 객체로 변환하는 데 사용된다.
colnames() 함수는 데이터 프레임에 새로운 열 이름을 할당하는 데 사용되며, 열 이름은 "receive_no", "receipt_sub_no", "sales_ymd"가 된다.
마지막으로 head() 함수를 사용하여 df_tmp 데이터 프레임의 처음 10줄을 표시한다.
전체적으로 이 코드는 영수증 번호, 영수증 하위 번호 또는 판매 날짜를 기준으로 다른 데이터 프레임과 병합하는 데 사용할 수 있는 3개의 열을 가진 새로운 데이터 프레임을 생성한다.
R-048: 영수증 내역 데이터(df_receipt)의 매출 에포크 초(sales_epoch)는 숫자형 UNIX 초로 데이터를 보유하고 있다. 이를 날짜형으로 변환하여 영수증 번호(receipt_no), 영수증 서브번호(receipt_sub_no)와 함께 10건을 표시하라.
df_tmp <- cbind(df_receipt[c("receipt_no", "receipt_sub_no")], as.POSIXct(df_receipt$sales_epoch, origin="1970-01-01"))
colnames(df_tmp) <- c("receipt_no", "receipt_sub_no", "sales_ymd")
head(df_tmp, 10)
receipt_no | receipt_sub_no | sales_ymd | |
---|---|---|---|
<int> | <int> | <dttm> | |
1 | 112 | 1 | 2018-11-03 |
2 | 1132 | 2 | 2018-11-18 |
3 | 1102 | 1 | 2017-07-12 |
4 | 1132 | 1 | 2019-02-05 |
5 | 1102 | 2 | 2018-08-21 |
6 | 1112 | 1 | 2019-06-05 |
7 | 1102 | 2 | 2018-12-05 |
8 | 1102 | 1 | 2019-09-22 |
9 | 1112 | 2 | 2017-05-04 |
10 | 1102 | 1 | 2019-10-10 |
설명:
이 코드는 원본 데이터 프레임 df_receipt에서 선택한 열을 결합하여 새로운 데이터 프레임 df_tmp를 생성한다. 구체적으로 df_receipt에서 "receive_no", "receipt_sub_no", "sales_epoch" 열을 선택하고 cbind()라는 함수로 결합하고 있습니다.
세 번째 열인 "sales_epoch"에는 유닉스의 에포크로 알려진 1970년 1월 1일부터의 초 단위가 저장되어 있다. 다음으로 as.POSIXct() 함수를 사용하여 이 수치를 R의 날짜와 시간을 나타내는 POSIXct 객체로 변환한다. 인수의 origin에는 에포크가 1970년 1월 1일 0시부터 시작됨을 나타내는 '1970-01-01'이 설정되어 있다.
마지막으로 colnames() 함수를 사용하여 df_tmp의 열 이름을 각각 "receive_no", "receipt_sub_no", "sales_ymd"로 변경했다.
그 결과, df_tmp의 데이터 프레임에는 df_receipt와 동일한 두 개의 열("receive_no", "receive_sub_no")과 "sales_epoch"에서 변환한 날짜와 시간 정보를 가진 새로운 열 "sales_ymd"가 포함되어 있다. tmp의 처음 10개의 행을 표시하기 위해 head() 함수가 사용되었다.
R-049: 영수증 내역 데이터(df_receipt)의 매출 에포크 초(sales_epoch)를 날짜형으로 변환하여 ‘연도’만 추출하여 영수증 번호(receipt_no), 영수증 하위 번호(receipt_sub_no)와 함께 10건 표시하라.
df_tmp <- cbind(df_receipt[c("receipt_no", "receipt_sub_no")], substring(as.POSIXct(df_receipt$sales_epoch, origin = "1970-01-01"), 1, 4))
colnames(df_tmp) <- c("receipt_no", "receipt_sub_no", "sales_year")
head(df_tmp, 10)
receipt_no | receipt_sub_no | sales_year | |
---|---|---|---|
<int> | <int> | <chr> | |
1 | 112 | 1 | 2018 |
2 | 1132 | 2 | 2018 |
3 | 1102 | 1 | 2017 |
4 | 1132 | 1 | 2019 |
5 | 1102 | 2 | 2018 |
6 | 1112 | 1 | 2019 |
7 | 1102 | 2 | 2018 |
8 | 1102 | 1 | 2019 |
9 | 1112 | 2 | 2017 |
10 | 1102 | 1 | 2019 |
설명:
이 코드는 df_receipt 데이터 프레임에서 세 개의 열을 결합하여 df_tmp라는 새로운 데이터 프레임을 생성한다. 처음 두 열인 receive_no와 receive_sub_no는 df_receipt에서 직접 선택됩니다.
세 번째 열인 sales_year는 sales_epoch 열을 날짜/시간 형식으로 변환하는 데 사용되는 as.POSIXct()의 출력에서 처음 4글자를 추출하는 substring() 함수를 사용하여 생성된다.
as.POSIXct() 함수는 origin 매개 변수를 사용하여 유닉스 에픽 시간(1970-01-01)을 기준점으로 사용하도록 지정한다. 다음으로 substring() 함수를 사용하여 이 날짜/시간 형식에서 연도를 추출하고 있다.
마지막으로 colnames()를 사용하여 새로운 데이터 프레임의 해당 열에 "receive_no", "receipt_sub_no", "sales_year"라는 열 이름을 할당하고 있습니다. 그리고 head() 함수를 사용하여 새 데이터 프레임의 첫 10개의 행을 표시합니다.
R-050: 영수증 내역 데이터(df_receipt)의 매출 에포크 초(sales_epoch)를 날짜형으로 변환하여 ‘월’만 추출하여 영수증 번호(receipt_no), 영수증 하위 번호(receipt_sub_no)와 함께 10건을 표시한다. 단, ‘월’은 0으로 채워진 2자리로 추출한다.
df_tmp <- cbind(df_receipt[c("receipt_no", "receipt_sub_no")], substring(as.POSIXct(df_receipt$sales_epoch, origin = "1970-01-01"), 6, 7))
colnames(df_tmp) <- c("receipt_no", "receipt_sub_no", "sales_ymd")
head(df_tmp, 10)
receipt_no | receipt_sub_no | sales_ymd | |
---|---|---|---|
<int> | <int> | <chr> | |
1 | 112 | 1 | 11 |
2 | 1132 | 2 | 11 |
3 | 1102 | 1 | 07 |
4 | 1132 | 1 | 02 |
5 | 1102 | 2 | 08 |
6 | 1112 | 1 | 06 |
7 | 1102 | 2 | 12 |
8 | 1102 | 1 | 09 |
9 | 1112 | 2 | 05 |
10 | 1102 | 1 | 10 |
설명:
이 코드에서는 "receive_no", "receipt_sub_no", "sales_ymd" 열을 포함하는 새로운 데이터 프레임 df_tmp를 생성하며, "sales_ymd" 열은 df_receipt의 "sales_epoch" 열에서 파생된 것이다.
구체적으로 substring() 함수를 사용하여 시작 위치를 6(월 성분의 첫 번째 문자에 해당), 끝 위치를 7(월 성분의 마지막 문자에 해당)로 설정하여 "sales_epoch" 컬럼에서 월 성분을 추출한다. 이 결과 문자열은 판매일 월을 나타낸다.
새로운 데이터 프레임 df_tmp는 df_receipt에서 선택한 열을 cbind() 함수를 사용하여 추출한 월 성분과 결합하여 생성된다. 마지막으로 df_tmp의 컬럼 이름이 "receive_no", "receipt_sub_no", "sales_ymd"로 갱신된다.
전체적으로 이 코드는 df_receipt의 "sales_epoch" 열에서 각 판매일의 월을 추출하여 새로운 데이터 프레임 df_tmp에 "sales_ymd"라는 이름의 새로운 열로 추가한다.
R-051: 영수증 내역 데이터(df_receipt)의 매출 에포크 초를 날짜형으로 변환하여 ‘일’만 추출하여 영수증 번호(receipt_no), 영수증 하위 번호(receipt_sub_no)와 함께 10건 표시한다. 단, ‘일’은 0으로 채워진 2자리로 추출한다.
df_tmp <- cbind(df_receipt[c("receipt_no", "receipt_sub_no")], substring(as.POSIXct(df_receipt$sales_epoch, origin = "1970-01-01"), 9, 10))
colnames(df_tmp) <- c("receipt_no", "receipt_sub_no", "sales_day")
head(df_tmp, 10)
receipt_no | receipt_sub_no | sales_day | |
---|---|---|---|
<int> | <int> | <chr> | |
1 | 112 | 1 | 03 |
2 | 1132 | 2 | 18 |
3 | 1102 | 1 | 12 |
4 | 1132 | 1 | 05 |
5 | 1102 | 2 | 21 |
6 | 1112 | 1 | 05 |
7 | 1102 | 2 | 05 |
8 | 1102 | 1 | 22 |
9 | 1112 | 2 | 04 |
10 | 1102 | 1 | 10 |
설명:
이 코드에서는 "receive_no", "receive_sub_no", "sales_day"라는 세 개의 열을 가진 df_tmp라는 새로운 데이터 프레임을 생성하고, "receive_no"와 "receive_sub_no" 열은 "df_receipt" 데이터 프레임에서 복사한 것입니다. receipt" 데이터 프레임에서 복사한 것이며, sales_day 컬럼은 df_receipt 데이터 프레임의 sales_epoch 컬럼에서 날짜를 추출하여 생성한다.
sales_epoch" 컬럼은 먼저 as.POSIXct 함수를 사용하여 POSIXct 객체로 변환하고 원점을 "1970-01-01"로 설정한다. 이는 유닉스 타임스탬프(1970년 1월 1일부터의 초 단위)를 R의 datetime 형식으로 변환하는 일반적인 방법이다. 그런 다음 substring 함수를 사용하여 datetime 객체의 day 부분을 추출합니다. substring 함수는 입력 문자열, 부분 문자열의 시작 위치, 부분 문자열의 끝 위치라는 세 가지 인수를 취합니다. 이 경우 부분 문자열은 9번 위치(datetime 문자열의 요일 부분)에서 시작하여 10번 위치에서 끝난다.
마지막으로 colnames 함수를 사용하여 열 이름을 'recipate_no', 'recipate_sub_no', 'sales_day'로 업데이트하고 있다. 완성된 데이터 프레임 df_tmp에는 처음 10행의 데이터 중 "receive_no", "receipt_sub_no", "sales_day" 열이 표시되어 있다.
R-052: 영수증 내역 데이터(df_receipt)의 매출 금액(amount)을 고객 ID(customer_id)별로 합산한 후, 매출 금액 총합에 대해 2,000원 이하를 0, 2,000원보다 큰 금액을 1로 이분화하여 고객 ID, 매출 금액 총합과 함께 10건씩 표시한다. 단, 고객 ID가 “Z”로 시작하는 것은 비회원을 의미하므로 제외하여 계산한다.
df_receipt %>%
filter(!grepl("^Z", customer_id)) %>%
group_by(customer_id) %>%
summarise(sum_amount=sum(amount), .groups = "drop") %>%
mutate(sales_flg = ifelse(sum_amount > 2000, 1, 0)) %>%
slice(1:10)
customer_id | sum_amount | sales_flg |
---|---|---|
<chr> | <int> | <dbl> |
CS001113000004 | 1298 | 0 |
CS001114000005 | 626 | 0 |
CS001115000010 | 3044 | 1 |
CS001205000004 | 1988 | 0 |
CS001205000006 | 3337 | 1 |
CS001211000025 | 456 | 0 |
CS001212000027 | 448 | 0 |
CS001212000031 | 296 | 0 |
CS001212000046 | 228 | 0 |
CS001212000070 | 456 | 0 |
설명:
이 코드는 df_receipt 데이터 프레임에 대해 다음과 같은 처리를 수행한다.
customer_id 컬럼이 "Z"로 시작하는 모든 행을 필터링합니다.
나머지 행을 customer_id로 검색합니다.
각 customer_id의 금액 열의 합계를 계산한다.
금액 열의 합계가 2000보다 크면 1, 그렇지 않으면 0으로 설정되는 새로운 열 sales_flg를 생성한다.
결과 데이터 프레임에서 처음 10개의 행을 선택합니다.
연산자 '%>%'를 사용하여 처리를 연쇄적으로 연결하여 코드를 더 간결하고 읽기 쉽게 만들었습니다.
아래에서 단계별로 설명하겠습니다.
filter(!grepl("^Z", customer_id)): filter() 함수는 customer_id 열이 "Z"로 시작하는 모든 행을 삭제하고 grepl() 함수는 customer_id 열의 각 요소가 ^Z 패턴과 일치하지 않는지(즉, "Z"로 시작하지 않는지)를 나타내는 논리 함수를 반환합니다. Z'로 시작하지 않는지 여부를 나타내는 논리 벡터를 반환한다. 연산자 ! 연산자는 논리 벡터를 부정하므로 filter()는 벡터가 TRUE인 행만 유지한다.
group_by(customer_id): group_by() 함수는 나머지 행을 customer_id로 그룹화한다.
summarise(sum_amount=sum(금액), .groups = "drop"): summarise() 함수는 각 고객 ID의 amount 열의 합계를 계산하고 그 결과를 sum_amount라는 새로운 열에 저장한다. .groups = "drop" 인수는 데이터를 요약한 후 그룹화 구조를 삭제하도록 summarise()에 지시한다.
mutate(sales_flg = ifelse(sum_amount > 2000, 1, 0)): mutate() 함수는 sales_flg라는 새로운 열을 생성하고 sum_amount 열이 2000보다 크면 1, 그렇지 않으면 0으로 설정한다. 표준 if.... .else 문장의 벡터화 버전으로, 조건 벡터와 동일한 길이의 벡터를 반환하며, 조건 벡터의 요소가 TRUE인지 FALSE인지에 따라 yes 또는 no 벡터 중 하나의 요소가 선택된다.
slice(1:10) : slice() 함수는 결과 데이터 프레임에서 처음 10개의 행을 선택한다.
R-053: 고객 데이터(df_customer)의 우편번호(postal_cd)에 대해 도쿄(앞 3자리가 100~209인 것)를 1, 그 외의 것을 0으로 이진화하라. 또한 영수증 내역 데이터(df_receipt)와 결합하여 전체 기간 동안 매출 실적이 있는 고객 수를 생성한 이항대수별로 계산하라.
df_customer[c("customer_id", "postal_cd")] %>%
mutate(postal_flg =
ifelse(100 <= as.integer(str_sub(postal_cd, start = 1, end = 3))
& as.integer(str_sub(postal_cd, start = 1, end = 3)) <= 209, 1, 0)) %>% inner_join(df_receipt, by = "customer_id") %>%
group_by(postal_flg) %>%
summarise(customer_cnt = n_distinct(customer_id), .groups = "drop")
postal_flg | customer_cnt |
---|---|
<dbl> | <int> |
0 | 3906 |
1 | 4400 |
설명:
이 코드는 다음과 같은 작업을 수행한다.
데이터 프레임 df_customer에서 "customer_id"와 "postal_cd" 열을 선택한다.
"postal_cd"의 첫 3글자가 100에서 209 사이의 우편번호를 나타내는 경우 1, 그렇지 않은 경우 0으로 설정되는 새로운 열 "postal_flg"를 생성한다. 이 검사에는 ifelse 함수가 사용된다.
수정된 df_customer 데이터 프레임과 df_receipt 데이터 프레임을 "customer_id" 열로 결합한다.
결과 데이터 프레임을 "postal_flg" 컬럼으로 그룹화한다.
n_distinct 함수를 사용하여 "postal_flg"의 각 값에 대한 고유한 고객 ID 수를 계산한다.
인수 ".groups = 'drop'"으로 그룹화 정보를 삭제한다.
postal_flg"와 "customer_cnt" 열이 있는 결과 데이터 프레임을 반환한다.
전체적으로 이 코드는 df_receipt에 포함된 우편번호가 100~209 범위에 있는 고객 수를 해당 범위에 우편번호가 있는지 여부에 따라 그룹화하여 계산한다.
R-054: 고객 데이터(df_customer)의 주소(address)는 사이타마현, 지바현, 도쿄도, 가나가와현 중 하나이다. 도도부현별로 코드 값을 생성하여 고객 ID, 주소와 함께 10건씩 표시하라. 값은 사이타마현을 11, 지바현을 12, 도쿄도를 13, 가나가와현을 14로 한다.
# 코드 예시 1 (고정으로 잘라내기)
df_customer %>%
mutate(prefecture_cd =
case_when(
str_sub(address, start = 1, end = 3) == "埼玉県" ~ "11",
str_sub(address, start = 1, end = 3) == "千葉県" ~ "12",
str_sub(address, start = 1, end = 3) == "東京都" ~ "13",
str_sub(address, start = 1, end = 3) == "神奈川" ~ "14")) %>% select(customer_id, address, prefecture_cd) %>%
slice(1:10)
customer_id | address | prefecture_cd |
---|---|---|
<chr> | <chr> | <chr> |
CS021313000114 | 神奈川県伊勢原市粟窪********** | 14 |
CS037613000071 | 東京都江東区南砂********** | 13 |
CS031415000172 | 東京都渋谷区代々木********** | 13 |
CS028811000001 | 神奈川県横浜市泉区和泉町********** | 14 |
CS001215000145 | 東京都大田区仲六郷********** | 13 |
CS020401000016 | 東京都板橋区若木********** | 13 |
CS015414000103 | 東京都江東区北砂********** | 13 |
CS029403000008 | 千葉県浦安市海楽********** | 12 |
CS015804000004 | 東京都江東区北砂********** | 13 |
CS033513000180 | 神奈川県横浜市旭区善部町********** | 14 |
설명:
이 코드는 다음과 같은 동작을 수행합니다.
데이터 프레임 df_customer를 입력으로 받습니다.
df_customer 데이터 프레임에 새로운 열 prefecture_cd를 생성한다.
prefecture_cd 열의 값은 address 열의 값을 기반으로 한다.
주소란의 첫 3글자가 "사이타마현"이라면 prefecture_cd 열의 값은 "11"로 설정된다.
주소란의 첫 3글자가 "치바현"인 경우, prefecture_cd란의 값은 "12"로 설정된다.
주소란의 첫 3글자가 "도쿄도"인 경우, prefecture_cd란의 값은 "13"으로 설정된다.
주소 컬럼의 첫 3글자가 "가나가와"인 경우, prefecture_cd 컬럼의 값은 "14"로 설정된다.
customer_id, address, prefecture_cd의 각 컬럼이 출력 대상으로 선택된다.
slice(1:10) 함수는 결과 데이터 프레임의 처음 10개의 행을 표시하는 데 사용된다.
# 코드 예시 2 (정규 표현식 사용)
df_customer %>%
mutate(prefecture_cd =
case_when(
str_extract(address, pattern = "^.*?[都道府県]") == "埼玉県" ~ "11",
str_extract(address, pattern = "^.*?[都道府県]") == "千葉県" ~ "12",
str_extract(address, pattern = "^.*?[都道府県]") == "東京都" ~ "13",
str_extract(address, pattern = "^.*?[都道府県]") == "神奈川県" ~ "14")) %>% select(customer_id, address, prefecture_cd) %>%
slice(1:10)
customer_id | address | prefecture_cd |
---|---|---|
<chr> | <chr> | <chr> |
CS021313000114 | 神奈川県伊勢原市粟窪********** | 14 |
CS037613000071 | 東京都江東区南砂********** | 13 |
CS031415000172 | 東京都渋谷区代々木********** | 13 |
CS028811000001 | 神奈川県横浜市泉区和泉町********** | 14 |
CS001215000145 | 東京都大田区仲六郷********** | 13 |
CS020401000016 | 東京都板橋区若木********** | 13 |
CS015414000103 | 東京都江東区北砂********** | 13 |
CS029403000008 | 千葉県浦安市海楽********** | 12 |
CS015804000004 | 東京都江東区北砂********** | 13 |
CS033513000180 | 神奈川県横浜市旭区善部町********** | 14 |
설명:
이 코드는 R의 dplyr 패키지를 사용하여 df_customer 데이터 프레임에 새로운 열 prefecture_cd를 생성하고, 일본 도도부현의 하위 집합에 대해 도도부현 이름과 도도부현 코드를 대응시킨다. 구체적으로는 데이터 프레임에 새로운 컬럼을 추가하는 mutate() 함수와 정규 표현식 패턴 매칭에 따라 도도부현 이름과 코드를 대응시키는 case_when() 함수를 사용합니다.
다음은 코드를 한 줄씩 설명합니다.
df_customer %>% df_customer 데이터 프레임을 입력으로 파이프라인을 시작합니다.
mutate(prefecture_cd = 데이터 프레임에 새로운 열 prefecture_cd를 생성합니다.
case_when( 도도부현 이름과 코드를 대응시키기 위한 일련의 조건을 시작합니다.
str_extract(address, pattern = "^. *? [都道府県]") == "埼玉県" ~ "11", 정규 표현식 패턴 "^. *? [도도부현]"에 매칭하여 주소열에서 도도부현 이름을 추출하고, "사이타마현"을 "11"에 대응시킨다.
str_extract(address, pattern = "^. *? [縣]") == "치바현" ~ "12", "치바현"에 대해서도 같은 처리를 하여 "12"에 매핑한다.
str_extract(address, pattern = "^. *? [도도부현]") == "도쿄도" ~ "13", "도쿄도"와 동일하게 처리하여 "13"에 대응시킨다.
str_extract(address, pattern = "^. *? [都道府県]") == "가나가와현" ~ "14"))는 "가나가와현"과 동일하게 "14"에 대응시키기 위해 사용한다.
select(customer_id, address, prefecture_cd)는 데이터 프레임에서 customer_id, address, prefecture_cd 열만 선택한다.
slice(1:10)은 결과 데이터 프레임의 처음 10행만 선택한다.
R-055: 영수증 명세서(df_receipt) 데이터의 매출 금액(amount)을 고객 ID(customer_id)별로 합산하고, 그 합산 금액의 사분위수를 구하시오. 그 후, 고객별 매출금액 합계에 대해 아래 기준으로 카테고리 값을 생성하여 고객 ID, 매출금액 합계와 함께 10건씩 표시하라. 카테고리 값은 순서대로 1~4로 한다.
- 최소값 이상 1사분위수 미만 ・・・ 1을 부여
- 1사분위 이상 2사분위 미만 ・・・ 2를 부여
- 2사분위 이상 3사분위 미만 ・・・ 3을 부여
- 3사분위 이상 ・・・ 4을 부여
df_receipt %>%
group_by(customer_id) %>%
summarise(sum_amount = sum(amount), .groups = "drop") %>%
mutate(pct_group = case_when(
sum_amount < quantile(sum_amount)[2] ~ "1",
sum_amount < quantile(sum_amount)[3] ~ "2",
sum_amount < quantile(sum_amount)[4] ~ "3",
quantile(sum_amount)[4] <= sum_amount ~ "4"
)) %>%
slice(1:10)
customer_id | sum_amount | pct_group |
---|---|---|
<chr> | <int> | <chr> |
CS001113000004 | 1298 | 2 |
CS001114000005 | 626 | 2 |
CS001115000010 | 3044 | 3 |
CS001205000004 | 1988 | 3 |
CS001205000006 | 3337 | 3 |
CS001211000025 | 456 | 1 |
CS001212000027 | 448 | 1 |
CS001212000031 | 296 | 1 |
CS001212000046 | 228 | 1 |
CS001212000070 | 456 | 1 |
설명:
본 코드는 다음과 같은 처리를 한다.
데이터 프레임 df_receipt를 가져옵니다.
df_receipt의 행을 customer_id로 그룹화합니다.
동일한 customer_id를 가진 각 행 그룹에 대해 sum() 함수를 사용하여 금액 열의 합계를 계산하고 그 결과를 sum_amount라는 새 열에 저장한다.
.groups = "drop"을 사용하여 그룹화 구조를 삭제한다.
case_when() 함수를 사용하여 새로운 열 pct_group을 생성하고 sum_amount 열의 값에 따라 각 행을 사분위수(quintile number)에 할당한다. 사분위 수는 quantile() 함수를 사용하여 결정된다.
마지막으로 결과 데이터 프레임의 처음 10개의 행을 선택하여 df_tmp라는 새로운 데이터 프레임에 저장한다.
예를 들어, quantile(sum_amount)이 [100, 200, 300, 400]을 반환하는 경우, 결과 pct_group 열은 sum_amount가 200 미만인 행은 '1', 200에서 299까지의 행은 '2', 300에서 399까지의 행은 '3', 400 이상의 행은 '4'라는 값을 가지게 된다. 에는 '4'라는 값을 가지게 된다.
R-056: 고객 데이터(df_customer)의 나이(age)를 기준으로 10세 단위로 연령을 계산하여 고객 ID(customer_id), 생년월일(birth_day)과 함께 10건씩 표시한다. 단, 60세 이상은 모두 60대 이상으로 한다. 연령을 나타내는 카테고리 명칭은 임의대로 한다.
# 코드 예시 1
df_customer[c("customer_id", "birth_day", "age")] %>%
mutate(era = trunc(age / 10) * 10) %>%
mutate(era = case_when( era < 60 ~ era, era >= 60 ~ 60 )) %>%
slice(1:10)
customer_id | birth_day | age | era |
---|---|---|---|
<chr> | <date> | <int> | <dbl> |
CS021313000114 | 1981-04-29 | 37 | 30 |
CS037613000071 | 1952-04-01 | 66 | 60 |
CS031415000172 | 1976-10-04 | 42 | 40 |
CS028811000001 | 1933-03-27 | 86 | 60 |
CS001215000145 | 1995-03-29 | 24 | 20 |
CS020401000016 | 1974-09-15 | 44 | 40 |
CS015414000103 | 1977-08-09 | 41 | 40 |
CS029403000008 | 1973-08-17 | 45 | 40 |
CS015804000004 | 1931-05-02 | 87 | 60 |
CS033513000180 | 1962-07-11 | 56 | 50 |
설명:
이 코드는 고객 데이터가 포함된 데이터 프레임 df_customer를 조작한다. 이 코드에서는 customer_id, birth_day, age의 세 가지 열을 선택합니다. 그리고 나이를 기준으로 각 고객의 나이를 계산한다.
첫 번째 mutate 함수는 각 고객의 나이를 10으로 나누고 그 결과를 가장 가까운 정수로 반올림하고 그 정수에 10을 곱하여 나이를 계산한다. 예를 들어, 어떤 고객의 나이가 43세라면 40세가 되고, 25세인 고객의 나이는 20세가 된다.
두 번째 mutate 함수는 60 이상의 era 값을 60으로 바꾼다. 이는 60세 이상의 모든 고객을 하나의 시대 범주로 묶기 위해 수행됩니다.
이 데이터 프레임에는 각 고객의 고객 ID, 생년월일, 연령 및 계산된 연령이 포함되어 있습니다.
# 코드 예제 2(min 사용 시)
df_customer[c("customer_id", "birth_day","age")] %>%
mutate(era = sapply(1:nrow(df_customer),
function(x){
return (min(trunc(.[x, 3] / 10) * 10, 60))
})) %>%
slice(1:10)
customer_id | birth_day | age | era |
---|---|---|---|
<chr> | <date> | <int> | <dbl> |
CS021313000114 | 1981-04-29 | 37 | 30 |
CS037613000071 | 1952-04-01 | 66 | 60 |
CS031415000172 | 1976-10-04 | 42 | 40 |
CS028811000001 | 1933-03-27 | 86 | 60 |
CS001215000145 | 1995-03-29 | 24 | 20 |
CS020401000016 | 1974-09-15 | 44 | 40 |
CS015414000103 | 1977-08-09 | 41 | 40 |
CS029403000008 | 1973-08-17 | 45 | 40 |
CS015804000004 | 1931-05-02 | 87 | 60 |
CS033513000180 | 1962-07-11 | 56 | 50 |
설명:
이 코드는 생년월일로부터 각 고객의 '나이'를 계산하는 데 사용됩니다. 아래는 각 행의 처리 내용입니다.
df_customer 데이터 프레임에서 "customer_id", "birth_day", "age" 컬럼만 선택한다.
mutate 함수를 사용하여 "era"라는 새로운 컬럼을 추가한다. 이 컬럼의 값은 "age"컬럼을 10으로 나누어 계수를 취한 후 (즉, 가장 가까운 정수로 반올림) 10을 곱하여 계산됩니다. 이렇게 하면 연령이 효과적으로 10의 배수로 반올림되어 각 고객의 대략적인 "나이"를 나타냅니다.
다시 'mutate' 함수를 사용하여 era의 값을 조정합니다. era가 60보다 작으면 그대로 두고, 60보다 크면 60으로 설정합니다.
slice 함수로 완성된 데이터 프레임의 처음 10줄을 선택한다.
이 코드에서는 데이터 프레임의 각 행에 계산을 적용하기 위해 "apply" 함수를 사용한다는 점에 유의하십시오. 이 방법은 효과적이지만 매우 큰 데이터 프레임의 경우 시간이 오래 걸릴 수 있다. 보다 효율적인 방법은 대신 벡터화 된 작업을 사용하는 것입니다.
R-057: 056의 추출 결과와 성별 코드(gender_cd)에 따라 성별×연령의 조합을 나타내는 카테고리 데이터를 새로 만들어 10개를 표시하라. 조합을 나타내는 카테고리의 값은 임의로 정한다.
# 성별 코드 1자리와 연대 코드 2자리를 연결한 성연령 코드를 생성한다.
df_customer[c("customer_id", "gender_cd", "birth_day", "age")] %>%
mutate(era = trunc(age / 10) * 10) %>%
mutate(era = case_when( era < 60 ~ formatC(era, width = 2,flag = "0"),
era >= 60 ~ formatC(60, width = 2,flag = "0"))) %>%
mutate(gender_era = paste(gender_cd, era, sep = "")) %>%
slice(1:10)
customer_id | gender_cd | birth_day | age | era | gender_era |
---|---|---|---|---|---|
<chr> | <chr> | <date> | <int> | <chr> | <chr> |
CS021313000114 | 1 | 1981-04-29 | 37 | 30 | 130 |
CS037613000071 | 9 | 1952-04-01 | 66 | 60 | 960 |
CS031415000172 | 1 | 1976-10-04 | 42 | 40 | 140 |
CS028811000001 | 1 | 1933-03-27 | 86 | 60 | 160 |
CS001215000145 | 1 | 1995-03-29 | 24 | 20 | 120 |
CS020401000016 | 0 | 1974-09-15 | 44 | 40 | 040 |
CS015414000103 | 1 | 1977-08-09 | 41 | 40 | 140 |
CS029403000008 | 0 | 1973-08-17 | 45 | 40 | 040 |
CS015804000004 | 0 | 1931-05-02 | 87 | 60 | 060 |
CS033513000180 | 1 | 1962-07-11 | 56 | 50 | 150 |
설명:
이 코드는 df_customer라는 데이터 프레임을 조작하는 코드이며, 아마도 고객에 대한 정보를 담고 있을 것입니다. 다음은 각 행에 대한 설명입니다.
df_customer[c("customer_id", "gender_cd", "birth_day", "age")]: df_customer[c("customer_id", "gender_cd", "birth_day", "age")]: 데이터 프레임 df_customer customer에서 "customer_id", "gender_cd", "birth_day", "age" 열을 선택합니다.
%>%: 데이터 프레임을 다음 연산에 연결하기 위해 사용하는 파이프 연산자이다.
mutate(era = trunc(age / 10) * 10). 이 열은 각 고객의 나이를 10으로 나누어 소수점 이하를 자르고 10을 곱하여 계산한다. 이렇게 하면 고객은 10세 범위로 분류됩니다.
mutate(era = case_when( era < 60 ~ formatC(era, width = 2,flag = "0"), era >= 60 ~ formatC(60, width = 2,flag = "0")))): case_when 문장을 적용하여 'era' 컬럼을 변경하여 60 미만의 'era' 값에 era' 값을 앞의 0이 포함된 2자리 문자열로 변환하고(예: 10~19세는 '10'), 60 이상의 'era' 값을 '60'으로 설정합니다.
mutate(gender_era = paste(gender_cd, era, sep = "")): 데이터 프레임에 "gender_era"라는 새로운 열을 추가한다." "gender_cd"와 "era" 열을 paste 함수로 연결하여 생성한다. sep = "" 인수는 두 값 사이에 구분 기호가 없음을 지정한다.
slice(1:10) : 데이터 프레임의 처음 10개의 행을 선택한다.
R-058: 고객 데이터(df_customer)의 성별 코드(gender_cd)를 더미 변수로 만들어 고객 ID(customer_id)와 함께 10건 표시하라.
# 코드 예시 1 (모든 코드 값을 항목화)
dummy_gender_model <- dummyVars(~gender_cd, data = df_customer, fullRank = FALSE)
dummy_gender <- predict(dummy_gender_model, df_customer)
head(cbind(df_customer["customer_id"], dummy_gender), 10)
customer_id | gender_cd0 | gender_cd1 | gender_cd9 | |
---|---|---|---|---|
<chr> | <dbl> | <dbl> | <dbl> | |
1 | CS021313000114 | 0 | 1 | 0 |
2 | CS037613000071 | 0 | 0 | 1 |
3 | CS031415000172 | 0 | 1 | 0 |
4 | CS028811000001 | 0 | 1 | 0 |
5 | CS001215000145 | 0 | 1 | 0 |
6 | CS020401000016 | 1 | 0 | 0 |
7 | CS015414000103 | 0 | 1 | 0 |
8 | CS029403000008 | 1 | 0 | 0 |
9 | CS015804000004 | 1 | 0 | 0 |
10 | CS033513000180 | 0 | 1 | 0 |
설명:
이 코드는 데이터 프레임 df_customer의 카테고리 변수 "gender_cd"에 대해 더미 변수를 생성합니다. 먼저 "care" 패키지의 dummyVars 함수를 사용하여 모델 객체를 생성하고, fullRank 인수를 FALSE로 설정하여 범주 변수의 첫 번째 수준(다른 수준에서 추론할 수 있는 수준)을 제거합니다.
두 번째 줄은 원본 데이터 프레임 df_customer에 모델을 적용하여 더미 변수가 있는 새로운 데이터 프레임을 생성한다. 첫 번째 인수에 dummy_gender_model, 두 번째 인수에 df_customer를 가진 predict 함수는 데이터 프레임에 모델을 적용하여 더미 변수를 생성한다.
마지막으로 cbind 함수로 df_customer의 customer_id 열을 더미 변수와 결합하고 head()로 처음 10개의 행을 표시한다.
# 코드 예시 2 (fullRank=TRUE로 설정하여 항목을 하나 깎을 수 있음)
dummy_gender_model <- dummyVars(~gender_cd, data = df_customer, fullRank = TRUE)
dummy_gender <- predict(dummy_gender_model, df_customer)
head(cbind(df_customer["customer_id"], dummy_gender), 3)
customer_id | gender_cd1 | gender_cd9 | |
---|---|---|---|
<chr> | <dbl> | <dbl> | |
1 | CS021313000114 | 1 | 0 |
2 | CS037613000071 | 0 | 1 |
3 | CS031415000172 | 1 | 0 |
설명:
이 코드는 care 패키지의 dummyVars() 및 predict() 함수를 사용하여 df_customer dataframe의 gender_cd 열에 대한 원샷 인코딩을 수행한다.
dummyVars() 함수는 수식으로 지정된 카테고리 변수의 카테고리를 나타내는 더미 변수 세트를 생성합니다. 이 경우 ~gender_cd 식은 더미 변수를 생성하기 위해 gender_cd 변수를 사용하도록 지정합니다. 인수 fullRank = TRUE는 더미 변수의 인코딩에 참조 레벨을 포함하도록 지정한다.
그런 다음 predict() 함수를 사용하여 원래의 df_customer 데이터 프레임에 인코딩을 적용한다. 그 결과 인코딩된 데이터 프레임은 dummy_gender 변수에 저장된다.
마지막으로 head() 함수를 사용하여 dummy_gender 데이터프레임의 처음 세 줄과 cbind()를 사용하여 추가한 원래 df_customer 데이터프레임의 customer_id 컬럼을 표시한다. 이를 통해 처음 몇 명의 고객에 대한 인코딩을 확인할 수 있습니다. 각 고객의 더미 변수의 인코딩은 해당 성별에 해당하는 열의 1과 다른 성별에 해당하는 열의 0으로 구성됩니다.
R-059: 영수증 내역 데이터(df_receipt)의 매출 금액(amount)을 고객 ID(customer_id)별로 합산하고, 매출 금액 합계를 평균 0, 표준편차 1로 표준화하여 고객 ID, 매출 금액 합계와 함께 10건씩 표시하라. 표준화에 사용하는 표준편차는 분산 제곱근 또는 불균형 분산 제곱근 중 어느 것이든 상관없다. 단, 고객 ID가 “Z”로 시작하는 것은 비회원을 의미하므로 제외하여 계산한다.
# R의 scale을 사용하기 때문에 불균등분산의 제곱근에 의한 표준편차로 표준화됨
df_receipt %>%
filter(!grepl("^Z", customer_id)) %>%
group_by(customer_id) %>%
summarise(sum_amount = sum(amount), .groups = "drop") %>%
mutate(std_amount = scale(sum_amount, center = TRUE, scale = TRUE)) %>%
slice(1:10)
customer_id | sum_amount | std_amount |
---|---|---|
<chr> | <int> | <dbl[,1]> |
CS001113000004 | 1298 | -0.4593502 |
CS001114000005 | 626 | -0.7063478 |
CS001115000010 | 3044 | 0.1824025 |
CS001205000004 | 1988 | -0.2057366 |
CS001205000006 | 3337 | 0.2900964 |
CS001211000025 | 456 | -0.7688324 |
CS001212000027 | 448 | -0.7717728 |
CS001212000031 | 296 | -0.8276413 |
CS001212000046 | 228 | -0.8526351 |
CS001212000070 | 456 | -0.7688324 |
설명:
이 코드는 다음 단계를 수행합니다.
df_receipt 데이터 프레임에서 customer_id 열이 "Z"로 시작하지 않는 행을 필터링합니다. 이는 dplyr 패키지의 filter 함수와 customer_id 열에 정규식 패턴을 일치시키는 grepl 함수를 사용하여 수행됩니다.
group_by 함수를 사용하여 결과 행을 customer_id로 그룹화한다.
dplyr의 summarise 함수를 사용하여 각 그룹의 금액 열의 합계를 계산한다.
std_amount라는 새로운 열을 생성하여 각 고객의 금액의 표준화 된 합계를 저장합니다. scale 함수를 사용하여 데이터를 평균값으로 중심을 잡고(center = TRUE), 표준 편차가 1이 되도록 스케일링하여 금액의 합계를 표준화합니다(scale = TRUE). ).
마지막으로 slice 함수를 사용하여 customer_id와 std_amount 열을 포함한 결과 데이터 프레임의 처음 10개의 행을 선택하는 데 사용됩니다.
R-060: 영수증 내역 데이터(df_receipt)의 매출 금액(amount)을 고객 ID(customer_id)별로 합산하여 매출 금액 합계를 최소값 0, 최대값 1로 정규화하여 고객 ID, 매출 금액 합계와 함께 10건씩 표시한다. 단, 고객 ID가 “Z”로 시작하는 것은 비회원을 의미하므로 제외하여 계산한다.
df_receipt %>% filter(!grepl("^Z", customer_id)) %>%
group_by(customer_id) %>%
summarise(sum_amount = sum(amount), .groups = "drop") %>%
mutate( scale_amount = scale(sum_amount, center = min(sum_amount), scale = max(sum_amount) - min(sum_amount)))%>%
slice(1:10)
customer_id | sum_amount | scale_amount |
---|---|---|
<chr> | <int> | <dbl[,1]> |
CS001113000004 | 1298 | 0.053354188 |
CS001114000005 | 626 | 0.024157108 |
CS001115000010 | 3044 | 0.129214460 |
CS001205000004 | 1988 | 0.083333333 |
CS001205000006 | 3337 | 0.141944734 |
CS001211000025 | 456 | 0.016770942 |
CS001212000027 | 448 | 0.016423358 |
CS001212000031 | 296 | 0.009819256 |
CS001212000046 | 228 | 0.006864790 |
CS001212000070 | 456 | 0.016770942 |
설명:
이 코드는 df_receipt 데이터 프레임에 대해 다음과 같은 처리를 수행한다.
customer_id가 "Z"로 시작하는 행을 필터링한다.
나머지 행을 customer_id로 그룹화한다.
customer_id의 각 그룹별 금액의 합계를 계산한다.
완성된 데이터 프레임을 변이시켜 sum_amount의 스케일링 버전인 새로운 열 scale_amount를 추가한다. scale 함수는 sum_amount의 최소값이 0, 최대값이 1이 되도록 스케일링한다.
완성된 데이터 프레임을 슬라이스하여 처음 10개의 행만 남깁니다.
요약하면, 이 코드는 df_receipt의 각 고객이 사용한 금액의 합계를 계산하고, 그 값을 최소값은 0, 최대값은 1이 되도록 스케일링하고 있습니다. 결과 scale_amount 값은 서로 다른 고객의 상대적인 지출 패턴을 비교하고 싶을 때와 같은 특정 분석에 유용하다.
Comment