경기도 인공지능 개발 과정/SQL

SQL SQLite 사용

agingcurve 2022. 4. 29. 11:48
반응형

관계형 데이터베이스로 작업하기

시나리오에 가장 적합한 솔루션은 데이터베이스를 이용하는 것

컴퓨터 메모리를 초과할 수 있는 데이터를 훨씬 쉽게 저장할 수 있음

데이터베이스의 데이터는 사용자가 제공한 조건에 따라 쿼리할 수 있음

기존 레코드를 쉽게 업데이트하고 데이터베이스에 새 레코드를 삽입할 수 있음

관계형 데이터베이스는 테이블과 테이블 관계의 집합 관계형 데이터베이스 테이블은 R의 데이터 프레임과 표현이 동일함

여러 테이블 간 정보를 쉽게 결합할 수 있도록 테이블은 관계를 가질 수 있음

가장 간단한 데이터베이스라고 할 수 있는 SQLite(http://sqlite.org/)에서 시작할 것

SQLite는 이식 가능한 경량 데이터베이스 엔진임

R에서는 SQLite 데이터베이스를 활용하는 데 RSQLite 패키지를 사용함 CRAN에서 설치하려면 다음 코드를 실행함

먼저 SQLite 데이터베이스를 만드는 방법을 알아보자

data/example.sqlite에 예제 데이터베이스를 만들려면 해당 디렉터리를 사용할 수 있어야 함

이 디렉터리가 없다면 만들어야 함 이제 data 디렉터리를 사용할 수 있음

다음으로 RSQLite 패키지를 로드함 데이터베이스 드라이버(SQLite( ))와 데이터베이스 파일(data/example.sqlite)을 제공하여 연결을 생성함 파일은 원래 없었지만, 드라이버가 빈 SQLite 데이터베이스를 나타내는 빈 파일을 생성함

 

SQLite 데이터베이스 만들기

데이터베이스 연결(con)은 사용자와 시스템 사이에 있는 레이어임

관계형 데이터베이스에 대한 연결을 생성함 관계형 데이터베이스로 데이터를 쿼리함 데이터를 가져오거나 업데이트할 수 있음

연결은 연결을 종료하기 전까지 모든 후속 작업에서 사용함

전형적인 관계형 데이터 베이스에서 특정 이름과 데이터 유형으로 테이블에 열을 만듦 레코드를 행으로 삽입하고 기존 레코드를 갱신할 수 있음

관계형 데이터베이스 테이블은 R의 데이터 프레임과 매우 유사함

 

 

install.packages("RSQLite")
if (!dir.exists("data")) dir.create("data")
library(RSQLite)
con <- dbConnect(SQLite(), "data/example.sqlite")

con

# SQLite 데이터베이스 만들기
#데이터 프레임이 준비됨
#이 데이터 프레임을 데이터베이스에 테이블로 저장할 수 있게 dbWriteTable() 함수를
#호출함

example1 <- data.frame(
  id=1:5, type= c("A","A","B","B","C"),
  score = c(8,9,8,10,9), stringsAsFactors = FALSE)

example1

dbWriteTable(con, "example1",example1)


library(nycflights13)

#코드에서 아마 다른 테이블 이름을 사용했어도 같은 데이터를 저장할 것
#마지막으로 dbDisconnect() 함수를 사용하여 데이터베이스 연결을 종료함
#데이터 작업에 더 이상 con을 사용할 수 없음

dbDisconnect(con)

#패키지를 설치했다면 다음과 같이 data() 함수를 호출하여 두 데이터 프레임을 불러옴
data("diamonds", package = "ggplot2")
data("flights", package = "nycflights13")


con <- dbConnect(SQLite(), "data/datasets.sqlite")

dbWriteTable(con, "diamonds", diamonds, row.names=FALSE)
dbWriteTable(con, "flights", flights, row.names=FALSE)
dbDisconnect(con)

class(diamonds)
class(flights)


#diamonds와 flights는 단순히 data.frame 클래스가 아니라 좀 더 복잡한 형태임
#과거에는 이 객체들을 데이터베이스에 저장할 때 다음 코드처럼 as.data.frame() 
#함수를 사용하여 평범한 data.frame 객체로 변형해야 했음
#최근 업데이트에서 tbl_df 객체를 지원하면서 더 이상 그럴 필요가 없어짐

con <- dbConnect(SQLite(), "data/datasets2.sqlite")
dbWriteTable(con, "diamonds", as.data.frame(diamonds), row.names = FALSE)
dbWriteTable(con, "flights", as.data.frame(diamonds), row.names = FALSE)
dbDisconnect(con)

con <- dbConnect(SQLite(), "data/example2.sqlite")

chunk_size <- 10
id <- 0
for (i in 1:6) {
  chunk <- data.frame(id = ((i - 1L) * chunk_size):(i * chunk_size - 1L),
                      type = LETTERS[[i]],
                      score = rbinom(chunk_size,10, (10-i)/10),stringsAsFactors = FALSE)
dbWriteTable(con, "products", chunk, append = i > 1, row.names = FALSE)
}

#각 데이터 덩어리(chunk)는 일부 고정된 데이터와 랜덤한 숫자가 섞여 있는 데이터
#프레임 객체임
#매번 이 레코드를 products 테이블에 추가함
#이 예제와 이전 예제는 다음 차이점이 있음
#dbWriteTable() 함수를 호출할 때 첫 번째 chunk에는 append = FALSE를 사용하여
#데이터베이스에 해당 테이블을 만듦
#이후의 각 chunk에는 append = TRUE를 사용하여 기존 테이블에 추가한다는 것임


dbDisconnect(con)

#SQLite 데이터베이스를 만들면 테이블에 저장된 데이터뿐만 아니라 모든 테이블의
#이름이나 열같은 일부 메타데이터에 접근할 수 있음
#이를 확인하고자 이전에 만든 SQLite 데이터베이스에 연결해 보자


con <- dbConnect(SQLite(), "data/datasets.sqlite")
con

dbExistsTable(con, "diamonds")
dbExistsTable(con, "mtcars")

#이전에 만든 datasets.sqlite에는 diamonds와 flights만 입력했기 때문에
#dbExistsTable() 함수는 올바른 결과를 보여줌
#테이블 존재 여부를 알려 주는 대신 dbListTables() 함수를 사용하여 데이터베이스에
#있는 모든 테이블 목록도 출력할 수 있음

dbListTables(con)
#dbListFields() 함수를 사용하면 특정 테이블에 있는 모든 열(필드) 이름의 목록을 얻을 수 있음
dbListFields(con, "diamonds")
#dbWriteTable() 함수와 반대로 dbReadTable() 함수는 테이블을 데이터 프레임 객체로 읽어 올 수 있음
db_diamonds <- dbReadTable(con, "diamonds")
dbDisconnect(con)

 

#dbListFields() 함수를 사용하면 특정 테이블에 있는 모든 열(필드) 
#이름의 목록을 얻을 수 있음
head(db_diamonds,3)

#bWriteTable() 함수와 반대로 dbReadTable() 함수는 테이블을 데이터 프레임
#객체로 읽어 올 수 있음
head(diamonds,3)

 

#두 데이터 프레임 안의 데이터는 완전히 동일하게 보임
#함수를 사용하여 비교하면 실제로 이 둘은 동일하지 않음
identical() 
identical(diamonds, db_diamonds)

 

#str()을 호출하여 두 데이터 프레임의 구조가 어떤 차이점이 있는지 살펴보자
#첫째, 데이터베이스에서 나온 데이터 프레임의 구조는 다음과 같음
str(db_diamonds)

 

con <- dbConnect(SQLite(), "data/datasets.sqlite")
dbListTables(con)


db_diamonds <- dbGetQuery(con, "select * from diamonds")

head(db_diamonds,3)


#데이터에 있는 모든 유일한 경우를 선택하려면 select distinct를 사용함
#예를 들어 다음 코드는 diamonds에서 가능한 모든 cut의 유일한 값을 구함
dbGetQuery(con, "select distinct cut from diamonds")


#dbGetQuery()는 때로 열이 하나만 있을 때도 항상 data.frame 값을 돌려줌
#값을 원자 벡터로 추출하려면 데이터 프레임에서 첫 번째 열을 선택함
dbGetQuery(con, "select distinct clarity from diamonds")[[1]]


#다음 코드처럼 기존에 있는 열을 사용해서 새로운 열을 만들고, 새로 만든 열을
#사용하여 또 다른 열을 만들려고 한다면 어떻게 될까?
db_diamonds <- dbGetQuery(con,
                          "select carat, price, x * y * z as size, price / size as value_density from diamonds")



#당연히 이러한 식으로는 할 수 없음
#A as B에서 A는 기존 열로 구성되어 있음
#이렇게 꼭 해야 할 때는 중첩된 쿼리를 사용함
#즉, 중첩된 select로 만드는 임시 테이블에서 열을 선택하면 됨
db_diamonds <- dbGetQuery(con, "select *, price / size as value_density from
                          (select carat, price, x*y*z as size from diamonds)")
head(db_diamonds,3)


#데이터베이스 쿼리에서 다음으로 중요한 구성 요소는 조건임
#결과를 만족시키는 조건을 지정하려면 where를 사용해야 함
#예를 들어 cut이 Good인 다이아몬드를 다음과 같이 선택할 수 있음
good_diamonds <- dbGetQuery(con,
                            "select carat, cut, price from diamonds where cut ='Good'")

head(good_diamonds,3)

#cut이 Good인 레코드의 비율이 모든 레코드에서 낮다는 점에 유의하자
nrow(good_diamonds) / nrow(diamonds)

#동시에 만족해야 하는 조건이 여러 가지가 있을 때는 이러한 조건을 조합하려고 and를 사용할 수 있음
#예를 들어 cut이 Good이고, color가 E인 모든 레코드를 선택해 보자

good_e_diamonds <- dbGetQuery(con,
                              "select carat, cut, color, price from diamonds where cut = 'Good' and color = 'E'")
head(good_e_diamonds,3)

 

nrow(good_e_diamonds) / nrow(diamonds)


# 이와 비슷한 연산자로는 or와 not이 있음
# 간단한 논리 연산자 외에도 필드 값이 주어진 집합에 포함되는지 알고자 레코드를
# 검사할 때 in을 사용할 수 있음
# 예를 들어 color가 E와 F인 레코드를 선택할 수 있음

color_ef_diamonds <- dbGetQuery(con, "select carat, cut, color, price from diamonds where color in ('E','F')")

nrow(color_ef_diamonds)

 

#다음 테이블로 결과를 검증할 수 있음
table(diamonds$color)

#in을 사용하려면 한 집합을 지정해야 함
#in과 마찬가지로 범위를 지정할 때 between A and B를 사용할 수 있음

some_price_diamonds <- dbGetQuery(con, "select carat, cut, color, price from diamonds where price between 5000 and 5500")

nrow(some_price_diamonds)

#문자형 열에 유용한 연산자로 like가 있음
#이것은 비슷한 문자형 패턴으로 레코드를 필터링할 수 있음
#예를 들어 cut 변수가 Good으로 끝나는 레코드를 모두 선택할 수 있음
#즉, Good이나 Very Good이 선택될 수 있는데, like '%Good'처럼 표기하면 됨

good_cut_diamonds <- dbGetQuery(con, "select carat, cut, color, price from diamonds where cut like '%Good'")

diamond_selector <- data.frame(cut = c("Ideal","Good","Fair"),
                               color = c("E","I","D"), clarity = c("VS1","I1","IF"), stringsAsFactors = FALSE)
diamond_selector

dbWriteTable(con, "diamond_selecotr", diamond_selector, row.names = FALSE, overwrite = TRUE)

'경기도 인공지능 개발 과정 > SQL' 카테고리의 다른 글

[SQL] 데이터 그룹  (0) 2022.08.12
SQL Mongo DB 활용  (0) 2022.04.28
SQL 활용  (0) 2022.04.22
SQL 기초  (0) 2022.04.22
SQL mysql 실습 셋팅  (0) 2022.04.20