options(jupyter.rich_display=FALSE)

리스트

- 이상한 자료형

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

예제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]]
IR2021[[c(1,2)]]
  • IR2021[[1]][2]와 결과가 같음
IR2021[[1:3]]
IR2021[[c(1,3)]]
#IR2021[[1]][3]

$연산자

IR2021$names

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

IR2021[['names']]

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

IR2021$n
IR2021[['n']]

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

IR2021$n
IR2021$na
IR2021$name
  • 특히 마지막 IR2021$name은 마치 오타를 허용해주는 느낌이다.

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

IR2021$ames
IR2021$es

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

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

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

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

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

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

rslt = cal(4,3)
rslt$add
rslt$sub

- 아래와 같이 쓰지는 않음

cal(4,3)$add
cal(4,3)$sub

숙제

- 기본적인 자료형 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)
num <- sum((x-mean(x))*(y-mean(y)))
num
[1] 6.206896
den <- sqrt(sum((x-mean(x))^2))*sqrt(sum((y-mean(y))^2))
den
[1] 122.7962
normal <- num/den
normal
[1] 0.05054633

보충학습

x

${\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
mean(x)

(풀이)

$$\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] 6.206896
B=0 
for (i in 1:100) B=B+(x[i]-mean(x))**2
B=sqrt(B)
B
[1] 11.24123
C=0 
for (i in 1:100) C=C+(y[i]-mean(y))**2
C=sqrt(C)
C
[1] 10.92373
A/(B*C)
[1] 0.05054633

(다른풀이)

sum((x-mean(x))*(y-mean(y))) / (sqrt(sum((x-mean(x))**2)) * sqrt(sum((y-mean(y))**2)))

(다른풀이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*2+ 2*3+ 3*4

이러한 성질을 이용하면

xx= x-mean(x) 
yy= y-mean(y)
((xx %*% yy) / (sqrt(xx %*% xx  )* sqrt(yy %*% yy  )))
Error in eval(expr, envir, enclos): 객체 'xx'를 찾을 수 없습니다
Traceback: