목적은 AWS EC2 를 통해서 베포하고 있는 내 웹사이트에서 DB에 저장된 데이터를 이용해서 통계를 돌리는 겁니다.
그리고 그 통계를 웹페이지에 실제로 나타내는 것이 저의 계획이지요.
이를 위해서 먼저, 상단 메뉴의 웹사이트 > 아마존으로 웹사이트 배포하기 내부에 있는 포스팅을 참고하시길 바랍니다.
우선 R 설치를 위해서는 내 EC2 에 SSH 접속이 필요합니다.
sudo dnf install -y R
저의 EC2 는 Amazon Linux 3 버전입니다.
무료 버전 micro를 이용하고 있다면, 저와 동일할 겁니다.
위 명령어를 입력해서 R 을 EC2에 다운로드 합시다.
약간 시간이 걸리는데 기다려주세요.
Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.
>
zlib-devel-1.2.11-33.amzn2023.0.5.x86_64
zziplib-0.13.72-1.amzn2023.0.3.x86_64
Complete!
기다리면 이런 식으로 다운로드에 성공했다는 메시지가 나타납니다.
이럼 다시 명령창에 명령어를 입력 가능합니다.
R
명령창에 R 이라는 명령어를 실행하면 이제 R을 실행할 수 있습니다.
실행하게 되면 SSH 명령어의 앞에 있던 [ec2-user-@ip … ] 이 사라지고 > 이라는 기호가 나타날 겁니다.
여기에 script를 작성하면 되는 건데요.
SSH 접속해서 R을 사용할 계획은 없으니 다시 나가줍시다.
> q()
Save workspace image? [y/n/c]: n
위처럼 q() 라는 명령어를 실행합시다.
그리고 n 을 누르면 저장 안 하고 나갈 수 있습니다.
y는 저장하고 나가기, c 는 취소입니다.
R
이 R을 사용하기 위해서는 필요한 라이브러리를 설치할 필요가 있습니다.
우선은 2개의 변수와, 그 변수에 해당하는 데이터를 이용한 T-test 를 실행하는 것을 목적으로 해보겠습니다.
이를 위해 다시 R을 실행하겠습니다.
install.packages("dplyr")
install.packages("jsonlite")
install.packages("knitr")
그리고 위와 같이 R에서 기존에 사용하던 명령어 그대로 패키지를 설치 가능합니다.
이때 “Would you like to use a personal library instead?” 라는 질문이 나오는데 yes 눌러줍시다.
이럼 EC2 인스턴스의 home 에 디렉토리가 생성이 됩니다.
그리고 selection 단계가 있는데 Korea 는 49입니다.
library(dplyr)
# 가상의 데이터 생성
group1 <- rnorm(100, mean = 50, sd = 10)
group2 <- rnorm(100, mean = 55, sd = 10)
# T-test 수행
test_result <- t.test(group1, group2)
# 결과 출력
print(test_result)
설치가 완료 되었다면 다음의 코드를 이용해서 잘 되나 한 번 볼까요?
이런 식으로 t-test 결과가 나타난다면 성공입니다.
제대로 R이 EC2에 설치가 되었으며 이것을 이용해서 통계 결과를 낼 수 있게 된 겁니다.
다만, 현재는 SSH 접속을 하고 해당 Putty 창에서 가능한 거라 처음 계획했던 것과는 거리가 있습니다.
이제 프론트엔드 및 백엔드에서 어찌 이용하면 좋을지 살펴보겠습니다.
우선은 프론트엔드를 한 번 세팅해봅시다.
저는 사용자가 특정한 변수와 그 변수에 해당하는 데이터를 백엔드에 전달하면 그 데이터를 가지고 특정한 통계가 진행될 수 있도록 하고 싶습니다.
이를 위해서 다음과 같이 페이지를 구성했습니다.
import React, { useState } from "react";
const Script = () => {
const data = {
a: [1, 2, 3, 4, 5, 6, 7, 8, 9],
b: [9, 8, 7, 6, 5, 4, 3, 2, 1],
c: [5, 5, 5, 5, 5, 5, 5, 5, 5],
};
const [selectedKeys, setSelectedKeys] = useState({
key1: "a",
key2: "b",
});
const handleSelectChange = (e) => {
const { name, value } = e.target;
setSelectedKeys({ ...selectedKeys, [name]: value });
};
const DoTtest = async () => {
if (selectedKeys.key1 === selectedKeys.key2) {
alert("다른 두 개의 키를 선택해주세요.");
return;
}
try {
const payload = {
data1: data[selectedKeys.key1],
data2: data[selectedKeys.key2],
};
const response = await fetch("your api", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
if (response.ok) {
const result = await response.json();
console.log(result);
} else {
alert("Something went wrong!");
}
} catch (error) {
alert(error);
}
};
return (
);
};
export default Script;
정말 대충 설정한 데이터가 Object 형태로 data 라는 변수에 지정되어 있습니다.
key 값으로는 총 3개를 설정해뒀죠? 이 key 값에 할당된 각각의 value를 2개 짝지어서 t-test 를 수행할 겁니다.
지금 이것을 위해서 생성한 로직이 DoTtest 라는 로직입니다.
이 로직은 특정 라우터와 함께 동작하며, 그 라우터에서 전송한 결과를 콘솔창에 나타내죠.
이를 위한 백엔드 라우터도 제작하겠습니다.
const { exec } = require("child_process");
app.post("/your api", (req, res) => {
const { data1, data2 } = req.body;
// R 스크립트 파일 경로
const scriptPath = "/r/ttest_script.R";
// R 스크립트 실행 명령어
const command = `Rscript ${scriptPath} ${data1.join(",")} ${data2.join(",")}`;
exec(command, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return res.status(500).send("R 스크립트 실행 중 에러가 발생했습니다.");
}
// R 스크립트 실행 결과를 파싱하여 JSON으로 변환
try {
const result = JSON.parse(stdout);
res.json(result);
} catch (parseError) {
console.error(`결과 파싱 에러: ${parseError}`);
res.status(500).send("결과 파싱 중 에러가 발생했습니다.");
}
});
});
이 백엔드는 특정한 경로에 저장한 R script 파일을 사용하여 t-test 를 수행하고 그 결과를 전송할 겁니다.
경로의 경우 Filezilla 를 통해 EC2 인스턴스에 접속해서 디렉토리를 생성해서 그곳에 파일을 업로드 하면 됩니다.
home/ec2-user/… /script.R 과 같은 식으로 경로를 지정할 수 있겠네요.
이를 위해서 작성한 R 스크립트의 내용은 아래와 같습니다.
args <- commandArgs(trailingOnly = TRUE)
data1 <- as.numeric(unlist(strsplit(args[1], ",")))
data2 <- as.numeric(unlist(strsplit(args[2], ",")))
result <- t.test(data1, data2)
# 결과를 JSON 형태로 출력
cat(jsonlite::toJSON(list(
p.value = result$p.value,
estimate = result$estimate,
conf.int = result$conf.int,
statistic = result$statistic,
parameter = result$parameter,
null.value = result$null.value,
alternative = result$alternative,
method = result$method,
data.name = result$data.name
)))
위 코드들이 서로 상호작용 하며 작동하도록 했을 때는 이런 결과가 나타나게 됩니다.
실제 console 창에 각종 Object 형태로 여러 값이 전달되고 있음을 파악 가능합니다.