일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- R
- 빅 데이타
- Big Data
- WebGL
- 빅데이타
- 김양재 목사님
- Statistics
- 데이터 과학
- probability
- 확률
- 우리들교회
- data science
- 몽고디비
- nodeJS
- 인공지능
- MongoDB
- c++
- 빅데이터
- No SQL
- node.js
- 빅 데이터
- 통계
- Artificial Intelligence
- 김양재 목사
- Machine Learning
- 주일설교
- 딥러닝
- Deep learning
- openCV
- 김양재
- Today
- Total
Scientific Computing & Data Science
[Data Science / MongoDB] R과 MongoDB 연동하기 (rmongodb) 본문
[Data Science / MongoDB] R과 MongoDB 연동하기 (rmongodb)
cinema4dr12 2014. 6. 3. 16:22이번 글에서는 MongoDB의 응용으로서 통계 분석의 오픈소스 S/W로 널리 알려진 R에서 MongoDB를 연동하는 방법에 대해 소개하고자 한다.
R용 MongoDB 패키지 설치 및 불러오기
우선 가장 먼저할 일은 R에서 MongoDB를 연동하는 패키지인 rmongodb를 설치하는 것이다:
> install.packages("rmongodb")
설치가 완료되면 라이브러리(패키지)를 불러온다:
> library(rmongodb)
MongoDB 서버 열기
R에서 MongoDB를 연결하기 전에 MongoDB 서버를 작동시킨다. 일단은 Command Line Tool(Mac에서는 Terminal, Winodws에서는 Console)을 이용하여 MongoDB 로컬 서버를 열도록 하겠다.
$ mongod -dbpath /{YOUR_MONGODB_DATA_PATH}/
R에서 MongoDB 연결
다시 R로 돌아와 작동 중인 MongoDB와 연결하기 위해 다음과 같이 입력한다:
> mongo = mongo.create(host = "localhost")
변수 mongo는 연결된 MongoDB의 인스턴스를 갖는다.
연결이 성공적으로 되었는지 확인하려면 다음과 같이 입력한다:
> mongo.is.connected(mongo)
[1] TRUE
결과가 TRUE이면 성공적으로 연결이 되었음을 의미한다.
테스트용 데이터 입력
테스트를 위해 MongoDB 쉘(Mac: Terminal, Windows: Console)을 연결한다:
$ mongo
test라는 이름의 db를 생성하고 users 컬렉션에 다음과 같이 데이터를 삽입한다:
> use test
switched to db test
> db.users.insert({name: "gchoi", age: 37})
> db.users.insert({name: "jmpark", age: 25})
> db.users.find().pretty()
{
"_id" : ObjectId("538d8cd7c5133151e018bdc9"),
"name" : "gchoi",
"age" : 37
}
{
"_id" : ObjectId("538d8ce1c5133151e018bdca"),
"name" : "jmpark",
"age" : 25
}
R에서 현재 등록된 db 리스트를 확인하려면 다음과 같이 입력한다:
> mongo.get.databases(mongo)
[1] "test"
test db에 등록된 컬렉션 리스트를 확인하려면 다음과 같이 입력한다:
> mongo.get.database.collections(mongo, db = "test")
[1] "test.users"
데이터 쿼리
다음의 예는 test db의 users 컬렉션의 데이터를 확인하는 것이다:
> find_all = mongo.find.all(mongo, ns = "test.users")
경고메시지:
In mongo.cursor.to.list(cursor) :
This fails for most NoSQL data structures. I am working on a new solution
> find_all
_id name age
val 0 "gchoi" 37
val 1 "jmpark" 25
놀랍게도 데이터가 테이블 형식으로 정리되어 출력된다. 옵션 중 ns는 데이터를 검색하고자 하는 네임스페이스(namespace)이다. 형식은 database.collection이 된다.
만약 test.users에서 name이 "gchoi"를 검색하는 쿼리는 다음과 같다:
> tmp = mongo.find.one(mongo, ns = "test.users", list(name="gchoi"))
> tmp
_id : 7 538d8cd7c5133151e018bdc9
name : 2 gchoi
age : 1 37.000000
또는 age가 25인 user를 검색하는 쿼리는 다음과 같다:
> tmp = mongo.find.one(mongo, ns = "test.users", list(age=25))
> tmp
_id : 7 538d8ce1c5133151e018bdca
name : 2 jmpark
age : 1 25.000000
데이터 입력하기
Mongo 쉘에서 test.users 컬렉션에 데이터를 입력하는 방법은 다음과 같다:
> db.users.insert({name: "tjkwak", age: 32L})
동일한 명령을 R에서 수행하려면 다음과 같이 입력한다:
> ns = "test.users"
> buf = mongo.bson.buffer.create()
> mongo.bson.buffer.append(buf, "name", "tjkwak")
[1] TRUE
> mongo.bson.buffer.append(buf, "age", 32L)
[1] TRUE
> b = mongo.bson.from.buffer(buf)
> mongo.insert(mongo, ns, b)
[1] TRUE
> mongo.find.all(mongo, ns)
_id name age
val 1 "gchoi" 37
val 0 "jmpark" 25
val 1 "tjkwak" 32
무척이나 복잡해 보인다. 위의 내용을 정리해 보면,
- 네임스페이스(ns), 즉, database.collection을 정의한다.
- bson 버퍼 인스턴스(buf)를 생성한다.
- buf에 데이터를 입력한다.
- buf로부터 bson 데이터(b)를 생성한다.
- bson 데이터를 입력한다.
그러나, 사실 이 과정을 한 줄의 명령어로 수행할 수 있다:
> mongo.insert(mongo, ns, list(name="hskim", age=37L))
[1] TRUE
> mongo.find.all(mongo, ns)
_id name age
val 1 "gchoi" 37
val 1 "jmpark" 25
val NA "tjkwak" 32
val 1 "hskim" 37
데이터 업데이트
R에서 만약 "gchoi"의 "age"를 37에서 38로 업데이트 하려면 다음과 같이 입력한다:
> mongo.update(mongo, ns, list(name="gchoi"), list(name="gchoi", age=38L))
[1] TRUE
bson 데이터로부터 데이터 가져오기
Mongo 쉘에서 다음과 같이 데이터가 저장되어 있다고 하자:
> db.users.find().pretty()
{
"_id" : ObjectId("544fa59e75b4d0ef59342106"),
"name" : "gchoi",
"age" : 37
}
{
"_id" : ObjectId("544fa5ad75b4d0ef59342107"),
"name" : "jmpark",
"age" : 25
}
{
"_id" : ObjectId("544fa5f875b4d0ef59342108"),
"name" : "tjkwak",
"age" : 32
}
{
"_id" : ObjectId("544fa62875b4d0ef59342109"),
"name" : "hskim",
"age" : 37
}
이제 R에서 저장된 데이터 중 "name"이 "gchoi"인 데이터를 찾기 위해 다음과 같이 입력한다:
> ns = "test.users";
> tmp = mongo.find.one(mongo, ns = ns, list(name="gchoi"));
> tmp
_id : 7 544fa59e75b4d0ef59342106
name : 2 gchoi
age : 1 37.000000
tmp는 bson 포맷의 데이터이며, "age" 키값에 대한 필드값을 읽으려면 다음과 같이 입력한다:
> age = mongo.bson.value(tmp, 'age')
> age
[1] 37
CSV 파일로부터 데이터 입력하기
CSV 파일로부터 얻어온 데이터를 일괄적으로 MongoDB에 입력하는 방법에 대해 알아보자.
우선 다음의 CSV 파일을 다운받는다:
이 파일을 R의 현재 working directory로 복사(또는 이동)한다.
현재 working directory에서 다음 .R 파일을 작성한다:
mongoTest = function() {
# Import "rmongodb" package
library(rmongodb);
# Import CSV file
don = read.csv("contribution.csv");
# Create mongo instance
mongo = mongo.create(host = "localhost");
# Assign db & collection (database.collection)
ns = "test.contribution";
if(mongo.is.connected(mongo)) { # if mongodb is successfully connected
rows = nrow(don); # Get the total number of data
# For each row read from CSV file and insert it into mongodb
for(i in 1:rows) {
mongo.insert(mongo, ns, list(Gender=as.character(don[i,1]), ClassYear=as.numeric(don[i,2]), MaritalStatus=as.character(don[i,3]), Major=as.character(don[i,4]), NextDegree=as.character(don[i,5]), FY04Giving=as.numeric(don[i,6]), FY03Giving=as.numeric(don[i,7]), FY02Giving=as.numeric(don[i,8]), FY01Giving=as.numeric(don[i,9]), FY00Giving=as.numeric(don[i,10]) ) );
}
}
}
파일이름은 어느 것이나 상관없으나 편의상 함수 이름과 동일하게 "mongoTest.R"로 하였다.
R의 console 윈도우에서 mongoTest.R을 로딩한다:
> source('{YOUR_WORKING_DIRECTORY}/mongoTest.R')
R console에서 mongoTest() 함수를 실행한다:
> mongoTest()
Mongo 쉘에서 데이터가 바르게 입력되었는지 확인한다:
> db.contribution.find().pretty()
{
"_id" : ObjectId("538e7af5a3ce27256fa722d9"),
"Gender" : "M",
"ClassYear" : 1957,
"MaritalStatus" : "M",
"Major" : "History",
"NextDegree" : "LLB",
"FY04Giving" : 2500,
"FY03Giving" : 2500,
"FY02Giving" : 1400,
"FY01Giving" : 12060,
"FY00Giving" : 12000
}
{
"_id" : ObjectId("538e7af5a3ce27256fa722da"),
"Gender" : "M",
"ClassYear" : 1957,
"MaritalStatus" : "M",
"Major" : "Physics",
"NextDegree" : "MS",
"FY04Giving" : 5000,
"FY03Giving" : 5000,
"FY02Giving" : 5000,
"FY01Giving" : 5000,
"FY00Giving" : 10000
}
{
"_id" : ObjectId("538e7af5a3ce27256fa722db"),
"Gender" : "F",
"ClassYear" : 1957,
"MaritalStatus" : "M",
"Major" : "Music",
"NextDegree" : "NONE",
"FY04Giving" : 5000,
"FY03Giving" : 5000,
"FY02Giving" : 5000,
"FY01Giving" : 5000,
"FY00Giving" : 10000
}
{
"_id" : ObjectId("538e7af5a3ce27256fa722dc"),
"Gender" : "M",
"ClassYear" : 1957,
"MaritalStatus" : "M",
"Major" : "History",
"NextDegree" : "NONE",
"FY04Giving" : 0,
"FY03Giving" : 5100,
"FY02Giving" : 200,
"FY01Giving" : 200,
"FY00Giving" : 0
}
Type "it" for more
>
물론 더 많은 데이터가 출력되겠지만 생략하였다. 명령 it를 입력하면 계속하여 데이터를 출력할 수 있다.
CSV 파일의 데이터 형식이나 컬럼(column) 길이에 따라 작성하는 함수 형태가 조금씩 달라지겠지만 요령은 동일하기 때문에 상황에 맞게 수정하여 쓰면 될 것이다.
다시 역으로 MongoDB에 저장된 데이터를 가져오도록 하겠다. 앞부분에서 언급한 바와 같이 MongoDB 인스턴스(mongo)를 생성하고, mongo.find.all 함수를 이용한다:
> library(rmongodb)
> don = mongo.find.all(mongo, ns = "test.contribution")
다음에 오류가 있습니다mongo.is.connected(mongo) : 객체 'mongo'를 찾을 수 없습니다
> mongo = mongo.create(host = "localhost");
> don = mongo.find.all(mongo, ns = "test.contribution")
경고메시지:
In mongo.cursor.to.list(cursor) :
This fails for most NoSQL data structures. I am working on a new solution
가져온 데이터를 don이라는 변수에 저장하였는데 데이터 타입(클래스 형식)은 matrix이다:
> class(don)
[1] "matrix"
R에서 데이터를 취급할 때 matrix 보다는 data frame 형식이 편리하기 때문에 클래스 형식을 data frame으로 변환한다:
> don = as.data.frame(don)
> class(don)
[1] "data.frame"
don의 데이터 필드에 대해 살펴보자:
> names(don)
[1] "_id" "Gender" "ClassYear" "MaritalStatus" "Major"
[6] "NextDegree" "FY04Giving" "FY03Giving" "FY02Giving" "FY01Giving"
[11] "FY00Giving"
이제 R에서 데이터베이스의 쿼리와 같은 효과로 데이터를 처리할 수 있다. 예를 들어 기부자의 분포를 성별(Gender) 분포를 확인해 보자. 그런데 우선 짚고 넘어가야할 부분이 각 데이터의 타입문제이다. don$Gender의 데이터 형식을 확인해보면:
> class(don$Gender)
[1] "list"
list 형식으로 되어있음을 알 수 있다. 사실 데이터 취급 시 list 형식이 큰 문제는 없을 것으로 보이지만 데이터를 출력해 보면 쓸데 없는 정보가 포함된다:
> don$Gender
$val
[1] "M"
$val
[1] "F"
$val
[1] "F"
$val
[1] "F"
$val
[1] "M"
...
일괄적으로 $val이 나온다. 보다 깔끔한 데이터를 위해 다음과 같이 데이터 형식을 변환한다:
> don$Gender = as.character(don$Gender)
> don$Gender
[1] "M" "M" "F" "M" "M" "F" "F" "F" "M" "M" "F" "F" "M" "M" "F" "F" "M" "M" "F" "M" "F"
[22] "F" "M" "M" "F" "M" "F" "M" "F" "M" "M" "F" "M" "F" "M" "F" "M" "M" "M" "M" "M" "M"
[43] "M" "M" "M" "M" "F" "M" "F" "M" "M" "M" "M" "M" "F" "M" "F" "M" "F" "M" "F" "F" "M"
[64] "M" "F" "M" "F" "M" "M" "F" "M" "M" "M" "M" "F" "M" "F" "M" "F" "M" "F" "M" "M" "M"
[85] "M" "F" "M" "M" "F" "M" "F" "M" "F" "M" "F" "M" "M" "F" "M" "F" "F" "F" "M" "M" "M"
[106] "F" "M" "M" "M" "M" "M" "F" "M" "F" "M" "M" "M" "M" "M" "M" "M" "F" "M" "F" "F" "M"
[127] "M" "M" "M" "F" "M" "M" "M" "M" "M" "F" "F" "M" "M" "M" "M" "M" "F" "F" "M" "M" "M"
[148] "F" "M" "F" "M" "F" "M" "F" "M" "F" "M" "F" "M" "F" "F" "M" "M" "F" "M" "M" "F" "M"
[169] "M" "M" "F" "M" "F" "F" "M" "M" "M" "M" "M" "F" "F" "F" "M" "M" "M" "M" "M" "M" "F"
[190] "M" "F" "M" "F" "M" "M" "M" "F" "M" "F" "M" "F" "F" "F" "F" "M" "F" "F" "M" "M" "F"
[211] "M" "M" "M" "F" "M" "F" "M" "M" "M" "F" "M" "F" "F" "F" "F" "M" "F" "F" "F" "F" "F"
[232] "F" "F" "M" "M" "F" "F" "F" "M" "M" "F" "F" "M" "F" "M" "F" "M" "F" "F" "M" "M" "F"
...
보다 깔끔한 형식의 데이터로 정리되었다. 다음과 같이 입력하면 기부자의 성별 분포를 알 수 있다:
> table(don$Gender)
F M
615 615
남녀 모두 615명씩으로 동일하다.
FY04Giving(회계년도 2004년도 기부금액)이 $1000을 초과하는 졸업생을 추출해 보자. 이를 위해서는 마찬가지로 list 형식을 numeric 형식으로 변환한다. 앞서 Gender는 character 형식인데 반해 FY04Giving은 숫자이므로 numeric으로 변환함을 상기하기 바란다.
> don$FY04Giving = as.numeric(don$FY04Giving)
이제 FY04Giving이 $1000을 초과하는 졸업생 데이터를 추출해 보자:
> tmp = don[don$FY04Giving > 1000 , ] > tmp[1:10,] _id Gender ClassYear MaritalStatus Major NextDegree FY04Giving val -83207680 M 1957 M History LLB 2500.00 val.1 0 M 1957 M Physics MS 5000.00 val.2 -83201656 F 1957 M Music NONE 5000.00 val.3 -83200264 M 1957 M Biology PHD 1500.00 val.4 0 F 1957 M English MLS 1500.00 val.5 -83179992 F 1957 W Sociology ME 1500.00 val.6 -41872472 M 1957 M History NONE 1500.00 val.7 1 F 1957 M Chemistry-Zoology MS 2000.00 val.8 -1 M 1957 M History PHD 11505.84 val.9 -83207680 F 1957 M Physical Education ME 1500.00 FY03Giving FY02Giving FY01Giving FY00Giving val 2500 1400 12060 12000 val.1 5000 5000 5000 10000 val.2 5000 5000 5000 10000 val.3 1500 1500 1500 1000 val.4 1500 1500 1500 1000 val.5 1500 1000 500 500 val.6 1500 250 455 200 val.7 10000 1000 1200 1000 val.8 10000 10000 0 20000 val.9 1500 1000 2000 1000
이번 글에서는 R와 MongoDB를 연동하는 방법에 대해 알아보았으며, 실무에서 R을 사용하다 보면 DB와의 연동이 필수적이기 때문에 유의깊게 살펴볼 가치가 있는 내용이라 생각한다.
'Data Science > MongoDB' 카테고리의 다른 글
[MongoDB] Ubuntu에 MongoDB 설치하기 (0) | 2015.06.22 |
---|---|
[MongoDB] Tips / DB 및 Collection 삭제 명령어 (0) | 2015.04.19 |
[MongoDB] Sharding / Sharding Administration (0) | 2014.04.25 |
[MongoDB] Sharding / Product Configuration (0) | 2014.04.23 |
[MongoDB] Sharding / Setting Up Sharding (1) | 2014.04.22 |