글쓴이 보관물: 홈피지기

R에서 `csv`형식 파일을 압축하기

사용하고 있는 csv형식 파일들을 갯수도 많고 용량도 크다면, 이것들을 보관하거나 전달하기 위해서는 압축하는 것이 편리하다. archive라는 패키지를 이용해서 여러개의 csv형식 파일들을 한 파일로 압축해보자. 이 패키지에 대한 세부적인 내용은 아래 링크를 참고하자.

우선 해당 패키지를 설치해보자.

install.packages("archive")

아래 명령어로 현재 압축하고자 하는 csv형식 파일이 있는지 살펴보자. 참고로 “data.zip”라는 파일명으로 압축하니, 이 폴더에 이 파일이 없어야 한다. 만약 있으면 에러가 날 확률이 많다.

dir()

이제 압축하고자 하는 csv형식 파일을 한 파일로 압축해보자. 확장자가 소문자로 .csv인 것만 선택하고 있다. 참고하자. 그러면 압축을 해보자.

library(archive)
save_files <- list.files(pattern="*.csv")
archive_write_files("data.zip", save_files)

만약 파일 1개를 압축한다고 한다면, 다음과 같이 하면 된다. “aaa.csv”은 자신이 압축하고자 하는 파일명을 넣으면 된다.

library(archive)
save_files <- list.files(pattern="*.csv")
archive_write_files("data.zip", "aaa.csv")

윗 코드를 실행하면 압축 진행 과정이 보일 것이다. 다 끝났다면, 아래 코드로 압축된 파일을 확인할 수 있다.

archive("data.zip")

이 글을 쓰기 위해서 테스트한 csv형식 파일들의 용량이 총 4.37GB이었는데 압축한 ‘data.zip’ 파일은 707.6MB이었다. 거의 1/6로 줄었다.

러스트(Rust)에서 한글 문자열 글자수 세기

러스트(Rust)에서 한글 문자열을 세기 위해서 단순하게 아래와 같이 len()을 사용하면 제대로 세지를 못한다. chars().count()을 이용해서 정확하게 셀 수 있다. 아래 코드를 실행하면, 정확하게 알 수 있다.

fn main() {
let temp = "안녕하세요!";
println!("temp.chars().count()로 센 글자수:{}", temp.chars().count());
println!("temp.len() 센 글자수:{}", temp.len());
}

Mac용 R 성능을 올려 보기

맥 OS에서 R 성능을 올리는 글이 봤었는데, 여기에서 알려지지 않을 것 같아서 정보 공유 차원에서 올려봅니다. 자세한 내용은 아래 링크 두 개를 참고하세요!

대락적인 내용은 애플에서 제공하는 Apple’s BLAS를 사용하면 R 속도가 메트릭스 연산 속도가 거의 1/10로 줄어 듭니다. 그런데 아쉽게도 현재 macOS에서는 사용할 수 없게 되었고 macOS 10.13 하이 시에라까지만 사용할 수 있습니다. 이 내용이 두 번째 링크 내용입니다.

그런데 첫 번째 링크를 보면, 저자는 M1 Mac mini에서 OpenBLAS 0.3.18 소스 코드를 다운받아서 직접 컴파일해 사용하면 위와 같은 효과를 볼 수 있다고 합니다. 이 글에서는 새로운 Apple Silicon arm64용 R과 비교하기 때문에 인텔 맥과 직접적인 비교를 할 수 없지만, 인텔 맥에서도 같은 방법으로 사용할 수 있을 것 같습니다.

(https://mpopov.com/blog/2021/10/10/even-faster-matrix-math-in-r-on-macos-with-m1/)[https://mpopov.com/blog/2021/10/10/even-faster-matrix-math-in-r-on-macos-with-m1/]

(https://mpopov.com/blog/2019/06/04/faster-matrix-math-in-r-on-macos/)[https://mpopov.com/blog/2019/06/04/faster-matrix-math-in-r-on-macos/]

러스트에서 `String`을 이용할 때, 생기는 유니코드 문제점

러스트에서 문자열을 다루는 방법은 String을 이용하는 것입니다. 그런데 이것을 이용하더라도 유니코드를 사용하는 경우 인텍싱이 다른 언어와 같이 명확하게 처리되지 않습니다. 다음 코드를 살펴봅시다.

fn main() {
let s1 = String::from("hello world!");
let hello = &s1[0..5];
let world = &s1[6..11];
println!("{}, {}", hello, world);

let s1 = String::from("안녕 세계!");
let hello = &s1[0..6];
let world = &s1[7..13];
println!("{}, {}", hello, world);

let s1 = String::from("こんにちは世界!");
let hello = &s1[0..15];
let world = &s1[15..21];

println!("{}, {}", hello, world);
}

윗 코드를 실행하면 다음과 같은 결과 나옵니다. 앞에서 인텍싱하는 코드를 살펴보면 글자 수와 인덱싱 숫자가 맞지 않는 것을 알 수 있습니다.

❯ cargo run
Compiling ownership v0.1.0 (/Users/jaehwan/git/rust/projects/ownership)
Finished dev [unoptimized + debuginfo] target(s) in 0.39s
Running `target/debug/ownership`
hello, world
안녕, 세계
こんにちは, 世界

참고하세요!

맥에서 보안 때문에 사용할 수 없는 크롬드라이버 사용하는 법

맥에서 크롤링을 하기 위해서 chromedriver를 사용하는 경우가 많습니다. 홈브루를 이용하시면, 터미널에서 brew install chromedriver을 입력하시면 사용할 수 있습니다. 그런데 맥 최신 오에스에서는 이렇게 설치한 chromedriver을 보안을 이유로 막는 경우가 있습니다. 좀 찾아봤는데 아주 쉽게 해결할 수 있습니다. 위와 같이 chromedriver를 설치하셨다면 터미널에서 xattr -d com.apple.quarantine $(which chromedriver)이라고 입력하시면 바로 문제 없이 사용하실 수 있습니다. 아래 글을 참고하세요!

java – MacOS Catalina(v 10.15.3): Error: “chromedriver” cannot be opened because the developer cannot be verified. Unable to launch the chrome browser – Stack Overflow

맥에서 sshpass 설치하기

homebrew로 sshpass이 설치되지 않는다!
아래 링크를 보면, 초보자들이 가볍게 설치하지 못 하도록 하려고 설치를 막았다고 하는 것 같다. 그래서 아래 링크에 있는 소스를 이용하는 방법으로 설치해보자! 설치한 후 다운받은 폴더와 파일을 삭제하면 된다.

cd ~
curl -O -L https://fossies.org/linux/privat/sshpass-1.09.tar.gz && tar xvzf sshpass-1.09.tar.gz
cd sshpass-1.09
./configure
sudo make install
sshpass

macos – How to install sshpass on mac? – Stack Overflow

R으로 Docker로 구성한 MariaDB 사용하기

이 글은 R로 MariaDB(이하 마리아디비)에 접근하기 위한 글입니다. 컴퓨터에 직접 마리아디비를 설치하고 이용하는 것이 아니라, 도커에 설치한 마리아디비를 이용하고자 합니다. 직접 설치하신 마리아디비를 사용하고자 하실 분들이나 외부 다른 컴퓨터에 설치된 것을 사용하고자 하실 분들도 아래 연결 설정값을 적절하게 입력하신다면, 그 글을 따라가시는데 문제가 없을 것 같습니다.

본격적으로 시작하기에 앞서

참고로 여기에서는 이미 Docker로 마리아디비를 설치했다고 가정할 것입니다. 설치하는 방법은 다음 링크를 참고하세요. Docker를 사용해서 MariaDB을 설치하기 그리고 이미 다음과 같은 sql명령을 사용하여 gregs_list이라는 DATABASE를 만들고, 그 안에 my_contacts라는 테이블을 만들고 두 사람의 자료를 입력했습니다.

CREATE DATABASE gregs_list;

CREATE TABLE my_contacts(
last_name VARCHAR(30),
first_name VARCHAR(20),
email VARCHAR(50),
birthday Date,
profession VARCHAR(50),
location VARCHAR(50),
status VARCHAR(20),
interests VARCHAR(100),
seeking VARCHAR(100)
);

INSERT INTO my_contacts(
last_name, first_name, email, gender, birthday, profession, location, status, interests, seeking
)
VALUES (
'Anderson', 'Jillian', 'jill_anderson@breakneckpizza.com', 'F', '1980-09-05', 'Technical Writer', 'Palo Alto, CA', 'Single', 'Kayaking, Reptiles', 'Relationship, Friends'
);

INSERT INTO my_contacts(
first_name, email,  profession, location
)
VALUES (
'Pat', 'patpost@breakneckpizza.com', 'Postal Worker', 'Princeton, NJ'
);

위에서 작업한 결과로 gregs_list 데이터베이스의 my_contacts라는 테이블에는 다음과 같이 두 사람의 자료가 들어있습니다.

MariaDB [gregs_list]> SELECT * FROM my_contacts;
+-----------+------------+----------------------------------+--------+------------+------------------+---------------+--------+--------------------+-----------------------+
| last_name | first_name | email                            | gender | birthday   | profession       | location      | status | interests          | seeking               |
+-----------+------------+----------------------------------+--------+------------+------------------+---------------+--------+--------------------+-----------------------+
| Anderson  | Jillian    | jill_anderson@breakneckpizza.com | F      | 1980-09-05 | Technical Writer | Palo Alto, CA | Single | Kayaking, Reptiles | Relationship, Friends |
| NULL      | Pat        | patpost@breakneckpizza.com       | NULL   | NULL       | Postal Worker    | Princeton, NJ | NULL   | NULL               | NULL                  |
+-----------+------------+----------------------------------+--------+------------+------------------+---------------+--------+--------------------+-----------------------+
2 rows in set (0.004 sec)

RMariaDB 설치하기

R 에서 MariaDB에 접근하기 위해서는 odbc 패키지나 RMariaDB를 사용해야 합니다. 이에 관련된 내용은 R Statistical Programming Using MariaDB as the Background Database – MariaDB Knowledge Base을 참고하시면 됩니다. 여기서는 RMariaDB를 사용하도록 하겠습니다. 앞 링크에서 RMariaDB을 다음과 같이 소개하고 있습니다.

“RMariaDB” R library, is a modern ‘MariaDB’ client based on ‘Rcpp’.

사용하기 위에서는 당연히 패키지를 설치해야 합니다.

install.packages("RMariaDB")

설치를 했으면 사용하시는 방법은 다음과 같습니다. 앞에서 말한 도커에 설치된 마리아디비의 정보를 그대로 입력했습니다. 여기서는 직접 입력하고 있지만, 실전에서 사용하시려면 Database Interface and MariaDB Driver • RMariaDB에서처럼 별도 파일에 입력하여 사용하시는 것이 좋을 것 습니다. 마지막 줄에서 dbListTables(con)을 통해서 gregs_list이라는 데이터베이스가 가지고 있는 테이블을 보여주게 됩니다.

library(RMariaDB)

con <- dbConnect(
  drv = RMariaDB::MariaDB(),
  username = "root",
  password = "RT27hDosK",
  host = "0.0.0.0",
  port = 3306,
  dbname = "gregs_list"
)

dbListTables(con)

앞의 코드가 실행된 결과는 다음과 같습니다. 현재 앞에서 입력한 my_contacts 테이블도 볼 수 있습니다.

> library(RMariaDB)
> con <- dbConnect(
+   drv = RMariaDB::MariaDB(),
+   username = "root",
+   password = "RT27hDosK",
+   host = "0.0.0.0",
+   port = 3306,
+   dbname = "gregs_list"
+ )
>
> con
<mariadbconnection>
Host:    0.0.0.0
Server:
Client:
> dbListTables(con)
[1] "movie_table"   "easy_drinks"   "my_contacts"   "doughnut_list" "users"         "clown_info"

R로 데이터베이스에 입력한 테이블을 살펴보기

이제 본격적으로 앞에서 데이터베이스에 저장한 테이블을 살펴보겠습니다. dbReadTable()을 사용하면 쉽게 테이블 내용을 확인하실 수 있습니다.

dbReadTable(con, "my_contacts")

윗 코드를 실행하면 다음과 같습니다.

> dbReadTable(con, "my_contacts")
contact_id phone last_name first_name                            email gender   birthday       profession      location status          interests               seeking
1          1  <na>  Anderson    Jillian jill_anderson@breakneckpizza.com      F 1980-09-05 Technical Writer Palo Alto, CA Single Kayaking, Reptiles Relationship, Friends
2          2  <na>      <na>        Pat       patpost@breakneckpizza.com   <na>       <na>    Postal Worker Princeton, NJ   <na>               <na>                  <na>

SQL을 사용하려면 다음과 같이 하시면 됩니다.

res <- dbSendQuery(con, "SELECT * FROM my_contacts")

위의 코드를 실행하면 다음과 같습니다. dbClearResult()을 이용해서 사용하신 다음에 정리하고 마무리하지 않으시면 에러가 날 수 있습니다. 주의하세요!

> res <- dbSendQuery(con, "SELECT * FROM my_contacts")
> res
<mariadbresult>
SQL  SELECT * FROM my_contacts
ROWS Fetched: 0 [incomplete]
Changed: 0
> dbFetch(res)
contact_id phone last_name first_name                            email gender   birthday       profession      location status          interests               seeking
1          1  <na>  Anderson    Jillian jill_anderson@breakneckpizza.com      F 1980-09-05 Technical Writer Palo Alto, CA Single Kayaking, Reptiles Relationship, Friends
2          2  <na>      <na>        Pat       patpost@breakneckpizza.com   <na>       <na>    Postal Worker Princeton, NJ   <na>               <na>                  <na>
> dbClearResult(res)

조금 더 세련되게 할 수도 있습니다.

res <- dbSendQuery(con, "SELECT * FROM my_contacts")
while(!dbHasCompleted(res)){
  chunk <- dbFetch(res, n = 5)
  print(chunk)
  print(nrow(chunk))
}

윗 코드를 실행하면 다음과 같습니다.

> dbClearResult(res)
> res <- dbSendQuery(con, "SELECT * FROM my_contacts")
> while(!dbHasCompleted(res)){
+   chunk <- dbFetch(res, n = 5)
+   print(chunk)
+   print(nrow(chunk))
+ }
  contact_id phone last_name first_name                            email gender   birthday       profession      location status          interests               seeking
1          1  <na>  Anderson    Jillian jill_anderson@breakneckpizza.com      F 1980-09-05 Technical Writer Palo Alto, CA Single Kayaking, Reptiles Relationship, Friends
2          2  <na>      <na>        Pat       patpost@breakneckpizza.com   <na>       <na>    Postal Worker Princeton, NJ   <na>               <na>                  <na>
[1] 2

tidyverse를 추가해서 사용하면 좀 더 쉽고 멋있게 처리할 수 있습니다. 다음 코드에서 볼 수 있는 것처럼 SQL를 사용하지 않고 filter()와 같은 것을 이용하여 쉽게 테이블에 있는 자료를 처리할 수 있습니다. 마지막 줄에서 filter()를 사용하여 first_name 열에 있는 “Pat”이라는 단어가 있는 줄을 뽑아서 보여줍니다.

library(tidyverse)
library(RMariaDB)
library(dplyr, warn.conflicts = FALSE)
con <- dbConnect(
  drv = RMariaDB::MariaDB(),
  username = "root",
  password = "RT27hDosK",
  host = "0.0.0.0",
  port = 3306,
  dbname = "gregs_list"
)
my_contacts <- tbl(con, "my_contacts")
my_contacts
my_contacts %>% filter(first_name == "Pat")

윗 코드를 실행하면 다음과 같습니다.

> library(tidyverse)
─ Attaching packages ─────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ─
✔ ggplot2 3.3.0     ✔ purrr   0.3.4
✔ tibble  3.0.1     ✔ dplyr   1.0.0
✔ tidyr   1.1.0     ✔ stringr 1.4.0
✔ readr   1.3.1     ✔ forcats 0.5.0
─ Conflicts ──────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ─
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
> library(RMariaDB)
> library(dplyr, warn.conflicts = FALSE)
> con <- dbConnect(
+   drv = RMariaDB::MariaDB(),
+   username = "root",
+   password = "RT27hDosK",
+   host = "0.0.0.0",
+   port = 3306,
+   dbname = "gregs_list"
+ )
> my_contacts <- tbl(con, "my_contacts")
> my_contacts
# Source:   table<my_contacts> [?? x 12]
# Database: mysql [root@0.0.0.0:NA/gregs_list]
contact_id phone last_name first_name email                            gender birthday   profession       location      status interests          seeking
<int> <chr> <chr>     <chr>      <chr>                            <chr>  <date>     <chr>            <chr>         <chr>  <chr>              <chr>
1          1 <na>  Anderson  Jillian    jill_anderson@breakneckpizza.com F      1980-09-05 Technical Writer Palo Alto, CA Single Kayaking, Reptiles Relationship, Friends
2          2 <na>  <na>      Pat        patpost@breakneckpizza.com       <na>   NA         Postal Worker    Princeton, NJ <na>   <na>               <na>
> my_contacts %>% filter(first_name == "Pat")
# Source:   lazy query [?? x 12]
# Database: mysql [root@0.0.0.0:NA/gregs_list]
contact_id phone last_name first_name email                      gender birthday   profession    location      status interests seeking
<int> <chr> <chr>     <chr>      <chr>                      <chr>  <date>     <chr>         <chr>         <chr>  <chr>     <chr>
1          2 <na>  <na>      Pat        patpost@breakneckpizza.com <na>   NA         Postal Worker Princeton, NJ <na>   <na>      <na>

참고 자료

파이썬으로 Docker로 구성한 MariaDB 사용하기

도커를 이용하여 MariaDB(이하 마리아디비)를 설치해봤습니다. 이렇게 설치한 마리아디비에 파이썬으로 이용하여 자료를 저장하고 저장한 값을 확인하고 지워보겠습니다. 우선 파이썬으로 마리아디비와 같은 실제 DB(이하 데이터베이스)에 접근하기 위해서는 해당 데이터베이스에 맞는 드라이버(또는 클라이언트 라이브러리(client library)라고 하기도 합니다)를 설치해줘야 합니다. 이 글에서는 PyMySQL을 사용하겠습니다. 설치 방법은 Installation을 참고하세요. 현재 사용하고 있는 PyMySQL의 버전은 0.10.1입니다.

본격적으로 시작하기에 앞서

참고로 여기에서는 이미 Docker로 MariaDB를 설치했다고 가정할 것입니다. 설치하는 방법은 다음 링크를 참고하세요. Docker를 사용해서 MariaDB을 설치하기 그리고 이미 다음과 같은 sql명령을 사용하여 gregs_list이라는 DATABASE를 만들고, 그 안에 my_contacts라는 테이블을 만들고 두 사람의 자료를 입력했습니다.그리고 사용하기 쉽게 하기 위해서 sqlalchemy을 사용합니다. 이것의 설치 방법은 How to Install SQLAlchemy on Windows, Mac and Linux | Python Central을 참고하세요!

CREATE DATABASE gregs_list;

CREATE TABLE my_contacts(
last_name VARCHAR(30),
first_name VARCHAR(20),
email VARCHAR(50),
birthday Date,
profession VARCHAR(50),
location VARCHAR(50),
status VARCHAR(20),
interests VARCHAR(100),
seeking VARCHAR(100)
);

INSERT INTO my_contacts(
last_name, first_name, email, gender, birthday, profession, location, status, interests, seeking
)
VALUES (
'Anderson', 'Jillian', 'jill_anderson@breakneckpizza.com', 'F', '1980-09-05', 'Technical Writer', 'Palo Alto, CA', 'Single', 'Kayaking, Reptiles', 'Relationship, Friends'
);

INSERT INTO my_contacts(
first_name, email,  profession, location
)
VALUES (
'Pat', 'patpost@breakneckpizza.com', 'Postal Worker', 'Princeton, NJ'
);

위에서 작업한 결과로 gregs_list 데이터베이스의 my_contacts라는 테이블에는 다음과 같이 두 사람의 자료가 들어있습니다.

MariaDB [gregs_list]> SELECT * FROM my_contacts;
+-----------+------------+----------------------------------+--------+------------+------------------+---------------+--------+--------------------+-----------------------+
| last_name | first_name | email                            | gender | birthday   | profession       | location      | status | interests          | seeking               |
+-----------+------------+----------------------------------+--------+------------+------------------+---------------+--------+--------------------+-----------------------+
| Anderson  | Jillian    | jill_anderson@breakneckpizza.com | F      | 1980-09-05 | Technical Writer | Palo Alto, CA | Single | Kayaking, Reptiles | Relationship, Friends |
| NULL      | Pat        | patpost@breakneckpizza.com       | NULL   | NULL       | Postal Worker    | Princeton, NJ | NULL   | NULL               | NULL                  |
+-----------+------------+----------------------------------+--------+------------+------------------+---------------+--------+--------------------+-----------------------+
2 rows in set (0.004 sec)

데이터베이스에 입력된 것을 가져오기

그러면 파이썬으로 이것에 연결해보겠습니다. 도커에 설치된 마리아디비의 정보를 파이썬에 입력하기 위해서 정보가 들어 있는 dict를 하나 만들었습니다.

db = {
'user'     : 'root',
'password' : 'RT27hDosK',
'host'     : '0.0.0.0',
'port'     : '3306',
'database' : 'gregs_list'
}

위에 입력한 자료를 가지고 DB_URL이라는 문자열을 만들어서 이를 가지고 데이터 베이스에 접근하기 위해 sqlalchemy으로 create_engine을 만들고, my_contacts 테이블에 접근하기 위해 execute을 가지고 sql을 직접 실행합니다. 그렇게 받아온 자료를 print를 이용해 확인합니다.

import sqlalchemy as sa
DB_URL = f"mysql+pymysql://{db['user']}:{db['password']}@{db['host']}:{db['port']}/{db['database']}?charset=utf8"
conn = sa.create_engine(DB_URL, encoding = 'utf-8')

rows = conn.execute('SELECT * FROM my_contacts')

for row in rows:
print(row)

지금까지 한 것을 실행하면 다음과 같습니다. 맥에서 실행한 것이니 조금씩 다를 수는 있겠지만, 거의 다 같게 작동할 것입니다. 만약 자료를 보기 위해서 print(rows)라고 하신다면 <sqlalchemy.engine.result.resultproxy object="" at="" 0x102e33940="">이라고 나올 것입니다. 왜냐하면 sqlalchemy의 ResultProxy 객체는 출력해서 볼 수 없기 때문입니다.</sqlalchemy.engine.result.resultproxy>

❯ python3
Python 3.8.6 (default, Oct 16 2020, 14:50:59)
[Clang 11.0.3 (clang-1103.0.32.62)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sqlalchemy as sa
>>> db = {
...     'user'     : 'root',
...     'password' : 'RT27hDosK',
...     'host'     : '0.0.0.0',
...     'port'     : '3306',
...     'database' : 'gregs_list'
... }
>>> DB_URL = f"mysql+pymysql://{db['user']}:{db['password']}@{db['host']}:{db['port']}/{db['database']}?charset=utf8"
>>> conn = sa.create_engine(DB_URL, encoding = 'utf-8')
>>> rows = conn.execute('SELECT * FROM my_contacts')
>>> for row in rows:
...     print(row)
...
('Anderson', 'Jillian', 'jill_anderson@breakneckpizza.com', 'F', datetime.date(1980, 9, 5), 'Technical Writer', 'Palo Alto, CA', 'Single', 'Kayaking, Reptiles', 'Relationship, Friends')
(None, 'Pat', 'patpost@breakneckpizza.com', None, None, 'Postal Worker', 'Princeton, NJ', None, None, None)

위의 방법을 보시면 아시겠지만, 기본적으로 SQL을 이용하는 것과 별 차이가 없습니다. 또한 PostgreSQL와 같은 다른 종류의 데이터베이스를 사용하면, 사용할 수 있는 SQL가 다르기 때문에 각각 DB에 맞춰 코드를 짜야 합니다. 이처럼 같은 기능을 하지만, 각각의 데이터베이스에서는 상이한 표현으로 되어 있는 것들을 같은 함수로 처리할 수 있는 기능이 SQLAlchemy에 들어 있습니다. 이 기능이 바로 ‘SQL Expression Language’입니다. 이것을 이용하여 위의 것과 동일한 일을 하는 코드를 작성하면 아래와 같습니다.

db = {
'user'     : 'root',
'password' : 'RT27hDosK',
'host'     : '0.0.0.0',
'port'     : '3306',
'database' : 'gregs_list'
}
import sqlalchemy as sa

DB_URL = f"mysql+pymysql://{db['user']}:{db['password']}@{db['host']}:{db['port']}/{db['database']}?charset=utf8"

conn = sa.create_engine(DB_URL, encoding = 'utf-8')

meta = sa.MetaData()

my_contacts = sa.Table('my_contacts', meta,
sa.Column('last_name', sa.String),
sa.Column('first_name', sa.String),
sa.Column('email', sa.String),
sa.Column('birthday', sa.Date),
sa.Column('profession', sa.String),
sa.Column('location', sa.String),
sa.Column('status', sa.String),
sa.Column('interests', sa.String),
sa.Column('seeking', sa.String))

meta.create_all(conn)

result = conn.execute(my_contacts.select())
rows = result.fetchall()
print(rows)

이 코드를 보시면 아시겠지만, SQL에서 벗어나, 순수 파이썬 코드처럼 보입니다. 윗 코드를 실행시키면 앞에 한 것과 동일한 결과가 나옵니다. 앞부분은 윗 코드와 동일하지만 데이블에 접근하는 방법은 많이 다릅니다.

Python 3.8.6 (default, Oct 16 2020, 14:50:59)
[Clang 11.0.3 (clang-1103.0.32.62)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sqlalchemy as sa
>>> db = {
...     'user'     : 'root',
...     'password' : 'RT27hDosK',
...     'host'     : '0.0.0.0',
...     'port'     : '3306',
...     'database' : 'gregs_list'
... }
>>> DB_URL = f"mysql+pymysql://{db['user']}:{db['password']}@{db['host']}:{db['port']}/{db['database']}?charset=utf8"
>>> conn = sa.create_engine(DB_URL, encoding = 'utf-8')
>>> meta = sa.MetaData()
>>> my_contacts = sa.Table('my_contacts', meta,
...     sa.Column('last_name', sa.String),
...     sa.Column('first_name', sa.String),
...     sa.Column('email', sa.String),
...     sa.Column('birthday', sa.Date),
...     sa.Column('profession', sa.String),
...     sa.Column('location', sa.String),
...     sa.Column('status', sa.String),
...     sa.Column('interests', sa.String),
...     sa.Column('seeking', sa.String))
>>> meta.create_all(conn)
>>> result = conn.execute(my_contacts.select())
>>> rows = result.fetchall()
>>> print(rows)
[('Anderson', 'Jillian', 'jill_anderson@breakneckpizza.com', datetime.date(1980, 9, 5), 'Technical Writer', 'Palo Alto, CA', 'Single', 'Kayaking, Reptiles', 'Relationship, Friends'), (None, 'Pat', 'patpost@breakneckpizza.com', None, 'Postal Worker', 'Princeton, NJ', None, None, None)]

이것을 이용해서 자료를 입력해보겠습니다. 참고로 생년월일을 입력하기 위해서 datetime가 필요합니다.

import datetime

conn.execute(my_contacts.insert(('Soukup', 'Alan', 'soupup@breakneckbizza.com', datetime.date(1975, 12, 2), 'Aeronautical Engineer', 'San Antonio, TX', 'Married', 'RPG, Programming', 'Nothing')))

윗 코드를 작동시켜보면 자료가 입력된 것을 확인할 수 있습니다.

>>> import datetime
>>> conn.execute(my_contacts.insert(('Soukup', 'Alan', 'soupup@breakneckbizza.com', datetime.date(1975, 12, 2), 'Aeronautical Engineer', 'San Antonio, TX', 'Married', 'RPG, Programming', 'Nothing')))
>>> result = conn.execute(my_contacts.select())
>>> rows = result.fetchall()
>>> print(rows)
[('Anderson', 'Jillian', 'jill_anderson@breakneckpizza.com', datetime.date(1980, 9, 5), 'Technical Writer', 'Palo Alto, CA', 'Single', 'Kayaking, Reptiles', 'Relationship, Friends'), (None, 'Pat', 'patpost@breakneckpizza.com', None, 'Postal Worker', 'Princeton, NJ', None, None, None), ('Soukup', 'Alan', 'soupup@breakneckbizza.com', datetime.date(1975, 12, 2), 'Aeronautical Engineer', 'San Antonio, TX', 'Married', 'RPG, Programming', 'Nothing')]

Docker를 사용해서 MariaDB을 설치하기

참고: 이 글은 JiHun님의 Docker를-사용해서-MariaDB-설치하기을 참고했습니다. 자세한 내용은 이 글을 참고하세요!

docker 에 mariadb container를 받고 실행합니다. MYSQL_ROOT_PASSWORD = RT27hDosK에 쓴 RT27hDosK은 DB 비번입니다. 적절하게 고쳐주세요. 연습용으로 쓰실 것이면, 그대로 사용해도 무방합니다.

docker pull mariadb
docker run --name mariadb -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=RT27hDosK mariadb

앞에서 실행한 container에 들어가서 bash를 실행합니다.


docker exec -it mariadb /bin/bash

container에 들어갔으니, mysql으로 들어가겠습니다. 피번은 앞에서 MYSQL_ROOT_PASSWORD = RT27hDosK이라고 했으니 RT27hDosK을 입력하시면 됩니다.

root@e144fdbab9be:/# mysql -u root -p
Enter password:

들어갔으니 DB상태를 살펴보겠습니다. latin1이 2개 있습니다. 이것때문에 한글이 깨질 수 있습니다. 변경해보겠습니다.

MariaDB [(none)]&gt; status
--------------
mysql  Ver 15.1 Distrib 10.5.5-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2

Connection id:      4
Current database:
Current user:       root@localhost
SSL:            Not in use
Current pager:      stdout
Using outfile:      ''
Using delimiter:    ;
Server:         MariaDB
Server version:     10.5.5-MariaDB-1:10.5.5+maria~focal mariadb.org binary distribution
Protocol version:   10
Connection:     Localhost via UNIX socket
Server characterset:    utf8mb4
Db     characterset:    utf8mb4
Client characterset:    latin1
Conn.  characterset:    latin1
UNIX socket:        /run/mysqld/mysqld.sock
Uptime:         2 min 1 sec

Threads: 2  Questions: 4  Slow queries: 0  Opens: 16  Open tables: 10  Queries per second avg: 0.033

앞에 설정을 바꾸기 위해서는 도커 컨테이너 안에 있는 파일을 고쳐야 합니다. 그런데 에디터가 없습니다. 에디터를 설치하고 파일을 열겠습니다.

root@e144fdbab9be:/# apt-get update
root@e144fdbab9be:/# apt-get install nano
root@e144fdbab9be:/# nano /etc/mysql/my.cnf

앞에서 연 /etc/mysql/my.cnf 파일에서 내용을 아래와 같이 추가/수정해 줍니다.

[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

[mysqld]
collation-server = utf8_unicode_ci
init-connect='SET NAMES utf8'
character-set-server = utf8

다 했으면 나갑니다.

root@e144fdbab9be:/# exit
exit

이제 변경한 내용을 적용하시려면 mariadb를 재시작해야 합니다. 우선 mariadb ID를 다음과 같이 찾습니다. 그런 다음 그 ID를 가지고 mariadb를 재실행합니다.

❯ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
e144fdbab9be        mariadb             "docker-entrypoint.s…"   20 minutes ago      Up 20 minutes       0.0.0.0:3306->3306/tcp   mariadb

❯ docker restart e144fdbab9be
e144fdbab9be

지금까지 한 것을 확인하러 컨데이너에 들어갑니다.

docker exec -it mariadb /bin/bash
mysql -u root -p
# MYSQL_ROOT_PASSWORD=RT27hDosK
Enter password:

잘 변경되었습니다.

MariaDB [(none)]&gt; status
--------------
mysql  Ver 15.1 Distrib 10.5.5-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2

Connection id:      3
Current database:
Current user:       root@localhost
SSL:            Not in use
Current pager:      stdout
Using outfile:      ''
Using delimiter:    ;
Server:         MariaDB
Server version:     10.5.5-MariaDB-1:10.5.5+maria~focal mariadb.org binary distribution
Protocol version:   10
Connection:     Localhost via UNIX socket
Server characterset:    utf8
Db     characterset:    utf8
Client characterset:    utf8mb4
Conn.  characterset:    utf8mb4
UNIX socket:        /run/mysqld/mysqld.sock
Uptime:         1 min 46 sec

Threads: 2  Questions: 4  Slow queries: 0  Opens: 16  Open tables: 10  Queries per second avg: 0.037

Array 에서 행을 잡는 방법

줄리아에서 아래와 같은 array를 가지고 for 문을 돌려 열을 선택하고 싶은 경우가 있다.

M = [1 2 3; 4 5 6; 7 8 9]
3×3 Array{Int64,2}:
1  2  3
4  5  6
7  8  9

그러나 아쉽게도 다음과 같이 셀을 하나씩 잡아서 준다.

for i in (M)
println(i)
end
1
4
7
2
5
8
3
6
9

이때 필요한 eachrow()함수이다. 이를 이용해서 for 문을 돌리면 아주 깔금하게 작동합니다.

for row in eachrow(M)
println(row)
end
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]