Backends Data Mining PHP R

PHP 소스코드에서 R 스크립트 실행하기

데이터와 통계분석에 활용되는 R을 웹 언어에서 실행한다면, 강력한 시너지 효과를 기대할 수 있을 것입니다. 그러나 많은 개발자들의 도전에도 불구하고 이것은 쉽지 만은 않은 과제였는데, 그 이유는 바로 R을 Input File 없이 커맨드라인에서 실행할 수 있는 방법이 녹록치 않았기 때문입니다.

이번 포스팅에서 소개하는 PHP 클래스는, 인자로 받은 R 스크립트를 임시파일로 만들어 쉘 커맨드로 R을 실행한 결과를 반환합니다. 이를 통해서 PHP에서 R 스크립트를 문자열로 만들어 그대로 실행할 수 있습니다. 본 클래스는 리눅스 OS에서 작동하는 것을 전제로 합니다.

 

클래스 R_script 소개

final class R_script
{
	private static $pathTmp		= '/tmp/';
	private static $pathRbin	= '/usr/bin/R';

	static function run($s)
	{
		// Setting File Names
		$sKey		= 'r-php-script-' . md5(time() . rand());
		$fInput		= self::$pathTmp . $sKey;
		
		// Write an Input File
		$fp = fopen($fInput, 'w+');
		fwrite($fp, $s);
		fclose($fp);
		
		// Run the R Binary
		$res = shell_exec(self::$pathRbin . ' --slave -q --no-save < ' . $fInput);
		
		// Delete Files
		unlink($fInput);
		
		// Return
		return $res;
	}
}

클래스를 구성하는 소스코드는 간결합니다. 먼저 임시파일의 이름을 설정하고, 인자 $s로 입력받은 R 스크립트를 임시파일에 작성합니다. 그 후에는 쉘 커맨드로 R을 실행하여 결과를 받은 후, 임시파일을 지우는 것으로 마무리됩니다.

R의 실행파일 경로는 /usr/bin/R로 지정되어 있으나, 서버환경에 따라서 경로가 다른 경우에는 $pathRbin 멤버변수를 수정하여 사용할 수 있습니다.

$s = '
	x <- c(14,26,68,47,33,95);
	y <- c(10,32,89,57,75,80);
	mean(x);
	mean(y);
	cor(x, y, method="pearson");
';

echo R_script::run($s);

// 출력결과
/*
[1] 47.16667
[1] 57.16667
[1] 0.7844031
*/

실제 클래스를 사용하는 예제는 위와 같습니다. 2개의 벡터를 각각 x와 y에 담고, 각 벡터의 평균과 함께 피어슨 상관계수를 구하는 코드입니다. 출력한 결과는 코드 가장 아래의 주석과 같습니다.

$s = "
	x <- c(14,26,68,47,33,95);
	y <- c(10,32,89,57,75,80);
	cat(mean(x));
	cat('\n')
	cat(mean(y));
	cat('\n')
	cat(cor(x, y, method='pearson'));
";

echo R_script::run($s);

// 출력결과
/*
47.16667
57.16667
0.7844031
*/

행 머리에 [1]이 붙어 이용하시기에 불편하시다면, R 스크립트 상에서 cat( ) 함수로 로직을 감싸면 결과만 출력할 수 있습니다. 다만 이 때는 개행문자가 별도로 붙지 않기 때문에, 여러 개의 결과를 출력할 때에는 개행문자 또한 따로 cat( ) 함수로 출력해야 할 것입니다. PHP 상에서 문자열 함수나 정규표현식을 활용하여 제거하는 방법도 있습니다만, 만약 각괄호 안의 숫자가 정상적인 출력 안에 포함된다면 예상하지 못한 문제가 발생할 수 있어 별도의 처리는 하지 않았습니다.

위 방법은 임시파일을 이용하고, 특히 쉘 커맨드를 직접 실행한다는 점에서 최선의 방법은 아닙니다. 만약 R 스크립트 문자열 중의 일부가 GET 또는 POST 파라미터로 이루어진다면, 보안위협에 그대로 노출될 수 있는 위험도 있습니다. 실행속도 또한 만족스러운 수준은 아닙니다. 그러나 매우 간편하게 PHP 소스코드 상에서 R의 다양한 연산을 활용할 수 있다는 점에서 실시간성이 필요하지 않은 통계분석 도구를 구현할 때 활용할만한 가치가 있을 것입니다.

 

활용예제 : 두 배열의 피어슨 상관계수를 구하는 함수

function pearsonCor($a, $b)
{
	// Check if It is an Array
	if(!is_array($a) || !is_array($b))
	{
		return false;
	}
	
	// Check Dimensions
	if(count($a) != count($b))
	{
		return false;
	}
	
	// Make All Elements to Float
	$a = array_map('floatval', $a);
	$b = array_map('floatval', $b);
	
	return floatval(R_script::run('
		a <- c(' . implode(',', $a) . ');
		b <- c(' . implode(',', $b) . ');
		cat(cor(a, b, method="pearson"))
	'));
}

$a = array(14, 26, 68, 47, 33, 95);
$b = array(10, 32, 89, 57, 75, 80);

echo pearsonCor($a, $b);

선형분석에서 자주 사용하는 계수라고 한다면, 피어슨 상관계수를 역시 빠뜨릴 수 없을 것입니다. 두 데이터 집합의 움직임이 얼마나 동질적인지를 밝힐 때 사용하는 계수인데, 금번 포스팅에서 소개한 클래스를 활용하여 피어슨 상관계수를 구하는 함수를 구현한다면 위와 같은 코드가 될 것입니다.

다만 PHP에서 피어슨 상관계수를 구하는 함수는 이미 PECLstats_stat_correlation( )라는 이름으로 존재하고, 작동속도도 이 함수가 월등히 빠르기 때문에 굳이 위 방법을 사용할 이유는 없습니다. 위 코드는 단지 이해하기 쉬운 활용예제로써 소개한 것입니다. 항상 그렇듯 문제를 해결할 때는 해당 언어의 기본스펙에서 먼저 답을 구하는 것이 순리라는 사실을 잊지 말아야 겠습니다.

4 thoughts on “PHP 소스코드에서 R 스크립트 실행하기”

Leave a Reply

Your email address will not be published. Required fields are marked *