options(jupyter.rich_display=FALSE)

강의영상

- (1/5) 리스트 (1)

- (2/5) 리스트 (2)

- (3/5) 리스트 (3)

- (4/5) 리스트 (4)

- (5/5) 리스트 (5)

R도서 참고자료

기말고사

- 중간고사와 비슷하게 낼 예정. 범위도 거의 비슷.

- 중간고사때 까지의 내용만 극한으로 단련해도 어느정도는 풀 수 있을 거에요.

- 코드를 좀 더 예쁘게 효율적으로 만들기 위한 다양한 문법 및 기능이 필요한데 중간~기말 이후에는 그것을 채우는 과정

- 수업목표:

  • 문제상황 (어떠한 것을 계산해야 하는 일이 생길때) 알고리즘을 머리속에 떠올릴 수 있다.
  • 머리속에 떠올린 알고리즘을 기본적인 제어문과 반복문을 통하여 구현할 수 있다. (이미 한 내용, 그런데 지금부터는 좀 더 예쁘고 효율적으로 구현하는 방법을 설명하겠습니다)

리스트

- 이상한 자료형

- 제가 굉장히 많이 사용하는 자료형태.. 그런데 왜 쓰는지 이유를 물어보면 딱히 잘 모르겠어요

예제1

- 리스트를 선언하는 방법

lst = list(5:10,c("A","B","C"),matrix(c(T,T,F,T),ncol=2))
lst
[[1]]
[1]  5  6  7  8  9 10

[[2]]
[1] "A" "B" "C"

[[3]]
     [,1]  [,2]
[1,] TRUE FALSE
[2,] TRUE  TRUE
  • 리스트의 첫번째 원소 = 숫자로 이루어진 벡터
  • 리스트의 두번째 원소 = 문자로 이루어진 벡터
  • 리스트의 세번째 원소 = True / False로 이루어진 매트릭스

- 리스트의 각 원소를 추출하는 방법

lst[[1]]
[1]  5  6  7  8  9 10
lst[[2]]
[1] "A" "B" "C"
lst[[3]]
     [,1] [,2] 
[1,] TRUE FALSE
[2,] TRUE  TRUE
lst[[1]]+3
[1]  8  9 10 11 12 13

- 리스트의 길이

length(lst)
[1] 3

- 왜 리스트를 쓰는가? (1) 함수에서 여러개의 리턴값을 주는 효과 (2) 정리의 효과

  • 명확한 이점: 함수의 리턴값을 여러개
  • 그외의 이점: 저도 솔직히 잘 모르겠어요.
  • 벡터, 매트릭스, 데이터프레임와 같이 기능상의 이점이 있는것 같진 않아요.
  • 그런데 자료를 저장하고 정리하기에 좋아요 (제가 정리하는걸 좋아하는것 같아요)

예제2

mid = list(c('hynn','iu','gd'),c(100,95,100))
mid
[[1]]
[1] "hynn" "iu"   "gd"  

[[2]]
[1] 100  95 100
names(mid)
NULL
names(mid)<-c('names','score')
mid
$names
[1] "hynn" "iu"   "gd"  

$score
[1] 100  95 100

- 보기에 깔끔하다.

- 데이터에 접근하기도 좋다.

mid$names
[1] "hynn" "iu"   "gd"  
mid$score
[1] 100  95 100

- 물론 아래와 같이 접근할수도 있다.

mid[[1]]
[1] "hynn" "iu"   "gd"  
mid[[2]]
[1] 100  95 100

- 리스트를 복사후 재생성하기에 좋음

mid
$names
[1] "hynn" "iu"   "gd"  

$score
[1] 100  95 100
final = mid
final
$names
[1] "hynn" "iu"   "gd"  

$score
[1] 100  95 100
final$score = mid$score - 10
final$score
[1] 90 85 90
final
$names
[1] "hynn" "iu"   "gd"  

$score
[1] 90 85 90

- 리스트를 묶어서 새로운 리스트를 또 만들 수도 있음

IR2021 <- list(mid,final)
IR2021
[[1]]
[[1]]$names
[1] "hynn" "iu"   "gd"  

[[1]]$score
[1] 100  95 100


[[2]]
[[2]]$names
[1] "hynn" "iu"   "gd"  

[[2]]$score
[1] 90 85 90

- 리스트원소에 이름을 붙여주면

names(IR2021)
NULL
names(IR2021) <- c("mid","final")
IR2021
$mid
$mid$names
[1] "hynn" "iu"   "gd"  

$mid$score
[1] 100  95 100


$final
$final$names
[1] "hynn" "iu"   "gd"  

$final$score
[1] 90 85 90

IR2021$final$score
[1] 90 85 90

- 아래와 같이 선언하는 것도 깔끔해보인다.

IR2021 = list(names=mid$names, mid=mid$score, final=final$score) # 리스트의 구성요소와 이름을 동시에 선언 
IR2021
$names
[1] "hynn" "iu"   "gd"  

$mid
[1] 100  95 100

$final
[1] 90 85 90

리스트의 서브셋팅

IR2021
$names
[1] "hynn" "iu"   "gd"  

$mid
[1] 100  95 100

$final
[1] 90 85 90

[연산자: 리스트를 리턴

IR2021[1]
$names
[1] "hynn" "iu"   "gd"  
IR2021[1:2]
$names
[1] "hynn" "iu"   "gd"  

$mid
[1] 100  95 100
IR2021[c(1,3)]
$names
[1] "hynn" "iu"   "gd"  

$final
[1] 90 85 90
IR2021[-2]
$names
[1] "hynn" "iu"   "gd"  

$final
[1] 90 85 90

[[ 연산자: 리스트의 요소를 추출함

IR2021[[1]]
[1] "hynn" "iu"   "gd"  
IR2021[[2]]
[1] 100  95 100

- 아래는 동작하지 않음

IR2021[[-1]]
Error in IR2021[[-1]]: invalid negative subscript in get1index <real>
Traceback:

- 아래는 의도와 다르게 동작함

IR2021[[1:2]]
[1] "iu"
IR2021[[c(1,2)]]
[1] "iu"
  • IR2021[[1]][2]와 결과가 같음
IR2021[[1:3]]
Error in IR2021[[1:3]]: recursive indexing failed at level 2

Traceback:
IR2021[[c(1,3)]]
#IR2021[[1]][3]
[1] "gd"

$연산자

IR2021$names
[1] "hynn" "iu"   "gd"  

[['names']]와 같은 사용도 가능

IR2021[['names']]
[1] "hynn" "iu"   "gd"  

- 언뜻 생각하면 IR2021$namesIR2021[['names']] 의 기능은 같으므로 이 경우에는 $[[를 서로 바꿔도 될것 같다. 하지만 항상 그런 것은 아니다.

IR2021$n
[1] "hynn" "iu"   "gd"  
IR2021[['n']]
NULL

-$연산자와 [[연산자의 차이는 파샬매칭(partial matching)을 허용하느냐 하지않느냐의 차이다.

IR2021$n
[1] "hynn" "iu"   "gd"  
IR2021$na
[1] "hynn" "iu"   "gd"  
IR2021$name
[1] "hynn" "iu"   "gd"  
  • 특히 마지막 IR2021$name은 마치 오타를 허용해주는 느낌이다.

- 그런데 아래는 동작하지 않음

IR2021$ames
NULL
IR2021$es
NULL

리스트의 응용: 함수의 return으로 사용

- R에서는 일반적으로 하나의 오브젝트만 리턴함

- 하지만 리스트를 사용하면 다중리턴을 지원하는 것처럼 느낄 수 있음.

cal= function(x,y){
    return(list(add=x+y, sub=x-y, mul=x*y, dic=x/y))
}
cal(2,3)
$add
[1] 5

$sub
[1] -1

$mul
[1] 6

$dic
[1] 0.6666667

- 이런일이 있으면 그냥 cal_add, cal_mul, cal_sub, cal_div 처럼 함수를 4개 구현하면 되는것이 아닌가? $\to$ 물론 그래도 가능하지만 코드가 지저분해 지니까

- 함수의 결과값을 저장하여 아래와 같이 사용

rslt = cal(4,3)
rslt$add
[1] 7
rslt$sub
[1] 1

- 아래와 같이 쓰지는 않음

cal(4,3)$add
[1] 7
cal(4,3)$sub
[1] 1

숙제

- 기본적인 자료형 vector, matrix, list에 기능을 스스로 정리해보고 요약해볼것 (제출의무 없음)

  • 벡터의 길이를 재려면 어떻게 해야하는지?
  • 매트릭스의 차원은 어떻게 알 수 있는지?
  • 리스트의 원소에 접근하려면?
  • $n\times 1$ 매트릭스 혹은 $1\times n$ 매트릭스를 쓰면 되는데 왜 굳이 벡터를 만들었을까?

- 벡터 ${\bf x}$와 벡터 ${\bf y}$를 아래의 코드를 이용해 표준 정규분포에서 생성하라. (표준정규분포를 모른다면 질문하거나 네이버 구글에서 스스로 찾아볼것)

x=rnorm(100)
y=rnorm(100)

아래의 수식을 계산하는 코드를 작성하라.

$$\frac{\sum_{i=1}^{100}(x_i-\bar{x})(y_i-\bar{y})}{\sqrt{\sum_{i=1}^{100}(x_i-\bar{x})^2}\sqrt{\sum_{i=1}^{100}(y_i-\bar{y})^2}}$$

단 $\bar{x}=\frac{1}{100}\sum_{i=1}^{100}x_i$로 정의한다.

x=rnorm(100)
y=rnorm(100)

보충학습

x
  [1] -1.34195186 -0.85612995 -1.09994510 -0.52712671 -0.96108745  0.43294735
  [7] -0.13052246 -1.65458005  1.55086554  0.88036601 -1.62934144  0.09050529
 [13] -0.31266135  0.06725000  0.74022593 -0.09217845  0.94826123 -0.37638526
 [19]  1.05201467  0.63982774 -0.16251479  0.60216102 -0.36023578  2.25220656
 [25] -0.99538800 -0.76112568  0.90719870 -0.16530389 -0.63598707 -1.56638152
 [31] -0.38664357  1.38393375 -1.36055810  0.17380230  0.83021234  0.44171935
 [37]  0.96312932  1.15326736 -1.47873860 -1.24613250 -3.26079697  0.59937020
 [43]  1.73490956 -0.29685605  0.38467151 -0.68211471 -0.90435763  1.38694961
 [49] -0.91639458 -1.04633026 -0.82508397  0.92621767  0.90406879 -0.35989507
 [55] -0.77384072  0.46544269 -0.41319154 -0.25227959 -0.55143134 -1.00881100
 [61] -0.63920795  0.86356587 -2.00842150 -2.80548750  1.27538116  0.17846435
 [67] -0.11627651 -1.95479833 -0.47060548 -2.13113365  1.27101358 -2.11915432
 [73] -1.33631120 -0.03854028 -0.01754093 -0.29509103 -0.08825048  1.38765285
 [79]  0.02008001  1.49634505 -0.64889609  1.09336952  0.17255440 -0.40512134
 [85]  0.89159556  0.68433663  0.33741577  0.44028690 -0.64519602  0.97174893
 [91]  1.37073087 -0.35971925  0.34607400  1.03844970 -0.76692713  0.11986849
 [97]  1.06544295 -0.73896215 -1.83669247 -0.87349548

${\bf x} = (x_1,x_2,\dots, x_{100})=(-1.34195186 ,-0.85612995,\dots, -0.87349548)$

$\frac{1}{100}\sum_{i=1}^{100} x_i =\frac{1}{100}(x_1+x_2+\dots +x_{100})=\frac{1}{100}(-1.34195186 + (-0.85612995) + \dots (-0.87349548))$

코드상으로는 아래와 같이 계산할 수 있겠음

sum(x)/100 # xbar
[1] -0.1315223
mean(x)
[1] -0.1315223

(풀이)

$$\frac{\sum_{i=1}^{100}(x_i-\bar{x})(y_i-\bar{y})}{\sqrt{\sum_{i=1}^{100}(x_i-\bar{x})^2}\sqrt{\sum_{i=1}^{100}(y_i-\bar{y})^2}}=\frac{A}{BC}$$

A=0 
for (i in 1:100) A=A+(x[i]-mean(x))*(y[i]-mean(y))
A
[1] 8.642164
B=0 
for (i in 1:100) B=B+(x[i]-mean(x))**2
B=sqrt(B)
B
[1] 10.53507
C=0 
for (i in 1:100) C=C+(y[i]-mean(y))**2
C=sqrt(C)
C
[1] 10.54876
A/(B*C)
[1] 0.07776485

(다른풀이)

sum((x-mean(x))*(y-mean(y))) / (sqrt(sum((x-mean(x))**2)) * sqrt(sum((y-mean(y))**2)))
[1] 0.07776485

(다른풀이2)

벡터의 내적: ${\bf x}=(x_1,\dots,x_{100})$ 라고 하고, ${\bf y}=(y_1,\dots,y_{100})$ 라고 할때 두 벡터의 내적은 아래와 같이 계산한다.

$${\bf x} \cdot {\bf y} = x_1 y_1 + \dots + x_{100}y_{100}$$

x_ <- c(1,2,3)
y_ <- c(2,3,4)
x_ %*% y_
     [,1]
[1,] 20  
1*2+ 2*3+ 3*4
[1] 20

이러한 성질을 이용하면

xx= x-mean(x) 
yy= y-mean(y)
((xx %*% yy) / (sqrt(xx %*% xx  )* sqrt(yy %*% yy  )))
     [,1]      
[1,] 0.07776485