04-19 05:22
Notice
Recent Posts
Recent Comments
관리 메뉴

Scientific Computing & Data Science

[Data Science / MongoDB] R과 MongoDB 연동하기 (mongolite) 본문

Data Science/MongoDB

[Data Science / MongoDB] R과 MongoDB 연동하기 (mongolite)

cinema4dr12 2017. 2. 17. 00:35

이전 글(R과 MongoDB 연동하기(rmongodb))에서 R의 MongoDB 관련 패키지인 rmongodb를 이용하여 R과 MongoDB를 연동하는 방법에 대해 소개한 바 있다.


그러나 rmongodb 패키지는 CRAN에서 제거되었으며, 이를 대신하여 mongolite 패키지를 사용할 수 있게 되었다.


이번 글에서는 mongolite 패키지를 이용하여 R과 MongoDB를 연동하여 데이터 도큐먼트 저장, 삭제, 업데이트 등을 하는 방법에 대하여 알아보도록 하겠다.


사용된 데이터는 다음 링크를 클릭하여 다운 받도록 한다: Batting.csv

MongoDB 실행하기

R의 Working Directory에 MongoDB 데이터를 저장할 폴더를 하나 생성하고 Command Line Tool에서 다음 명령을 통해 MongoDB를 실행한다:


$  mongodb --dbpath {YOUR_MONGODB_DATA_PATH}

mongolite Package 설치하기

R에서 다음 명령을 입력하여 mongolite를 설치하고 로딩한다.


## intall packages & load them
if (! ("mongolite" %in% rownames(installed.packages()))) { install.packages("mongolite") }
library(mongolite)

MongoDB 연결하기

mongolitemongoDbConnect() 함수를 통해 실행된 MongoDB와 연결한다.


## MongoDB connection
con <- mongolite::mongo(collection = "test_data",
                        db = "test",
                        url = "mongodb://localhost",
                        verbose = TRUE,
                        options = ssl_options())

각 옵션에 대한 자세한 설명은 mongolite의 PDF 문서를 참고하도록 한다.

기존 Collection 삭제

만약 기존 Collection이 존재하는 경우, 테스트를 위해 삭제한다:


## remove existing collection if exists
if(con$count() > 0) con$drop()

CSV 파일로부터 데이터 불러오기

파일로 첨부한 Batting.csv 파일을 Data Frame으로 로딩한다. 단, 해당 파일은 현재 R의 Working Directory 내에 있다고 가정한다:


## read data from CSV file
df <- utils::read.csv("./Batting.csv")

Document 삽입

Document 삽입을 위해 JSON 포맷으로 변환해야 하는 다른 R-MongoDB 연동 패키지와는 달리 mongodblite의 Document를 삽입하는 메써드인 insert()는 Data Frame을 직접 인수로 전달하며, 메써드에서 내부적으로 JSON 포맷으로 변환하여 처리한다.


## insert document as data frame
con$insert(df)

Document가 잘 저장되었는지 확인하기 위해 Command Line Tool에서 다음과 같이 명령을 입력한다:


$ mongo
2017-02-18T22:39:08.368+0900 I CONTROL  [main] Hotfix KB2731284 or later update
is not installed, will zero-out data files
MongoDB shell version: 3.2.11
connecting to: test
$ db.test_data.find().pretty()
{                                                                               
        "_id" : ObjectId("58a8116f3ed55ab41ff12213"),                           
        "playerID" : "aardsda01",                                               
        "yearID" : 2004,                                                        
        "stint" : 1,                                                            
        "teamID" : "SFN",                                                       
        "lgID" : "NL",                                                          
        "G" : 11,                                                               
        "G_batting" : 11,                                                       
        "AB" : 0,                                                               
        "R" : 0,                                                                
        "H" : 0,                                                                
        "X2B" : 0,                                                              
        "X3B" : 0,                                                              
        "HR" : 0,                                                               
        "RBI" : 0,                                                              
        "SB" : 0,                                                               
        "CS" : 0,                                                               
        "BB" : 0,                                                               
        "SO" : 0,                                                               
        "IBB" : 0,                                                              
        "HBP" : 0,                                                              
        "SH" : 0,                                                               
        "SF" : 0,                                                               
        "GIDP" : 0,                                                             
        "G_old" : 11                                                            
}                                                                               
{                                                                               
        "_id" : ObjectId("58a8116f3ed55ab41ff12214"),                           
        "playerID" : "aardsda01",                                               
        "yearID" : 2006,                                                        
        "stint" : 1,                                                            
        "teamID" : "CHN",                                                       
        "lgID" : "NL",                                                          
        "G" : 45,                                                               
        "G_batting" : 43,                                                       
        "AB" : 2,                                                               
        "R" : 0,                                                                
        "H" : 0,                                                                
        "X2B" : 0,                                                              
        "X3B" : 0,                                                              
        "HR" : 0,                                                               
        "RBI" : 0,                                                              
        "SB" : 0,                                                               
        "CS" : 0,                                                               
        "BB" : 0,                                                               
        "SO" : 0,                                                               
        "IBB" : 0,                                                              
        "HBP" : 0,                                                              
        "SH" : 1,                                                               
        "SF" : 0,                                                               
        "GIDP" : 0,                                                             
        "G_old" : 45                                                            
}                                                                               
...

또는, Robomongo를 설치하여 저장된 데이터를 좀 더 쉽게 확인할 수 있다.



누락없이 DB에 Document가 삽입되었는지 확인하려면 원래의 Data Frame와 개수를 비교하면 된다:


## compare number of data
dim(df)[1]
num <- con$count()

정상적으로(누락없이) Document가 삽입되었으면 다음과 같은 실행 결과를 얻을 것이다:


> dim(df)[1]
[1] 95195
> num <- con$count()
> num
[1] 95195

DB로부터 Document 불러오기

이제 원래의 Data Frame(df)을 삭제하고 df에 MongoDB로부터 데이터를 임포트해 보자:


## remove df & import data from MongoDB
rm(df)
df <- con$find(query = '{}')
head(df)
dim(df)

다음과 같은 실행 결과를 얻을 수 있을 것이다:


> rm(df)
> df <- con$find(query = '{}')
 Imported 95195 records. Simplifying into dataframe...
> head(df)
   playerID yearID stint teamID lgID  G G_batting AB R H X2B X3B HR RBI SB CS BB SO IBB HBP SH SF GIDP G_old
1 aardsda01   2004     1    SFN   NL 11        11  0 0 0   0   0  0   0  0  0  0  0   0   0  0  0    0    11
2 aardsda01   2006     1    CHN   NL 45        43  2 0 0   0   0  0   0  0  0  0  0   0   0  1  0    0    45
3 aardsda01   2007     1    CHA   AL 25         2  0 0 0   0   0  0   0  0  0  0  0   0   0  0  0    0     2
4 aardsda01   2008     1    BOS   AL 47         5  1 0 0   0   0  0   0  0  0  0  1   0   0  0  0    0     5
5 aardsda01   2009     1    SEA   AL 73         3  0 0 0   0   0  0   0  0  0  0  0   0   0  0  0    0    NA
6 aardsda01   2010     1    SEA   AL 53         4  0 0 0   0   0  0   0  0  0  0  0   0   0  0  0    0    NA
> dim(df)
[1] 95195    24


만약 yearID가 2000 이상을 불러올 경우 다음과 같이 입력한다:


## import data with yearID above 1999
df <- con$find(query = '{"yearID":{"$gt":1999}}')
head(df)


실행 결과는 다음과 같다:


> df <- con$find(query = '{"yearID":{"$gt":1999}}')
 Imported 15946 records. Simplifying into dataframe...
> head(df)
   playerID yearID stint teamID lgID  G G_batting AB R H X2B X3B HR RBI SB CS BB SO IBB HBP SH SF GIDP G_old
1 aardsda01   2004     1    SFN   NL 11        11  0 0 0   0   0  0   0  0  0  0  0   0   0  0  0    0    11
2 aardsda01   2006     1    CHN   NL 45        43  2 0 0   0   0  0   0  0  0  0  0   0   0  1  0    0    45
3 aardsda01   2007     1    CHA   AL 25         2  0 0 0   0   0  0   0  0  0  0  0   0   0  0  0    0     2
4 aardsda01   2008     1    BOS   AL 47         5  1 0 0   0   0  0   0  0  0  0  1   0   0  0  0    0     5
5 aardsda01   2009     1    SEA   AL 73         3  0 0 0   0   0  0   0  0  0  0  0   0   0  0  0    0    NA
6 aardsda01   2010     1    SEA   AL 53         4  0 0 0   0   0  0   0  0  0  0  0   0   0  0  0    0    NA

Data 업데이트 하기

playerID가 "aardsda01"이고, yearID가 2004인 데이터를 불러와 보자:


> df <- con$find(query = '{"playerID" : "aardsda01", "yearID": 2004}')
 Imported 1 records. Simplifying into dataframe...
> df
   playerID yearID stint teamID lgID  G G_batting AB R H X2B X3B HR RBI SB CS BB SO IBB HBP SH SF GIDP G_old
1 aardsda01   2004     1    SFN   NL 11        11  0 0 0   0   0  0   0  0  0  0  0   0   0  0  0    0    11


데이터를 보면 teamID가 "SFN"으로 되어 있는데, 이것을 "SEA"로 업데이트 해본다:


## update data
df <- con$find(query = '{"playerID" : "aardsda01", "yearID": 2004}')
con$update(query = '{"playerID" : "aardsda01", "yearID": 2004}', update = '{ "$set" : { "teamID" : "SEA"} }')


df를 삭제 후, 해당 조건의 데이터를 불러와서 teamID를 확인해 보자.


> rm(df)
> df <- con$find(query = '{"playerID" : "aardsda01", "yearID": 2004}')
 Imported 1 records. Simplifying into dataframe...
> df
   playerID yearID stint teamID lgID  G G_batting AB R H X2B X3B HR RBI SB CS BB SO IBB HBP SH SF GIDP G_old
1 aardsda01   2004     1    SEA   NL 11        11  0 0 0   0   0  0   0  0  0  0  0   0   0  0  0    0    11

Regular Expression

정규식(Regular Expression)을 이용하여 playerID가 "e"로 시작하는 데이터를 불러오자:


## regular expression
df <- con$find(query = '{"playerID":{"$regex": "^e"}}')
head(df)

실행결과를 살펴보면 다음과 같다:


> df <- con$find(query = '{"playerID":{"$regex": "^e"}}')
 Imported 1684 records. Simplifying into dataframe...
> head(df)
   playerID yearID stint teamID lgID  G G_batting  AB  R  H X2B X3B HR RBI SB CS BB SO IBB HBP SH SF GIDP G_old
1 eaddydo01   1959     1    CHN   NL 15        15   1  3  0   0   0  0   0  0  0  0  1   0   0  0  0    0    15
2 eaganbi01   1891     1    SL4   AA 83        83 302 49 65  11   4  4  43 21 NA 44 54  NA   3 NA NA   NA    83
3 eaganbi01   1893     1    CHN   NL  6         6  19  3  5   0   0  0   2  4 NA  5  5  NA   0 NA NA   NA     6
4 eaganbi01   1898     1    PIT   NL 19        19  61 14 20   2   3  0   5  1 NA  8 NA  NA   6  1 NA   NA    19
5 eagantr01   1901     1    PIT   NL  4         4  12  0  1   0   0  0   2  1 NA  0 NA  NA   0  0 NA   NA     4
6 eagantr01   1901     2    CLE   AL  5         5  18  2  3   0   1  0   2  0 NA  1 NA  NA   0  0 NA   NA     5


예상대로 playerID "e"로 시작하는 데이터가 표시된다.

DB 연결해제

mongolite에는 별다른 DB 연결해제 메써드를 지원하지 않으며 오브젝트(con) 삭제 시 자동으로 DB 연결을 해제한다:


## disconnect
rm(con)


Comments