Source file ⇒ 세미나_3_.Rmd

학습목표

  1. Joins and Relational Databases
  2. tidyr - Wide and Narrow
  3. ggplot2(2)
    1) Aesthetics vs. Fixed Attributes
    2) Theme
    3) Loess(Locally Weighted Linear Regression)

1. Joins and Relational Databases

데이터 분석에 있어 하나의 데이터 테이블을 사용하는 경우는 드물다. 많은 경우 서로 연관있는 다수의 데이터 테이블을 합쳐 사용하게 되는데, 이러한 서로 관련있는 다수의 데이터 테이블을 relational data이라 한다.

예시: Grades and Enrollment

두 데이터 테이블 GradesCourses 한 학교에서의 grade와 course에 관해 연관된 정보를 제공한다.

Grades <- read.csv("http://tiny.cc/mosaic/grades.csv")
sid grade sessionID
2197 S31680 B session3518
259 S31242 B session2897
4188 S32127 A session2002
3880 S32058 A- session2952
Courses <- read.csv("http://tiny.cc/mosaic/courses.csv")
sessionID dept level sem enroll iid
640 session2568 J 100 FA2002 15 inst223
76 session1940 d 100 FA2000 16 inst409
1218 session3242 m 200 SP2004 30 inst476

여기서 기본키(primary key)와 외래키(foreign key)는 sessionID이다.

기본키(primary key)
하나의 값 혹은 여러 값의 조합으로 테이블의 각 case를 유일하게 식별

외래키(foreign key)
또 다른 테이블에 있는 유일하게 케이스를 식별하는 하나의 값(혹은 여러 값의 조합). 즉 외래키는 다른 테이블에 존재하는 테이블의 기본키이다.

join이라는 data verb는 left tableright table을 합친다.

left table이 보통 기본 테이블이고 right tableleft table에서 얻을 수 없는 정보를 가진 테이블이 된다.

예시: Average class size

목표: 학생 별로 학급의 평균 크기를 찾는다.

Courses 테이블에서 enrollment에 대한 정보를 Grades 테이블로 가져와야 한다.

Grades %>%
  left_join(Courses) %>% sample_n(size=4)
sid grade sessionID dept level sem enroll iid
4043 S32061 B+ session3644 K 300 SP2005 18 inst239
1536 S31518 AU session2901 J 100 FA2003 22 inst224
1844 S31587 B- session3191 b 200 SP2004 10 inst403
3593 S31962 B session3821 W 300 SP2005 24 inst138
Courses %>%
  left_join(Grades) %>% sample_n(size=4)
sessionID dept level sem enroll iid sid grade
2050 session2454 Y 200 FA2002 13 inst397 S31587 C+
3823 session2990 m 200 FA2003 20 inst476 S32310 B+
3354 session2851 O 300 SP2003 14 inst308 S31509 A
5405 session3573 M 100 SP2005 23 inst263 S31830 S

CoursesGrades가 join되면, 다음과 같이 평균 학급 수를 찾을 수 있다.

AveClassEachStudent <- Grades %>% 
  left_join(Courses) %>%
  group_by(sid) %>%
  summarise(ave_enroll = mean(enroll, na.rm=TRUE))
sid ave_enroll
S32124 25.10000
S32154 22.93333
S32415 20.87500

case 사이의 match

예시:

Grades %>% 
  left_join(Courses, by = c(sessionID = "sessionID")) %>%
  head(4)
sid grade sessionID dept level sem enroll iid
S31185 D+ session1784 M 100 FA1991 22 inst265
S31185 B+ session1785 k 100 FA1991 52 inst458
S31185 A- session1791 J 100 FA1993 22 inst223
S31185 B+ session1792 J 300 FA1993 20 inst235

by=의 default 값은 양쪽의 테이블에서 같은 이름을 가지고 있는 변수이다. 하지만 직접 눈으로 확인하지 않는 한, default값을 신뢰할 수 없다.

Grades %>% 
  left_join(Courses) %>%
  head(4)
sid grade sessionID dept level sem enroll iid
S31185 D+ session1784 M 100 FA1991 22 inst265
S31185 B+ session1785 k 100 FA1991 52 inst458
S31185 A- session1791 J 100 FA1993 22 inst223
S31185 B+ session1792 J 300 FA1993 20 inst235
Grades %>% 
  left_join(Courses, by="sessionID") %>%
  head(4)
sid grade sessionID dept level sem enroll iid
S31185 D+ session1784 M 100 FA1991 22 inst265
S31185 B+ session1785 k 100 FA1991 52 inst458
S31185 A- session1791 J 100 FA1993 22 inst223
S31185 B+ session1792 J 300 FA1993 20 inst235

예시 (nycflights)

#install.packages("nycflights13")
library(nycflights13)

데이터 테이블 nycflights13::flights에서 몇 가지 변수를 선택하여 join 예시를 살펴보자.

flights2 <- flights %>% 
  select(year:day, hour, tailnum, carrier)
head(flights2,2)
year month day hour tailnum carrier
2013 1 1 5 N14228 UA
2013 1 1 5 N24211 UA

또 다른 데이터 테이블 airlines은 약자로 표현된 항공사 정보의 full name을 알 수 있도록 해준다.

head(airlines,2)
carrier name
9E Endeavor Air Inc.
AA American Airlines Inc.

또 다른 weather이라는 데이터 테이블은 NYC 공항의 시간당 날씨 정보를 알려준다.

head(weather,2)
origin year month day hour temp dewp humid wind_dir wind_speed wind_gust precip pressure visib time_hour
EWR 2013 1 1 0 37.04 21.92 53.97 230 10.35702 11.91865 0 1013.9 10 2013-01-01 09:00:00
EWR 2013 1 1 1 37.04 21.92 53.97 230 13.80936 15.89154 0 1013.0 10 2013-01-01 10:00:00

세 데이터 테이블의 관계는 다음과 같다:

flights데이터는 carrier변수를 통해 airlines 데이터와 연결되어 있다.

flights데이터는 origin(the location), year, month, day 그리고 hour(the time)를 통해 weather데이터와 연결되어 있다.

만약 flight2데이터에 존재하는 항공사 이름들의 full name을 얻고 싶다면 airlinesflights2 데이터를 left_join()으로 합칠 수 있다:

flights2 %>%
  left_join(airlines, by="carrier") %>%
  head(3)
year month day hour tailnum carrier name
2013 1 1 5 N14228 UA United Air Lines Inc.
2013 1 1 5 N24211 UA United Air Lines Inc.
2013 1 1 5 N619AA AA American Airlines Inc.

left_join()의 결과는 flight2에 새로 생긴 name 변수이다.

joins 함수 이해하기

키(key)
위의 열에서 색칠된 부분이 “키”에 해당한다. 키는 테이블 간 열을 합칠 때 사용된다.

값(value)
회색으로 칠해진 부분은 “값”에 해당한다.

위의 그림에서는 키와 값이 각각 하나씩 존재하지만, 여러개 존재할 수도 있다.

join은 x 테이블의 각각의 열을 y 테이블의 열과 연결하는 것이다. 아래의 다이어그램은 케이스간 match가 어떻게 이루어지는지 보여준다.

실제 join()에서, match는 점으로 표현된다. 점의 개수는 match의 수를 의미하고 이는 곧 join 결과에서 그만큼의 열이 생성됨을 의미한다.

Inner Join

join 중 가장 단순한 형태가 inner join이다. inner join은 두 테이블의 key가 값을 때 match가 일어나는 형태이다.

inner join의 output은 key, x 테이블의 값(values), y 테이블의 값(values)이 들어있는 새로운 데이터 프레임이다. 명령에서는 by=를 이용하여 dplyr에 어떠한 변수가 key로 사용되는지를 알려준다.

x %>% 
  inner_join(y, by="key")

inner join에서 match되지 못한 열들은 결과에 나열되지 않는다. 이는 즉, 데이터 분석에 inner join이 사용될 때, 손실되는 케이스가 있음을 의미하고 따라서 대부분의 데이터 분석에서 적절한 join 방법은 아니다.

Outer Joins

inner join은 두 테이블 모두에 나타난 관측값만을 결과로 전송한다. outer join의 경우 최소 한 테이블에 나타난 관측값 모두를 결과로 전송한다. outer join에는 3가지 종류가 있다.

  • left joinx의 모든 관측값을 유지한다.
  • right joiny의 모든 관측값을 유지한다.
  • full joinxy에 나타난 모든 관측값을 유지한다.

joins은 key를 중심으로 이루어지며, match되는 key가 없는 경우 NA를 반환한다.

다이어그램으로 표현하면:

이 중 가장 흔히 쓰이는 것은 left join이다: left join에서는 기존의 데이터의 모든 정보가 그대로 반환되기 때문에 부가적인 정보를 기존의 데이터 테이블에 join할 때 유용하게 사용된다.

따라서 left join이 default join으로 사용되어야 한다: 다른 join을 선호할 특별한 이유가 없는 한 left join을 사용하는 것이 좋다. 만약 NA가 있어서는 안되는 경우, 특별히 inner join을 사용할 수는 있지만 특별한 경우가 아니라면 기존 데이터에 손실이 없는 left join을 사용하는 것이 기본이다.

Venn diagram으로 여러 joins을 살펴보면:

예시

두 데이터 테이블이 있다고 가정하자:

clinicName postalCode
A 22120
B 35752
C 56718
D 35752
E 67756
F 69129
G 73455
H 73455
I 76292
over65 postalCode
0.46 35752
0.72 22120
0.93 22120
0.26 92332
0.46 84739
0.94 67756

아래의 다이어그램은 left와 right 테이블의 cases가 어떻게 연결되어 있는지를 시각적으로 보여준다. 그리고 line은 match를 의미한다. 총 5번의 match가 있고 그중 중복되는 case도 존재하는 것을 볼 수 있다. match되지 않은 case 또한 양측의 테이블에 존재한다.

inner join 은 match가 된 짝들을 반환한다. clinic A는 두 번의 match가 있는 것을 볼 수 있는데, 이는 우측의 테이블에서 clinc A와 두 번의 match가 발생하였기 때문이다.

LL %>% inner_join(RR)
clinicName postalCode over65
A 22120 0.72
A 22120 0.93
B 35752 0.46
D 35752 0.46
E 67756 0.94

outer join 은 match가 없는 cases까지도 포함하여 결과로 반환한다. 세부 디테일은 left, right, full join 중 어떤 것을 사용하는지에 따라 달라진다.

left table에서 match되지 않은 결과들을 반환할 때
LL %>% left_join( RR)
clinicName postalCode over65
A 22120 0.72
A 22120 0.93
B 35752 0.46
C 56718 NA
D 35752 0.46
E 67756 0.94
F 69129 NA
G 73455 NA
H 73455 NA
I 76292 NA
right table에서 match되지 않은 결과들을 반환할 때
LL %>%  right_join(RR) 
clinicName postalCode over65
B 35752 0.46
D 35752 0.46
A 22120 0.72
A 22120 0.93
NA 92332 0.26
NA 84739 0.46
E 67756 0.94
both tables에서 match되지 않은 결과들을 반환할 때
LL %>% full_join(RR)
clinicName postalCode over65
A 22120 0.72
A 22120 0.93
B 35752 0.46
C 56718 NA
D 35752 0.46
E 67756 0.94
F 69129 NA
G 73455 NA
H 73455 NA
I 76292 NA
NA 92332 0.26
NA 84739 0.46

2. tidyr - Wide and Narrow

tidyr 패키지의 tidyr::narrow()tidyr::gather() 두 가지 data verbs를 살펴보자.

데이터 테이블은 wide 혹은 narrow의 형태로 표현될 수 있다. 각각은 각각의 이점이 있다.

Wide format의 경우 각 환자 별 sbp (systolic blood pressure)의 전과 후 차이를 도출하는데 유용하다. 하지만 세미나(1)에서 살펴본 내용에 따르면 아래의 데이터는 tidy하지 않다.

BP_wide
subject before after
BHO 120 160
GWB 115 135
WJC 105 145

아래는 narrow format (tidy)이다. 종종 그래프를 그리기 위해서 우리는 데이터를 narrow format으로 표현해야할 경우가 있을것이다.

BP_narrow
subject when sbp
BHO before 160
GWB before 115
WJC after 145
GWB after 135
WJC before 105
BHO after 160

data verbs spread()gather()이 wide format과 narrow format 사이를 변환시켜준다.

gather(): wide -> narrow

데이터 셋의 행(column)의 이름이 변수의 이름이 아닌, 변수의 값인 경우 우리는 데이터가 tidy하지 못하다는 문제를 가지게 된다. 이때 우리는 gather()을 사용한다. 변수의 이름이 아닌 값을 가진 행들은 새로운 변수를 통해 정리되어야 할 필요가 있다. 이 작업을 수행하기 위해서 아래의 3가지 매개변수(parameters)가 필요하다.

  1. key: column이 변수의 이름이 아닌 값을 가지고 있는 경우, 변수 값을 포괄할 새로운 이름이 필요하다. 이때의 새로운 이름이 key가 된다. 위의 예시의 경우 before과 after이 column 이름 위치에 존재하지만 변수의 이름이 아닌 값에 해당한다. 따라서 새로운 이름인 when을 지어주기로 하자. 따라서 keywhen이 된다.

  2. value: 셀에 있는 값들을 통합할 이름. 즉 wide 테이블에서 before과 after 행에 존재하는 값들을 부를 이름을 의미한다. 여기서 이들을 sbp라고 하기로 하자.

  3. 변수가 아닌 값을 대표하는 column(행)의 집합. 여기서는 beforeafter.

BP_narrow1 <-  BP_wide %>%
  gather(key= when, value = sbp, `before`, `after`)  # before or after are legal names so it isn't necessary to use backticks (but it doesn't hurt)
BP_narrow1
subject when sbp
BHO before 120
GWB before 115
WJC before 105
BHO after 160
GWB after 135
WJC after 145

spread(): narrow -> wide

Spreadinggathering과 반대의 작업을 수행한다. 관측값들이 여러 열에 걸쳐 산포되어 있을 때 spread를 사용한다. 이를 수행하기 위해서는 아래의 2가지 매개변수(parameters)가 필요하다:

  1. key: 새로 형성할 데이터 테이블의 column 이름으로 만들고 싶은 값이 들어 있는 기존 테이블의 column. 여기서는 when이 새로 만들 테이블에서 column의 이름이 될 after과 before을 포함하고 있으므로 key가 된다.

  2. value: key 맞게 정렬되어야 할 값들을 가진 기존 테이블에서의 column의 이름. 여기서는 새롭게 만들 테이블에서 after과 before의 키 아래 sbp값들이 값으로 정렬될 것이므로 sbp값을 값으로 가지고 있는 sbp column이 value가 된다.

BP_wide1 <-  BP_narrow %>% 
  spread(key= when, value = sbp)
BP_wide1
subject after before
BHO 160 160
GWB 135 115
WJC 145 105

Discuss

1. 아래와 같은 데이터 테이블을 임의로 만들었다고 하자.

a <- c("Afghanistan","Brazil", "China")
b <- c(745,37737,212258)
c <- c(266,80488,213766)
df_wide <- data.frame(a,b,c)
names(df_wide) <- c("countries","1999", "2000")
df_wide
countries 1999 2000
Afghanistan 745 266
Brazil 37737 80488
China 212258 213766

테이블을 gather을 사용하여 tidy form으로 만들고자 한다.

countries year population
Afghanistan 1999 745
Brazil 1999 37737
China 1999 212258
Afghanistan 2000 266
Brazil 2000 80488
China 2000 213766

아래 어떠한 명령이 들어가야 할까:

df_narrow <- df_wide %>% 
  gather(fill__this__out)
df_narrow

2. 아래의 데이터 테이블은 narrow 형태 인가 wide 형태인가? 다른 형태로 바꾸어보자. (narrow 형태이면 wide 형태로, vice versa)

## # A tibble: 3 x 3
## # Groups:   name [3]
##    name       F      M
## * <chr>   <int>  <int>
## 1 Allen    1836 263375
## 2  Mary 4112464  15151
## 3   Sue  144410    519
## # A tibble: 6 x 3
## # Groups:   name [3]
##    name   sex   value
##   <chr> <chr>   <int>
## 1 Allen     F    1836
## 2  Mary     F 4112464
## 3   Sue     F  144410
## 4 Allen     M  263375
## 5  Mary     M   15151
## 6   Sue     M     519

3. 아래의 결과는 옳은가?

4. Here are two equivalent data tables. What is the “key” variable in the conversion?

3. ggplot2(2)

1) Aesthetics versus fixed attributes

Aesthetics은 그래프의 특징 중 변수들과 연관된 것들이다. (ex. col=as.factor(cyl))

Attribute은 그래프의 특징 중 변수들과 연관이 없는 것들이다. 따라서 특정한 고정 값을 가진다. (ex. col=“red”)

예시

mtcars %>% ggplot(aes(x=wt,y=mpg)) + geom_point(aes(col=as.factor(cyl))) 

mtcars %>% ggplot(aes(x=wt,y=mpg)) + geom_point(col="red") 

Note: attributes는 특정하게 정해진 값이기 때문에 이에 대해 legend가 존재하지 않는다.

2) Theme

theme은 ggplot2에서 non-data를 사용자의 뜻에 따라 변경할 수 있게 해준다.
예를들어 할 수 있는 것들에는:

  • 축 라벨의 글자크기 조정
  • grid lines을 삭제
  • plot에 이름을 표시
  • legend을 그래프의 안으로 위치 변경
  • 그래프의 배경색 변경

theme의 변경은 그래프 자체가 보이는 방식을 바꾸지만 data와는 independent하다. 이러한 것들을 theme elements (i.e. aspects of a ggplot object that are capable of modifying its appearance but are neither directly related to data nor aesthetics associated with data)라고 부른다.

아래의 그래프로 시작해보자:

p <- ggplot2::mpg %>% ggplot( aes(x = cty, y = hwy, color = factor(cyl))) +
  geom_jitter() +
  labs(
    x = "City mileage/gallon",
    y = "Highway mileage/gallon",
    color = "Cylinders"
  )
p

ggplot2의 theme은 다음의 것들로 구성되어 있다:

  • theme elements, data와는 무관한 그래프의 특징. 예를들어 축에 표현되는 텍스트 (ex: axis.text);

  • theme element functions, theme elements를 변경할 수 있도록 해주는 함수 (ex: axis.text = element_text(size = 14));

  • theme functions, 그래프의 전체적인 테마를 바꾸기 위한 함수

p + 
  theme(axis.text = 
          element_text(colour = "blue", size = 15, face = "italic"), 
        axis.text.y = 
          element_text(size = rel(0.7), angle = 90))

  • ready made theme() functions, theme_grey(), theme_bw(), theme_igray()와 같이 이미 만들어진 테마 함수들
library(ggthemes)  #in console: install.packages("ggthemes") to install
p  + theme_igray()

만약 색을 바꾸고 싶은 경우 scale_colour_brewer() 함수를 사용하여 원하는 팔레트를 지정할 수 있다.
ggplot2 help.

p + scale_colour_brewer(palette = "Dark2") 

Theme elements and theme element functions

theme elements는 대응하는 element function을 이용하여 그래프의 특정 오브젝트가 가지는 특징을 바꿀 수 있다.

  • element_text()
  • element_line()
  • element_rect()
  • element_blank()

element_xx()의 함수는 theme element의 attributes를 변형시킬 수 있다 (e.g., color, text size).

그래프에서 다음의 사항을 변경하고 싶을 때:

  • 축 라벨의 글씨 크기를 크게
  • minor grid lines을 제거
  • legend을 그래프의 공간 안으로 이동
  • 그래프 공간의 배경색을 변경

다음의 명령은 위의 변경사항을 실행한다:

p  +
  theme(
    axis.text = element_text(size = 14),
    legend.background = element_rect(fill = "white"),
    legend.position = c(0.14, 0.70),
    panel.grid.minor = element_blank(),
    panel.background = element_rect(fill = "navy")
  )

theme element functions를 자세히 살펴보자:

element_text()

목적: label과 heading에 관여.

##     Argument              Description Default
## 1     family              font family      “”
## 2       face                font face   plain
## 3     colour               font color   black
## 4       size                font size      10
## 5      hjust horizontal justification     0.5
## 6      vjust   vertical justification     0.5
## 7      angle               text angle       0
## 8 lineheight              line height     1.1
element_line()

목적: To draw lines and segments such as graphics region boundaries, axis tick marks and grid lines.

##    Arument    Description Default
## 1   colour     line color   black
## 2     size line thinkness     0.5
## 3 linetype   type of line       1
element_rect()

목적: To draw rectangles. It is mostly used for background elements and legend keys.

##   Arguement              Description Default
## 1      fill               fill color    none
## 2    colour             border color   black
## 3      size thinkness of border line     0.5
## 4  linetype      type of border line       1
element_blank()

목적: To draw nothing.

Arguments: 없음.

예시

다음 그래프를 보고 명령어를 이해해보라.

# Use theme() to modify theme elements
p + labs(title = "Highway vs. city mileage per gallon") +
  theme(
    axis.text = element_text(size = 20),
    plot.title = element_text(size = 20,color = "red"),
    legend.key = element_rect(fill = "black"),
    legend.background = element_rect(fill = "white"),
    legend.position = "right",
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.background = element_rect(fill = "grey40")
  )

Theme functions

theme functions을 이용하면 다른 사용자가 이미 만들어준 theme을 그래프에 적용시킬 수 있다.

library(ggthemes)  #need to install ggthemes
mpg %>% ggplot( aes(x = cty, y = hwy, color = factor(cyl))) +
  geom_jitter() +
  labs(
    x = "City mileage/gallon",
    y = "Highway mileage/gallon",
    color = "Cylinders"
  ) + theme_igray()

Colors in R

colors

hexidecimal color code

색은 RGB의 16진법으로 표현된다. 예를들어, “#0066CC”의 경우 처음 두 자리수는 빨간색의 정도, 그 다음 두 자리는 초록색의 정도, 그리고 마지막은 파란색의 정도를 의미한다. 각각의 정도는 16진법으로 00에서 FF까지로 표현된다. 예를들어 “#FFFFFF”은 하얀색이며, “#990000” 은 짙은 빨간색이다.

예시:

set.seed(955)
# Make some noisily increasing data
dat <- data.frame(xvar = 1:20 + rnorm(20,sd=3),
                  yvar = 1:20 + rnorm(20,sd=3))

ggplot(dat, aes(x=xvar, y=yvar)) +
    geom_point(shape=1) +    # Use hollow circles
    geom_smooth(method=lm, fill="#013A59") + # Add linear regression line
    theme_igray()  #default theme

3) Loess(Locally Weighted Linear Regression)

Linear Regression

mtcars %>% ggplot(aes(x=wt, y=mpg)) +geom_point() +geom_smooth(method="lm") + geom_point(aes(x=mean(wt),y=mean(mpg)),size=5)

Loess(Locally Weighted Linear Regression)

두 개의 연속형 변수 X 와 Y가 있다. 예를들어, mtcars 데이터 테이블에서, X=wt 와 Y=mpg.

mtcars %>% ggplot(aes(x=wt, y=mpg)) +geom_point() +geom_smooth(se=FALSE, method = "loess")

Loess 알고리즘

\(x_0\)를 하나의 관측치라고 하자. 예를들어, \(x_0=3.435\) (3435파운드)이다.

  1. \(x_0\)근방의\(x_i\)들의 일부를 모은다. 이때의 일부를 span이라 한다.
    예를들어, 만약 32개의 자동차 중 span=.4이라면 우리는 중량 3.435 근방의 가장 가까운 13개 (정확히는 0.4*32=12.8)의 관측치를 찾는다 (아래 파란색으로 표현).

  1. \(K_{i0}=K(x_i,x_0)\)를 이용하여 각각의 point에 가중치를 부여한다. \(x_0\)로부터 가장 먼 것은 0의 가중치를 가지고, 가까이 있을 수록 높은 가중치를 가진다.

위의 예시에서는, 중량이 3.435 근방인 경우 1에 가까운 가중치를, 그리고 멀어질 수록 낮은 가중치를 가진다. 모든 빨간 점들은 가중치가 0이다.

  1. \(\widehat{\beta_0}\)\(\widehat{\beta_1}\)\[ \sum_{i=1}^{n} K_{i0}(y_i-\beta_0 -\beta_1x_i)^2. \] 를 최소화하는 값을 구한다. simple linear regression과 다른 점은 여기에 가중치\(K_{i0}\)가 포함된다는 것이다.

  2. \(x_0\)의 적합값: \[\widehat{M}(x_0)=\widehat{\beta_0} + \widehat{\beta_1}x_0\]

이러한 절차를 데이터셋에 주어진 모든 \(x_0\)에 대하여 실행한다. 그리고 \(\widehat{M}(x_0)\) point를 연결시킨다. 우리는 각각의 \(x_0\)에 대하여 서로 다른 \(\widehat{\beta_0}\)\(\widehat{\beta_1}\) 를 얻게 된다. (점들을 어떻게 연결하는지에 대한 구체적인 내용은 생략) 여기서 우리가 이해해야 할 점은 만약 span이 0에 가깝다면 regression line의 정확성(accuracy)은 아주 작은 범위 내에서 한정된다. 따라서 각각의 관측치마다 regression line의 방향이 바뀔 것이고, 그것이 wiggly한 직선을 형성한다. 만약 span이 1에 가깝다면 regression line은 넓은 범위의 관측치에 대해 정확할 것이고, Loess 커브는 직선에 가깝게 형성된다.

mtcars %>% ggplot(aes(x=wt, y=mpg)) +geom_point() +stat_smooth(se=FALSE,method="loess", span=.4)

mtcars %>% ggplot(aes(x=wt, y=mpg)) +geom_point() +stat_smooth(se=FALSE,method="loess", span=.8)

Loess방법은 분포에 대한 아무런 가정이 없다(linearity의 가정이 없음)는 점에서 non parametric 방법에 해당한다.