해당 문서는 R Markdown 을 이용하여 제작했으며 dplyr패키지를 이용한 데이터 전처리(Pre-processing)에 대한 것 입니다. 예제 데이터로는 ggplot2 패키지에 있는 diamonds 데이터를 사용했습니다. 먼저 전처리가 무엇인지에 대해 알아보고 dplyr 패키지에 어떤 함수가 있는지 그리고 함수들을 어떻게 사용하는지 순서대로 서술하겠습니다.
데이터 전처리란 작업 할 raw data를 구성하는 관측치와 변수들을 제거, 수정 혹은 추가하여 최종적으로 분석에 사용할 Data Set을 만드는 과정을 말합니다. 예를 몇 가지 들자면 다음과 같습니다.
변경하는 것제거하는 것.추가하는 경우dplyr 패키지 인가?dplyr 패키지의 가장 큰 장점은 %>%(파이프, Pipe) 연산자라고 생각합니다. 전처리 외에도 파이프 연산자 덕에 가독성이 굉장히 좋아집니다. 수학적으로 말하자면 합성함수 o(circle)와 유사한 기능을 합니다. 다만 둘의 차이점은 합성함수 (f o g)(x) == f(g(x)) 처럼 뒤에서부터 앞의 순서로 계산하지만 dplyr 의 파이프 연산자는
DataFrame %>% function1() %>% function2() 순서대로 진행됩니다.
dplyr 패키지에 있는 함수들dplyr 패키지에 있는 많은 함수들 중 해당 글에서 설명할 함수들은 다음과 같습니다.
library(dplyr)
library(ggplot2)ggplot2::diamonds## # A tibble: 53,940 x 10
## carat cut color clarity depth table price x y z
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
## 1 0.230 Ideal E SI2 61.5 55.0 326 3.95 3.98 2.43
## 2 0.210 Premium E SI1 59.8 61.0 326 3.89 3.84 2.31
## 3 0.230 Good E VS1 56.9 65.0 327 4.05 4.07 2.31
## 4 0.290 Premium I VS2 62.4 58.0 334 4.20 4.23 2.63
## 5 0.310 Good J SI2 63.3 58.0 335 4.34 4.35 2.75
## 6 0.240 Very Good J VVS2 62.8 57.0 336 3.94 3.96 2.48
## 7 0.240 Very Good I VVS1 62.3 57.0 336 3.95 3.98 2.47
## 8 0.260 Very Good H SI1 61.9 55.0 337 4.07 4.11 2.53
## 9 0.220 Fair E VS2 65.1 61.0 337 3.87 3.78 2.49
## 10 0.230 Very Good H VS1 59.4 61.0 338 4.00 4.05 2.39
## # ... with 53,930 more rows
관측치 53,940개, 변수 10개로 이루어진 데이터임을 알 수 있다. 이 외에도 데이터를 확인하는 다양한 함수들은 다음과 같은 것들이 있다.
summary()
DT::datatable()
str()
dplyr::glimpse()dim(DataName)의 결과값을 순서대로 m, n 이라 할 때 m은 관측치의 갯수, n은 변수의 개수라는 뜻이다. 이 때 연구자 본인이 판단했을 때 전체 n개의 변수 중에서 필요한 변수들만 선택(추출) 하는 함수가 dplyr::select()이다.
기본적인 입력 방식은 다음과 같다.
DataFrame %>%
select(VariableName)diamonds %>%
select(color)## # A tibble: 53,940 x 1
## color
## <ord>
## 1 E
## 2 E
## 3 E
## 4 I
## 5 J
## 6 J
## 7 I
## 8 H
## 9 E
## 10 H
## # ... with 53,930 more rows
cut, color 변수 추출
diamonds %>%
select(cut, color)## # A tibble: 53,940 x 2
## cut color
## <ord> <ord>
## 1 Ideal E
## 2 Premium E
## 3 Good E
## 4 Premium I
## 5 Good J
## 6 Very Good J
## 7 Very Good I
## 8 Very Good H
## 9 Fair E
## 10 Very Good H
## # ... with 53,930 more rows
DataName %>% select(Vector) 형태로 입력해주면 된다.
diamonds %>%
select(1:4)## # A tibble: 53,940 x 4
## carat cut color clarity
## <dbl> <ord> <ord> <ord>
## 1 0.230 Ideal E SI2
## 2 0.210 Premium E SI1
## 3 0.230 Good E VS1
## 4 0.290 Premium I VS2
## 5 0.310 Good J SI2
## 6 0.240 Very Good J VVS2
## 7 0.240 Very Good I VVS1
## 8 0.260 Very Good H SI1
## 9 0.220 Fair E VS2
## 10 0.230 Very Good H VS1
## # ... with 53,930 more rows
dplyr::select(starts_with()) diamonds 데이터에서 c로 시작하는 변수들만 선택
diamonds %>%
select(starts_with("c"))## # A tibble: 53,940 x 4
## carat cut color clarity
## <dbl> <ord> <ord> <ord>
## 1 0.230 Ideal E SI2
## 2 0.210 Premium E SI1
## 3 0.230 Good E VS1
## 4 0.290 Premium I VS2
## 5 0.310 Good J SI2
## 6 0.240 Very Good J VVS2
## 7 0.240 Very Good I VVS1
## 8 0.260 Very Good H SI1
## 9 0.220 Fair E VS2
## 10 0.230 Very Good H VS1
## # ... with 53,930 more rows
diamonds 데이터에서 e로 끝나는 변수들만 선택
diamonds %>%
select(ends_with("e"))## # A tibble: 53,940 x 2
## table price
## <dbl> <int>
## 1 55.0 326
## 2 61.0 326
## 3 65.0 327
## 4 58.0 334
## 5 58.0 335
## 6 57.0 336
## 7 57.0 336
## 8 55.0 337
## 9 61.0 337
## 10 61.0 338
## # ... with 53,930 more rows
diamonds 데이터에서 r이 들어간 변수들 선택
diamonds %>%
select(contains("r"))## # A tibble: 53,940 x 4
## carat color clarity price
## <dbl> <ord> <ord> <int>
## 1 0.230 E SI2 326
## 2 0.210 E SI1 326
## 3 0.230 E VS1 327
## 4 0.290 I VS2 334
## 5 0.310 J SI2 335
## 6 0.240 J VVS2 336
## 7 0.240 I VVS1 336
## 8 0.260 H SI1 337
## 9 0.220 E VS2 337
## 10 0.230 H VS1 338
## # ... with 53,930 more rows
행(관측치) 추출 할 때 사용한다. 내가 원하는 조건에 맞는 관측치만 고르는 함수
diamonds %>%
filter(price <= 950)## # A tibble: 13,490 x 10
## carat cut color clarity depth table price x y z
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
## 1 0.230 Ideal E SI2 61.5 55.0 326 3.95 3.98 2.43
## 2 0.210 Premium E SI1 59.8 61.0 326 3.89 3.84 2.31
## 3 0.230 Good E VS1 56.9 65.0 327 4.05 4.07 2.31
## 4 0.290 Premium I VS2 62.4 58.0 334 4.20 4.23 2.63
## 5 0.310 Good J SI2 63.3 58.0 335 4.34 4.35 2.75
## 6 0.240 Very Good J VVS2 62.8 57.0 336 3.94 3.96 2.48
## 7 0.240 Very Good I VVS1 62.3 57.0 336 3.95 3.98 2.47
## 8 0.260 Very Good H SI1 61.9 55.0 337 4.07 4.11 2.53
## 9 0.220 Fair E VS2 65.1 61.0 337 3.87 3.78 2.49
## 10 0.230 Very Good H VS1 59.4 61.0 338 4.00 4.05 2.39
## # ... with 13,480 more rows
다이아몬드 가격이 950 이하이고, 800이상인 것만 고를 때
diamonds %>%
filter(price <= 950 & price >= 800)## # A tibble: 3,707 x 10
## carat cut color clarity depth table price x y z
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
## 1 0.410 Very Good G VS2 61.4 57.0 800 4.76 4.81 2.94
## 2 0.320 Ideal F VVS2 62.1 55.0 800 4.37 4.39 2.72
## 3 0.320 Ideal F VVS2 61.2 57.0 800 4.42 4.44 2.71
## 4 0.320 Ideal F VVS2 60.9 56.0 800 4.44 4.46 2.71
## 5 0.320 Ideal F VVS2 61.2 55.0 800 4.43 4.46 2.72
## 6 0.380 Ideal I VVS1 62.4 54.8 800 4.64 4.66 2.90
## 7 0.400 Ideal H VS2 61.6 57.0 800 4.71 4.74 2.91
## 8 0.360 Ideal D VS2 61.8 55.0 800 4.58 4.61 2.84
## 9 0.310 Ideal E VS1 62.0 55.0 800 4.35 4.38 2.70
## 10 0.310 Ideal E VS1 61.7 53.0 800 4.36 4.39 2.70
## # ... with 3,697 more rows
데이터를 이루는 기존 변수들의 변수명을 바꾸는 경우에 사용. 데이터 분석을 하다보면 간혹 RawData들의 변수명이 V1, V2, V3, …. 식으로 나와있고 별도로 CodeBook 이 같이 있는 경우가 있다. 이런 경우 분석에 필요한 몇가지 변수들의 이름을 좀 더 직관적으로 편하게 알아볼 수 있도록 변환 할 때 사용하는 것이 rename() 이다.
입력 방식은 다음과 같이 새로 저장할 변수명 = 기존 변수명 형태로 넣어주면 된다.
DataFrame %>% rename(New.Vaiable.Name = Variable.Name)
diamonds 데이터 중에 x, y, z 변수들을 각각 width, length, heigth 로 변경하고 colnames()를 이용하여 변환된 변수명들을 확인해보자.
diamonds <- diamonds %>%
rename(width = x,
length = y,
heigth = z)
colnames(diamonds)## [1] "carat" "cut" "color" "clarity" "depth" "table" "price"
## [8] "width" "length" "heigth"
위에 서술한 rename()은 변수명만 변환할 때 사용하는 것이다. 지금 설명할 mutate()는 기존에 존재하던 변수들을 이용하여 파생변수를 만들거나 기존 변수를 변환할 때 사용한다. 입력방식은 rename()과 유사하게 변환명 = 기존 변수명 형태로 입력하면 된다.
기존에 있던 price 를 이용하여 3933 이상을 Expensive, 그 외에는 Cheap이라는 질적 자료로 이루어진 price2 파생변수를 만들어보자.
diamonds <- diamonds %>%
mutate(price2 = ifelse(price >= 3933, "Expensive", "Cheap"))
str(diamonds)## Classes 'tbl_df', 'tbl' and 'data.frame': 53940 obs. of 11 variables:
## $ carat : num 0.23 0.21 0.23 0.29 0.31 0.24 0.24 0.26 0.22 0.23 ...
## $ cut : Ord.factor w/ 5 levels "Fair"<"Good"<..: 5 4 2 4 2 3 3 3 1 3 ...
## $ color : Ord.factor w/ 7 levels "D"<"E"<"F"<"G"<..: 2 2 2 6 7 7 6 5 2 5 ...
## $ clarity: Ord.factor w/ 8 levels "I1"<"SI2"<"SI1"<..: 2 3 5 4 2 6 7 3 4 5 ...
## $ depth : num 61.5 59.8 56.9 62.4 63.3 62.8 62.3 61.9 65.1 59.4 ...
## $ table : num 55 61 65 58 58 57 57 55 61 61 ...
## $ price : int 326 326 327 334 335 336 336 337 337 338 ...
## $ width : num 3.95 3.89 4.05 4.2 4.34 3.94 3.95 4.07 3.87 4 ...
## $ length : num 3.98 3.84 4.07 4.23 4.35 3.96 3.98 4.11 3.78 4.05 ...
## $ heigth : num 2.43 2.31 2.31 2.63 2.75 2.48 2.47 2.53 2.49 2.39 ...
## $ price2 : chr "Cheap" "Cheap" "Cheap" "Cheap" ...
만약에 범주를 2개 이상으로 나누고 싶다면, ifelse()를 2번 이상 사용해주면 된다. 예를 들어 price가 5324 이상인 것들을 High, 950 이상부터 5324 미만을 Middle, 950 미만을 Low로 하는 질적자료 price3 파생변수를 만들어보자.
diamonds <- diamonds %>%
mutate(price3 = ifelse(price >= 5324, "High",
ifelse(price >= 950, "Middle", "Low")))
str(diamonds)## Classes 'tbl_df', 'tbl' and 'data.frame': 53940 obs. of 12 variables:
## $ carat : num 0.23 0.21 0.23 0.29 0.31 0.24 0.24 0.26 0.22 0.23 ...
## $ cut : Ord.factor w/ 5 levels "Fair"<"Good"<..: 5 4 2 4 2 3 3 3 1 3 ...
## $ color : Ord.factor w/ 7 levels "D"<"E"<"F"<"G"<..: 2 2 2 6 7 7 6 5 2 5 ...
## $ clarity: Ord.factor w/ 8 levels "I1"<"SI2"<"SI1"<..: 2 3 5 4 2 6 7 3 4 5 ...
## $ depth : num 61.5 59.8 56.9 62.4 63.3 62.8 62.3 61.9 65.1 59.4 ...
## $ table : num 55 61 65 58 58 57 57 55 61 61 ...
## $ price : int 326 326 327 334 335 336 336 337 337 338 ...
## $ width : num 3.95 3.89 4.05 4.2 4.34 3.94 3.95 4.07 3.87 4 ...
## $ length : num 3.98 3.84 4.07 4.23 4.35 3.96 3.98 4.11 3.78 4.05 ...
## $ heigth : num 2.43 2.31 2.31 2.63 2.75 2.48 2.47 2.53 2.49 2.39 ...
## $ price2 : chr "Cheap" "Cheap" "Cheap" "Cheap" ...
## $ price3 : chr "Low" "Low" "Low" "Low" ...
연구자 본인이 원하는 요약 통계량을 구할 때 사용하는 함수이다. R 에서 기본적으로 지원해주는 요약 통계량 함수들은 아래와 같다.
| 요약 통계량 | 함수 |
|---|---|
| 최솟값 | min() |
| 최댓값 | max() |
| 평균 | mean() |
| 합 | sum() |
| 분산 | var() |
| 표준편차 | sd() |
| 중앙값 | median() |
| 사분위 범위 | IQR() |
이 외에도 데이터를 이루는 혹은 그룹별 관측치의 갯수를 구하는 n(), 변수의 고유한 범주들의 갯수를 알려주는 n_distinct() 등이 있다.
아래는 summarize() 함수를 이용하여 순서대로 다이아몬드 데이터의 전체 관측치 개수, cut 변수의 고유 범주들의 수, 여러 다이아들중에 가장 비싼 가격을 구하여 dia.table 에 저장하는 코드이다.
dia.table <- diamonds %>%
summarize(n.obs = n(),
n.cut = n_distinct(cut),
max.price = max(price))
dia.table## # A tibble: 1 x 3
## n.obs n.cut max.price
## <int> <int> <dbl>
## 1 53940 5 18823
데이터에 있는 질적 자료들 별로 그룹핑(or Clustering) 해주는 함수이다. DataFrame %>% group_by(VariableName) 형태로 입력해주면 되며, summarize()와 함께 사용할 경우 그룹별 요약통계량을 구해주기 때문에 더욱 강력하다.
아래와 같이 실행하면 cut의 범주별로 그룹을 만든 후 그룹별 관측치 개수, 최고가, 평균 carat을 구할 수 있다.
diamonds %>%
group_by(cut) %>%
summarize(n.obs = n(),
max.price = max(price),
mean.carat = mean(carat))## # A tibble: 5 x 4
## cut n.obs max.price mean.carat
## <ord> <int> <dbl> <dbl>
## 1 Fair 1610 18574 1.05
## 2 Good 4906 18788 0.849
## 3 Very Good 12082 18818 0.806
## 4 Premium 13791 18823 0.892
## 5 Ideal 21551 18806 0.703
여기서 한 가지 추가한다면 cut의 순서가 Fair, Good, Very Good, Ideal, Premium 인 것이 더 보기 편하다.
위에 서술한 mutate()를 이용하여 수정한다면 아래와 같이 하면 된다.
diamonds %>%
mutate(cut = factor(diamonds$cut,
levels = c("Fair", "Good", "Very Good",
"Ideal", "Premium"))) %>%
group_by(cut) %>%
summarize(n.obs = n(),
max.price = max(price),
mean.carat = mean(carat))## # A tibble: 5 x 4
## cut n.obs max.price mean.carat
## <ord> <int> <dbl> <dbl>
## 1 Fair 1610 18574 1.05
## 2 Good 4906 18788 0.849
## 3 Very Good 12082 18818 0.806
## 4 Ideal 21551 18806 0.703
## 5 Premium 13791 18823 0.892
연구자가 선택한 변수에 대하여 오름차순 혹은 내림차순으로 나열하게 해주는 함수로서 디폴트는 오름차순으로 되어있다. 단순하게 다이아몬드 가격에 대해 오름차순으로 나열하고 싶다면 아래와 같이 실행하면 된다.
diamonds %>%
arrange(price)## # A tibble: 53,940 x 12
## carat cut color clarity depth table price width length heigth price2
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl> <chr>
## 1 0.230 Ideal E SI2 61.5 55.0 326 3.95 3.98 2.43 Cheap
## 2 0.210 Premi~ E SI1 59.8 61.0 326 3.89 3.84 2.31 Cheap
## 3 0.230 Good E VS1 56.9 65.0 327 4.05 4.07 2.31 Cheap
## 4 0.290 Premi~ I VS2 62.4 58.0 334 4.20 4.23 2.63 Cheap
## 5 0.310 Good J SI2 63.3 58.0 335 4.34 4.35 2.75 Cheap
## 6 0.240 Very ~ J VVS2 62.8 57.0 336 3.94 3.96 2.48 Cheap
## 7 0.240 Very ~ I VVS1 62.3 57.0 336 3.95 3.98 2.47 Cheap
## 8 0.260 Very ~ H SI1 61.9 55.0 337 4.07 4.11 2.53 Cheap
## 9 0.220 Fair E VS2 65.1 61.0 337 3.87 3.78 2.49 Cheap
## 10 0.230 Very ~ H VS1 59.4 61.0 338 4.00 4.05 2.39 Cheap
## # ... with 53,930 more rows, and 1 more variable: price3 <chr>
# 만약 내림차순으로 하고 싶다면
# diamonds %>%
# arrange(desc(price))전체 관측치(모집단)에서 표본 집단을 뽑을 때 사용하는 함수이며 디폴트는 비복원 추출이다. 재현 가능한 연구를 위해서는 set.seed()를 이용해서 seed 를 지정해줘야 하며 복원 추출을 하고 싶은 경우 replace = TRUE 로 설정해주면 된다. 원하는 갯수만큼 추출하는 경우에는 sample_n()을, 비율로 추출하는 경우에는 sample_frac()을 이용하면 된다.
# 전체 관측치 중에서 100개만 비복원 추출
diamonds %>%
sample_n(100)## # A tibble: 100 x 12
## carat cut color clarity depth table price width length heigth price2
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl> <chr>
## 1 1.33 Fair G SI2 63.0 62.0 6078 6.90 6.87 4.34 Expen~
## 2 0.330 Ideal H VVS1 62.1 53.0 730 4.47 4.51 2.79 Cheap
## 3 0.310 Very ~ G VVS1 59.9 62.0 816 4.35 4.37 2.61 Cheap
## 4 0.230 Very ~ D VVS1 63.3 58.0 530 3.90 3.93 2.48 Cheap
## 5 0.330 Ideal G IF 61.7 55.0 984 4.45 4.47 2.75 Cheap
## 6 0.700 Very ~ G VVS2 59.3 62.0 2905 5.78 5.82 3.44 Cheap
## 7 0.400 Premi~ F VS2 59.7 58.0 1080 4.83 4.79 2.87 Cheap
## 8 0.240 Very ~ E VVS2 58.5 59.0 552 4.04 4.09 2.38 Cheap
## 9 0.500 Fair F SI1 64.7 60.0 1069 4.99 4.84 3.18 Cheap
## 10 0.420 Ideal E VS2 61.7 56.0 1024 4.82 4.80 2.97 Cheap
## # ... with 90 more rows, and 1 more variable: price3 <chr>
# 100개만 복원 추출
diamonds %>%
sample_n(100,
replace = T)## # A tibble: 100 x 12
## carat cut color clarity depth table price width length heigth price2
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl> <chr>
## 1 1.01 Ideal H SI1 62.2 58.0 4773 6.37 6.43 3.98 Expen~
## 2 1.10 Ideal F VVS2 61.2 56.0 10487 6.66 6.74 4.10 Expen~
## 3 0.700 Very ~ D VVS1 62.7 54.0 4244 5.67 5.71 3.57 Expen~
## 4 0.560 Very ~ F VVS1 61.7 56.0 2321 5.26 5.30 3.26 Cheap
## 5 1.01 Very ~ G SI2 61.9 55.0 3852 6.43 6.46 3.99 Cheap
## 6 1.29 Ideal J SI1 61.5 57.0 6097 7.00 7.06 4.32 Expen~
## 7 0.300 Very ~ G VS2 61.8 60.0 505 4.29 4.25 2.64 Cheap
## 8 0.700 Fair H VS1 59.6 66.0 2395 5.80 5.74 3.44 Cheap
## 9 0.520 Ideal D I1 61.1 57.0 971 5.18 5.20 3.17 Cheap
## 10 1.01 Premi~ D SI2 61.7 59.0 4072 6.41 6.37 3.94 Expen~
## # ... with 90 more rows, and 1 more variable: price3 <chr>
# 전체 데이터중에 30% 비복원 추출
diamonds %>%
sample_frac(.3)## # A tibble: 16,182 x 12
## carat cut color clarity depth table price width length heigth price2
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl> <chr>
## 1 0.540 Ideal D VVS1 61.4 58.0 3139 5.28 5.25 3.23 Cheap
## 2 0.330 Premi~ E VVS1 59.7 58.0 984 4.49 4.52 2.69 Cheap
## 3 0.300 Very ~ G VS1 60.8 61.0 565 4.31 4.34 2.63 Cheap
## 4 0.530 Ideal E SI2 60.8 57.0 1229 5.23 5.26 3.19 Cheap
## 5 1.20 Premi~ F SI2 62.8 57.0 5988 6.78 6.73 4.24 Expen~
## 6 0.580 Premi~ G SI2 61.2 59.0 1307 5.40 5.36 3.29 Cheap
## 7 0.510 Ideal D VS1 61.7 54.0 1752 5.12 5.15 3.17 Cheap
## 8 1.02 Premi~ E VS2 60.3 60.0 6032 6.58 6.48 3.94 Expen~
## 9 1.20 Very ~ H SI1 62.3 57.0 6569 6.78 6.76 4.22 Expen~
## 10 1.50 Ideal G SI1 61.0 57.0 12009 7.38 7.41 4.51 Expen~
## # ... with 16,172 more rows, and 1 more variable: price3 <chr>
# 전체 데이터중에 30% 복원 추출
diamonds %>%
sample_frac(.3,
replace = T)## # A tibble: 16,182 x 12
## carat cut color clarity depth table price width length heigth price2
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl> <chr>
## 1 0.330 Ideal I IF 61.7 55.0 675 4.45 4.49 2.76 Cheap
## 2 0.810 Ideal I SI1 61.3 56.0 3097 6.23 6.27 3.83 Cheap
## 3 0.800 Ideal E VS2 61.4 56.0 3972 5.97 6.02 3.68 Expen~
## 4 0.710 Premi~ F SI1 59.8 62.0 2756 5.74 5.73 3.43 Cheap
## 5 1.21 Ideal I SI2 60.6 56.0 5091 6.92 6.94 4.20 Expen~
## 6 0.700 Very ~ H VS2 61.8 58.0 2042 5.66 5.73 3.52 Cheap
## 7 1.51 Premi~ H SI2 59.4 62.0 7235 7.47 7.31 4.39 Expen~
## 8 1.71 Very ~ I SI2 62.7 58.0 8896 7.59 7.54 4.74 Expen~
## 9 0.390 Very ~ G VVS1 60.3 57.0 873 4.74 4.78 2.87 Cheap
## 10 0.320 Premi~ F VS1 62.1 60.0 874 4.37 4.33 2.70 Cheap
## # ... with 16,172 more rows, and 1 more variable: price3 <chr>