7월, 2016의 게시물 표시

(R) unique 함수

>unique(AA[, c("XX","YY","ZZ")]) 예) mau<-unique(dau[,c("region_month","device","user_id")]) -->AA라는 데이터에서 항목 XX와 YY,ZZ가 중복되지 않도록 정리할 수 있다. XX만 다른 값이고 YY와 ZZ가 같은 값이라면 양쪽 대이터가 남지만 XX,YY,ZZ모두 같은 값이라면 중복처리되어 하나만 남게된다. >unique(AA[AA$XX=="xxx", c("X","Y","Z")]) 예) fp.mau<-unique(dau[dau$device=="FP",c("region_month","device","user_id")]) sp.mau<-unique(dau[dau$device=="SP",c("region_month","device","user_id")]) 위 코드는 AA라는 데이터에서 AA의 항목이 xxx인 것만 추출하고 X,Y,Z의 항목이 중복되지 않도록 데이터를 가공하는 것이다.

(R,데이터분석) 로지스틱 회귀 분석

이미지
가설: 피처폰에서 스마트폰으로 이용자수가 변화함에 따라 ID이전 실패로 인해 모바일 게임을 탈퇴한 유저가 많다. * 정답을 포함한 데이터 없이 모델 세우기 정답을 포함하지 않은 데이터에 대해 억지로 모델을 만들어서 제안한다는 건 학술적으로 완전히 용납되지 않습니다. 그러나 비즈니스에서는 매번 정답을 포함한 데이터를 손에 넣을 수 있다고 장담할 수 없습니다. 가설에서처럼 ID이전 실패로 인해 탈퇴한 유저수가 많은 경우를 생각해봅시다.  따라서 탈퇴자 전체에 대한 'ID 이전 실패로 인한 탈퇴'의 비율이 높을 때는 탈퇴 유저와 이전 유저간에 1월의 이용횟수가 크게 다르지 않을 것입니다. 1월의 이용횟수가 크게 다르지 않다는 건 이용횟수를 가지고는 모델을 만들 수 없다는 뜻입니다.  반대로 말하면 'ID 이전 실패로 인한 탈퇴'가 적다면 이용횟수의 차이가 분명히 드러날 것이기 때문에 모델을 만들 수 있다는 뜻이 됩니다. 따라서 모델이 만들어진다면 ID이전 실패로 인한 탈퇴자수가 그리 많지 않으므로 기존 ID이전 기능의 복잡함이 크게 문제되지 않는 다는 해석이 가능해집니다. *어떤 모델을 사용할 것인가? 이번 사례는 'ID 이전 유저'와 '탈퇴 유저'의 판별 모델을 구축할 필요가 있다. 판별 모델에는 여러가지가 있는데, 이번에는 가지고 있는 데이터에 정답이 포함되어 있지 않기 때문에 SVM(서포트 벡터 머신)이나 뉴럴 네트워크 등과 같이 정확도는 높지만 계산이 오래 걸리는 모델을 굳이 쓸 필요는 없습니다. 그래서 단순한 방법으로 재빨리 결과를 뽑기 좋은 '로지스틱 회귀 분석'을 사용합니다. 로지스틱 회귀분석이란? 예를들어, 목적변수가 '구매하기/구매하지 않기'와 같이 두 가지가 값을 가질 때 사용하는 회귀모델로서, 신속하게 데이터의 경향을 파악하기에 적합합니다. 로지스틱 회귀분석을 설명하기 위

(데이터분석) 로지스틱 회귀 분석

가설: 피처폰에서 스마트폰으로 이용자수가 변화함에 따라 ID이전 실패로 인해 모바일 게임을 탈퇴한 유저가 많다. * 정답을 포함한 데이터 없이 모델 세우기 정답을 포함하지 않은 데이터에 대해 억지로 모델을 만들어서 제안한다는 건 학술적으로 완전히 용납되지 않습니다. 그러나 비즈니스에서는 매번 정답을 포함한 데이터를 손에 넣을 수 있다고 장담할 수 없습니다. 가설에서처럼 ID이전 실패로 인해 탈퇴한 유저수가 많은 경우를 생각해봅시다.  따라서 탈퇴자 전체에 대한 'ID 이전 실패로 인한 탈퇴'의 비율이 높을 때는 탈퇴 유저와 이전 유저간에 1월의 이용횟수가 크게 다르지 않을 것입니다. 1월의 이용횟수가 크게 다르지 않다는 건 이용횟수를 가지고는 모델을 만들 수 없다는 뜻입니다.  반대로 말하면 'ID 이전 실패로 인한 탈퇴'가 적다면 이용횟수의 차이가 분명히 드러날 것이기 때문에 모델을 만들 수 있다는 뜻이 됩니다. 따라서 모델이 만들어진다면 ID이전 실패로 인한 탈퇴자수가 그리 많지 않으므로 기존 ID이전 기능의 복잡함이 크게 문제되지 않는 다는 해석이 가능해집니다. *어떤 모델을 사용할 것인가? 이번 사례는 'ID 이전 유저'와 '탈퇴 유저'의 판별 모델을 구축할 필요가 있다. 판별 모델에는 여러가지가 있는데, 이번에는 가지고 있는 데이터에 정답이 포함되어 있지 않기 때문에 SVM(서포트 벡터 머신)이나 뉴럴 네트워크 등과 같이 정확도는 높지만 계산이 오래 걸리는 모델을 굳이 쓸 필요는 없습니다. 그래서 단순한 방법으로 재빨리 결과를 뽑기 좋은 '로지스틱 회귀 분석'을 사용합니다. 로지스틱 회귀분석이란? 예를들어, 목적변수가 '구매하기/구매하지 않기'와 같이 두 가지가 값을 가질 때 사용하는 회귀모델로서, 신속하게 데이터의 경향을 파악하기에 적합합니다. 로지스틱 회귀분석을 설명하기 위

(R) 타입 판별

데이터를 처리하기 위해 여러 함수를 호출하다보면 반환된 결과의 타입이 무엇인지 분명하지 않을떄가 있다. 다음 함수들을 사용하여 데이터 타입을 손쉽게 판단할 수 있다. class(x) : 객체 x의 클래스 str(x) : 객체x의 내부구조 is.factor(x) : 주어진 객체 x가 팩터인가 is.numeric(x) : 주어진 객체 x가 숫자를 저장한 벡터인가 is.character(x) : 주어진 객체 x가 문자열을 저장한 벡터인가 is.matrix(x) : 주어진 객체 x가 행렬인가 is.array(x) : 주어진 객체 x가 배열인가 is.data.frame(x) : 주어진 객체 x가 데이터 프레임인가

(스프링) @ControllerAdvice를 이용한 공통 익셉션 처리

이미지
컨트롤러 클래스에 @ExceptionHandler 애노테이션을 적용하면 해당 컨트롤러에서 발생한 익셉션만을 처리한다. 그런데 다수 컨트롤러에서 동일 타입의 익셉션을 발생시킬 수 있고, 이 때 익셉션 처리 코드가 동일하다면 어떻게 해야 할까? 각 컨트롤러 클래스마다 익셉션 처리 메소드를 구현하는 것은 불필요한 코드 중복을 발생시킨다. 이럴경우, @ControllerAdvice애노테이션을 이용해서 익셉션 처리 메소드 중복을 없앨 수 있다. @ControllerAdvice애노테이션이 적용된 클래스는 지정한 범위의 컨트롤러에서 공통으로 사용될 설정을 지정할 수 있다. 위 코드의 경우 "chap13.spring"패키지 및 그 하위 패키지에 속한 컨트롤러 클래스를 위한 공통기능을 정의하였다. 이 패키지 및 하위 패키지에 속한 컨트롤러에서 RuntimeException이 발생하면 handleRuntimeException()메소드를 통해서 익셉션을 처리한다. @ControllerAdvice 적용 클래스가 동작하려면 해당 클래스를 스프링에 빈으로 등록해주엉 한다. <bean class="chap13.common.CommonExceptionHandler"/> @ControllerAdvice클래스에 있는 @ExceptionHandler메소드와 컨트롤러 클래스에 있는 @ExceptionHandler 메소드 중 우선순위를 갖는 것은 컨트롤러 클래스에 적용된 @ExceptionHandler클래스이다. 즉, 컨트롤러의 메소드를 실행하는 과정에서 익셉션이 발생하면 다음의 순서로 익셉션을 처리할 @ExceptionHandler메소드를 찾는다. 1. 같은 컨트롤러에 위치한 @ExceptionHandler 메소드 중 해당 익셉션을 처리할 수 있는 메소드를 검색 2. 같은 클래스에 위치한 메소드가 익셉션을 처리할 수 없을 경우, @ControllerAdvice클래스에 위치한 @ExceptionHandler메소드

(스프링) 컨트롤러 익셉션 처리하기

이미지
*익셉션 화면이 보이는 것보다는 알맞게 익셉션을 처리해서 사용자에게 더 적합한 안내를 해 주는 것이 더 좋은 방법이다. MemberNotFoundException의 경우 try-catch로 잡은 뒤 안내 화면을 보여주는 뷰를 보여주면 될 것이다. 그런데, 타입 변환 실패에 따른 익셉션은 어떻게 해야 에러 화면을 보여줄 수 있을까? 이럴때 유용하게 사용할 수 있는 것이 바로 @ExceptionHandler애노테이션이다. 같은 컨트롤러에 @ExceptionHandler애노테이션을 적용한 메소드가 존재하면, 스프링 MVC는 그 메소드가 익셉션을 처리하도록 한다. 따라서, 컨트롤러에서 발생한 익셉션을 직접 처리하고 싶다면 @ExceptionHandler애노테이션을 적용한 메소드를 구현해주면 된다. ---->@ExceptionHandler의 값으로 TypeMimatchException.class를 주었다. 이 익셉션은 경로 변수값의 타입이 올바르지 않은 경우에 발생하는데, 이 익셉션이 발생하면 에러 응답을 보내지 않고 handleTypeMismatchException()메소드를 실행한다. 비슷하게 detail()메소드를 실행하는 과정에서 MemberNotFoundException이 발생하면 handleNotFoundException()메소드를 이용해서 익셉션을 처리한다.

(스프링) @PathVariable을 이용한 경로 변수 처리

이미지
*ID가 10인 회원의 정보를 조회하기 위한 URL을 구성할 때 다음과 같이 ID 값을 요청경로에 포함시키는 방법을 사용할 수 있다. http://localhost:8080/sp4-chap13/member/detail/10 각 회원의 ID값이 달라지므로 회원마다 경로의 마지막 부분이 달라진다. 이렇게 경로의 특정부분의 값이 고정되어 있지 않고 달라질 때 사용할 수 있는 것이 @PathVariable이다. @PathVariable을 사용하면 가변 경로를 처리할 수 있다. 매핑경로에 '{경로변수}'와 같이 중괄호로 둘러싸인 부분을 경로변수라고 부른다.  "{경로변수}"에 해당하는 값은 같은 경로 변수 이름을 지정한 @PathVariable파라미터에 전달된다. 위 코드에서는 {id}에 해당하는 부분이 @PathVariable("id")애노테이션이 적용된 memId파라미터에 전달한다. memId파라미터의 타입은 Long인데 이 경우 String타입을 알맞게 Long타입으로 변환해준다.

(스프링) 변환처리에 대한 이해

이미지
@DateTimeFormat 애노테이션을 사용하면 지정한 형식의 문자열을 Date타입으로 변환해준다. 그럼 누가 문자열을 Date타입으로 변환해줄까? 답은 WebDataBinder에 있다. 스프링 MVC는 @RequestMapping 적용 메소드의 DispatcherServlet 사이를 연결하기 위해 RequestMappingHandlerAdapter객체를 사용하는데, 이 핸들러 어댑터 객체는 요청 파라미터와 커맨드 객체 사이의 객체 사이의 변환 처리를 위해 WebDataBinder라는 것을 이용한다. WebDataBinder는 @RequestMapping적용 메소드의 파라미터에 지정한 커맨드 클래스를 이용해서 커맨드 객체를 생성한다. 그리고 커맨드 객체의 프로퍼티와 같은 이름을 갖는 요청 파라미터를 이용해서 프로퍼티 값을 생성한다 -->WebDataBinder는 직접 타입을 변환하지 않고 위 그림처럼 ConversionService에 그 역할을 위임한다. <mvc:annotation-driven> 태그를 사용하면, ConversionService로 DefaultFormattingConversionService

(R) 성능 향상: 속도와 메모리

1. 속도향상을 위한 벡터화 ifelse(), which(), where(), any(),all(), cumsum(), cumprod()가 있다. 행렬의 경우 rowSums(), colSums() 등이있다. 2. 함수평 프로그래밍과 메모리 문제 대부분 R 객체는 '불변성'을 갖고 있어서 변경할 수 없다. 그래서 R연산은 특정 객체를 재할당하는 함수로 구현돼 있는데, 이런 성격은 성능에 영향을 미친다. *벡터할당 문제 z[3]<-8 이것은 내부에서 z를 복사하고 복사본의 3번쨰 원소를 8로바꿔, 결과 벡터를 z에 재할당한다. 그리고 이때 결과의 z는 복사본을 가리키고 있다는 것을 기억하자. 즉 벡터원소 하나를 바꿧을 뿐이지만, 문법적으로는 '벡터 전체를 새로 계산한 것이다' tracemem()은 메모리 재배치에 대해 알려준다.(주소를 알려줌) *리스트를 여러개 만드는 것보다 행렬 하나를 만드는게 빠르다.. *코드에서 느린 부분을 찾을 때 사용하는 Rprof() ********R세션의 모든 객체는 메모리에 저장된다. 램사이즈의 크기에 관계없이 231-1바이트의 객체 크기 제한이 있다. 하지만 좀만 신경을 쓰면 많은 메모리를 필요로하는 프로그램도 R에서 잘 사용할 수 있따. 청킹과 메모리 관리용 R패키지이다. 청킹 파일로부터 한번에 하나의 청크 단위로 부터 데이터를 읽어 들이는 방법이다. 예를들어 특정 변수의 평균이나 크기를 알고자 한다고하면, 이때 read.table()에서 skip인수를 사용할 수 있다.  데이터세트에 1,000,000개의 데이터가 있고 이를 10개 혹은 그 이상으로 메모리에 적합한 크기로 데이터를 잘랐다고 하자. 그리고 처음에는 skip=0으로 설정하고 두 번째는 skip=100000라고 설정해보자. 매번 청크를 읽을 때마다 각 청크의 수나 총합을 계산해 기록한다. 전체 평균이나 크기를 계산할 필요없이 모든 청크를 다 읽은

(스프링) 컨트롤러에서 쿠키 사용하기

이미지
사용자의 편리함을 위해 아이디를 기억해 두었다가 다음에 로그인을 할 때 아이디를 자동으로 넣어주는 사이트가 많다. 이 기능을 구현할 때 쿠키를 사용한다. 여기서는 쿠키를 사용해서 이메일 기억하기 기능을 추가해보자. 이메일 기억하기 기능을 구현하는 방식은 다음과 같다. 로그인 폼에 '이메일 기억하기'옵션을 추가한다. 로그인 시에 '이메일 기억하기'옵션을 선택했으면, 로그인 성공 후 쿠키에 이메일을 저장한다. 이때 쿠키는 웹 브라우저를 닫더라도 삭제되지 않도록 유효시간을 길게 설정한다. 이후, 로그인 폼을 보여줄 때 이메일을 저장한 쿠키가 존재하면 입력 폼에 이메일을 보여준다. LoginCommand클래스에 rememberEmail필드를 추가했다. 이메일 기억하기 기능을 위해 추가해야 할 부분은 다음의 세 곳이다. loginForm.jsp에 이메일 기억하기 선택 항목을 추가한다. LoginController의 form()메소드에서 쿠키가 존재하는 경우 폼에 전달할 커맨드 객체의 email 프로퍼티를 쿠키의 값으로 설정한다. LoginController의 submit()메소드에서, 이메일 기억하기 옵션을 선택한 경우 로그인 성공 후에 이메일을 담고 있는 쿠키를 생성한다. @CookieValue애노테이션의 value속성은 쿠키의 이름을 지정한다. 이 경우는  이름이 REMEMBER인 쿠키를 Cookie타입으로 전달받게 된다. 지정한 이름을 가진 쿠키가 존재하지 않을 수도 있다면 required속성의 값을 false로 지정해주어야 한다.  이 경우 이메일 기억하기를 선택하지 않을 수도 있기 때문에 required속성의 값을 false로 지정했다.  REMEBER쿠키가 존재할 경우 쿠키의 값을 읽어와 커맨드 객체의 email프로퍼티 값을 설정한다. 커맨드 객체를 사용해서 폼을 출력하므로, REMEMBER쿠키가 존재하면 입력 폼의 email부분에 쿠키의 값이 채워져

(스프링) 인터셉터 사용하기

이미지
로그인 하지 않은 상태에서 비밀번호를 바꾸는 URL주소를 입력하면, 비밀번호 변경 폼이 출력될 것이다. 로그인하지 않았는데 변경 폼이 출력되는 것은 다소 이상하다. 그것보다는 로그인하지 않은 상태에서 비밀번호 변경 폼을 요청하면, 로그인 화면으로 이동시키는 것이 더 좋은 방법인 것 같다. 이를위해, HttpSession에 "authInfo"객체가 존재하는지 검사해서, 존재하지 않으면 로그인 경로로 리다이렉트하도록 구현한 코드를 컨트롤러 클래스에 추가한 것이다. 그런데 실제 웹 어플리케이션에서는 비밀번호 변경 기능외에 더 많은 기능이 로그인 여부를 확읺야 하는데, 각 기능을 구현한 컨트롤러 코드에 위와 같이 세션을 확인하는 코드를 삽입하는 것은 많은 중복을 발생시킨다. 이렇게 다수의 컨트롤러에 대해 동일한 기능을 적용해야 할 때 사용할 수 있는 것이 인터셉터이다. 스프링은 인터셉터를 지원하기 위해 HandlerInterceptor인터페이스를 제공한다. 1. HandlerInterceptor 인터페이스 사용하기 다음의 세 가지 시점에 공통기능을 넣을 수 있다. 컨트롤러(핸들러)실행 전 컨트롤러(핸들러)실행 후, 아직 뷰를 실행하기 전 뷰를 실행한 이후 다음의 세 개의 메소드를 정의하고 있다. boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception; void postHandle(HttpServletRequest request, HttpServletResponse response,Object handler, ModelAndView modelAndView)throws Exception; void afterCompletion(HttpServletRequest request, HttpServletResponse response,Object handler,E

(스프링) 커맨드 객체의 값 검증과 에러 메시지 처리

이미지
*회원가입 처리 부분의 코드가 동작하긴 하지만, 정상적이지 않은 값을 입력해도 정상적으로 동작할 수 있다. 올바르지 않은 이메일 주소를 입력해도 가입 처리가 되고 이름을 입력하지 않아도 가입을 할 수 있다. 또 다른 문제는 중복된 이메일 주소를 입력해서 다시 폼을 보여줄 때 가입이 처리되지 않는 이유에 대한 설명을 보여주지 않는다. 가입이 실패하는 이유를 보여주어야 한다. 그렇지 않으면 사용자는 혼란을 겪는다. 1. 커맨드 객체 검증과 에러 코드 지정하기 다음 두 인터페이스를 사용한다. org.springframework.validation.Validator org.springframework.validation.Errors Validator 인터페이스는 객체를 검증할 때 사용되며, 다음과 같이 정의되어 있다. public interface Validator{    boolean supports(Class<?> clazz);    void validate(Object target, Errors errors); } --->supports()메소드는 Validator가 검증할 수 있는 타입인지를 검사할 목적으로 사용되고, validate()메소드는 첫 번쨰 마라미터로 전달받은 객체를 검증하고 그 결과를 Erros에 담는 기능을 정의한다. -->validate()메소드에서 target을 실제 타입으로 변환한 뒤에 if문에서 값을 검사한다. email프로퍼티의 값이 유효한지를 검사한다. "email"프로퍼티 값이 존재하지 않을 경우(null이나 빈 문자열인 경우) , errors.rejectValue("email", "required"); "required"를 추가한다. matcher을 통해 정규표현식이 일치한지 검사한다.      ValidationUtils.reject

(R) 시각화 함수 ggplot

이미지
*ggplot()함수는 data, 좌표시스템, geoms집합(데이터 점에 대한 시각적표현)을 사용한다. *ggplot 막대 그래프 library(ggplot2) ggplot(simpledat_long, aes(x=Aval, y=value, fill=Bval))+geom_bar(stat="identity", position="dodge") X축은 Aval, Y축은 value, 그리고 그 사이에 채워지는 값은 Bval이 된다. 만약 이 그래프를 선으로 바꾸려면 geom_line()을 사용하면 된다. *ggplot 선 그래프 ggplot(simpledat_long,aes(x=Aval,y=value,colour=Bval,group=Bval))+geom_line() fill 대신 colour을 사용해 '채우기' 색깔이 아닌 '선' 색깔에 대입하였다. *몇 가지 용어와 이론 데이터는 우리가 시각화하고 싶은 대상이다. 데이터는 '변수'로 구성되어 있으며, 변수는 데이터프레임에서 열로 저장한다. '도형(geom)'은 데이터를 표현하기 위해 그리는 도형 객체들로, 막대와 선, 점 등이있다. 에스테틱 속성(aesthetics)은 도형의 시각적인 속성으로, x위치나 y위치, 선 색상, 점 모양 등이다. 데이터 값을 에스테틱에 '대입(map)'한다. '척도(scale)'는 데이터의 공간의 값들을 에스테틱 공간의 값들로 대입하는 과정을 제어한다. 연속적인 y척도는 숫자가 큰 값을 수직 공간 상 더 높은 위치에 대입해준다. '가이드(guide)'는 독자가 시각적인 속성들을 데이터 공간으로 어떻게 대입해야 하는지 알려주는 역할을 한다. 가장 흔하게 사용하는 가이드로는 눈금표시와 축 라벨이있다. 예) dat<-d

(R) plyr패키지 (ddply, adply)

이미지
1. adply 함수 adply()는 배열(a)을 받아 데이터 프레임(d)을 반환하는 함수다. 그러나 입력이 받으시 배열일 필요는 없다. 그보다는 주어진 입력을 숫자 색인으로 읽을 수 있는가(즉, 행렬처럼 다룰 수 있는 형태의 데이터인가)하는 점이 중요하다.  plyr::adply(      .data, #행렬,배열 또는 데이터프레임      #함수를 적용할 방향. 1(행 방향), 2(컬럼 방향) 또는 c(1,2)(행과 컬럼 모두의 방향)     .margins,     .fun=NULL  #.margin방향으로 잘려진 데이터에 적용할 함수 ) 반환값은 데이터 프레임이다. adply()함수는 apply()함수와 유사하지만, apply()는 행 방향으로 처리할 때 각 컬럼에 서로 다른 데이터 타입이 섞여 있다면 예상치 못한 타입 변환이 발생할 수 있다. apply()에 숫자형 컬럼만 입력으로 주어졌을 경우는 그 값이 제대로 숫자로 나오지만, 문자열이 섞이면 데이터가 모두 문자열로 변환된다. 반면 adply()를 사용해 결과를 데이터 프레임을 변환하면 결과 타입이 문자열로 모두 바뀌는 현상을 피할 수 있다. 예) >adply(iris,1,function(row){row$Sepal.Length>=5.0 & row$Species=="setosa"}) 2. ddply 함수 데이터 프레임을 분할하고 함수를 적용한 뒤 결과를 데이터 프레임으로 반환한다. plyr::ddply(      .data,      .variables, #데이터를 그룹 지을 변수명      .fun=NULL ) adply()와 ddply()의 가장 큰 차이점이라면 adply()는 행 또는 칼럼 단위로 함수를 적용하는 반면 ddply()는 .variables에 나열한 칼럼에 따라 데이터를 나눈 뒤 함수를 적용한다는 점이다. #날짜별, 테스트 케이스

(데이터 분석) A/B 테스트

*A/B 테스트는 여러 선택지 중에서 어느 것이 가장 좋은 결과를 가져다줄지 알아보기 위한 검증방법이다. 예를들어, 배너 A와 B를 따로 광고하게 되면 외부요인의 영향이 생길 수 밖에없지만, 배너 A와 B를 동시에 광고하면 외부요인의 영향을 배제할 수 있는 것이다. 예를들어, A와 B라는 2개의 제품을 만들고 동시에 판매해서 데이터를 수집하고, 타깃 고객층에 크게 어필한 것이 어느 쪽인지 검증하는 것이다. 비용이 제법 들지만, 같은 시기에 같은 타깃 고객층에 대한 분명한 인과관계를 알 수 있기 떄문에 많이 사용한다. *A와B의 구분은 임의적이어야 한다. A/B테스트를 실시하기 위해서는 먼저 유저를 A와 B두 그룹으로 나누어야 한다. 그룹 A에는 배너 A를, 그룹 B에는 배너 B를 보여준 후 그룹 A와 그룹 B의 구매율을 비교한다. 이떄 주의해야 할 점이 있습니다. 그것은 그룹 A와 그룹 B를 나누는 방법이다. 예를들어, A: 남성 B: 여성 이렇게 나누더라도 시기적인 요인이나 게임의 이벤트, TV광고 등의 영향은 배제할 수 있을 것입니다. 그러나 게임에서 사용하는 금액은 남녀 간에 차이가 날 수 있습니다. 또한 앞에서 TV광고등의 영향을 배제할 수 있을 거라고 했지만, 곰곰히 생각해보면 남녀가 TV를 시청하는 시간이나 선호하는 방송이 다를 수 있습니다. 즉, 그룹 A와 B를 구분할 때는 두 그룹간에 '남녀'와 같은 명확한 차이가 나타나지 않도록 임의로 나눌 필요가 있습니다. 애당초 A/B테스트를 실시하는 것은 그런 '배너광고 이외의 영향'을 없애고 순순히 배너광고의 내용에 의한 차이를 보기 위해서이니깐요. 두 개의 그룹에서 조건의 차이가 생기지 않도록 하는 가장 단순한 방법은 유저 ID를 어떤 숫자로 나눈 나머지로 분류하는 방법입니다. 이 방법을 이용하면  성별, 연령대, 게임이용시작일 등의 조건이 모든 그룹에 균등학 배분될 것입니다. *A/B 테스트를 동시

(통계학) 카이제곱분포

http://math7.tistory.com/57 카이제곱 값은 χ 2  = Σ (관측값 - 기댓값) 2  / 기댓값 으로 계산한다.

(데이터베이스) 제 3정규화

이미지
"기본키(Primary Key)에 의존하지 않고 일반 컬럼에 의존하는 칼럼들을 제거한다." 이를 이전적 함수 종속관계라고하며 이를 해결하는 것이 바로 제 3정규화이다. 위의 주문 테이블에서 키가 아닌 모든 컬럼은 기본키인 주문ID에 종속적인가? 그렇지 않다. 회원명, 전화번호, 회원등급은 회원ID에 종속적이다. 즉 위의 견본데이터에서 회원 ID가 "HONG"임을 알면 회원명은 '홍길동', 전화번호는 222-2222, 회원등급은 '우수'임을 알 수 있다. 그럼 이 설계의 문제점은 무엇인가? 회원이 주문을 할 때마다 동일한 회원에대한 회원명, 전화번호, 회원등급에 대한 데이터가 계속해서 중복되어 쌓일 것이다. 또한 중복되는 데이터들로 인한 데이터 무결성을 유지하는데 문제가 될 수 있다. 만약 홍길동의 전화번호가 222-2222에서 211-1111으로 수정이 되어졌다면 주문 테이블에서 홍길동이란 회원의 모든 전화번호를 수정해 주어야 할 것이다. 제 3정규화란 기본키에 전적으로 의존하지 않고 키가 아닌 일반 칼럼에 의존하는 칼럼을 제거시켜 원래의 제자리에 위치시키는 것이다. 따라서 다음과 같이 새로운 테이블을 구성할 수 있다.

(R) 크로스 집계

이미지
2개 변수의 인과관계를 교차해서 집계하는 분석기법을 크로스 집계라고 한다. 유저속성이 30대여성인 경우와 20대 남성인 경우에 행동패턴이 어떻게 바뀌는지 알고자 할 경우, 그 두가지 속성(성별과 연령대)의 행동결과에 대한 관계가 집계되기 때문에 이를 2중 크로스 집계라고 한다. 두 가지 이상의 유저속성을 이용해서 복합적인 항목과 결과의 인과관계를 도출하는 것을 다중(n중) 크로스 집계라고 한다. -->dau.user.info테이블에서 log_month와 gender 항목에 대해 크로스 집계를 실시한 결과이다. 2013년 8월과 9월에 전체적인 수치는 떨어졌지만, 남녀 간의 구성비율은 거의 변화가 없으므로 성별과 게임이용율 하락에는 연관관계가 크지 않다. 모든 연령대에서 대체로 비슷한 비율로 이용자수가 하락하였으므로, 특별히 특정 연령대가 하락에 영향을 끼쳤다고 볼 수 없다. *n중 크로스 집계 n중 크로스집계를 위해 reshape2라이브러리를 이용한다. 여기서 그중에서는 dcast라는 함수를 이용한다. dcast(AAA,XX~YY+ZZ,value.var="CCC",length) 위와 같이 입력하면 AAA라는 데이터에서 세로축에는 XX를 놓고 가로축에는 YY와 ZZ의 모든 가능한 조합을 놓아 크로스집계를 실시한다. '크로스 집계안의 값은 CCC의 숫자를 세어서 넣으라'는 것이 value.var="CCC", length에 해당한다. *시계열의 트렌드 그래프 그리기

(R) 11장. 문자열 처리

이미지
1. grep() grep(pattern,x)는 문자열 벡터 x에서 특정 부분 문자열 pattern을 찾기 위해 호출한다. 첫 번째의 경우"Pole" 문자열은 두 번쨰 인수의 2번째와 3번쨰 원소에서 나타난다. 두 번쨰의 경우 아무데도 없어서 빈 벡터가 반환된다. 2. nchar() nchar(x)는 x의 길이를 알려준다. >nchar("South Pole") [1] 10 3. paste() 여러 문자열을 하나의 긴 문자열로 합쳐준다. >paste("North","Pole") [1] "North Pole" >paste("North","Pole",sep=".") [1] North.Pole 예제에서 선택 인수 sep는 문자열 사이에 기본으로 사용되는 띄어쓰기 대신 다른 문자를 넣고 싶을 때 사용한다. 4. sprint() 주어진 형식에 맞춰서 문자열을 조합한다. >i<-8 >s<-sprintf("the square of %d is %d,i,i^2) [1] "the square of 8 is 64" 5. substr() substr(x, start, stop)은 주어진 문자열 x에서 start부터 stop까지의 범위에 위치한 부분 문자열을 출력한다. >substring("Equator",3,5) [1] uat 6. strsplit() strsplit(x, split)은 x에서 문자열 split을 기준으로 나눠 부분 문자열의 리스트를 만든다. >strsplit("6-16-2011",split="-") [[1]] [1

(데이터베이스) 2정규화

이미지
2. 제 2정규화 "복합키(Composit Primary Key)에 전체적으로 의존하지 않는 속성들을 제거한다." 우선 제 2정규화의 대상이 되는 테이블은 키가 여러 칼럼으로 구성된 경우이다. 제 2정규화를 이해하기 위해서 우선 '키에 의존적(지배적)이다' 라는 말의 의미를 먼저 살펴보자. '키의 값을 알면 칼럼 값을 알 수 있다.' 위 테이블의 기본키는 사원번호이다. 키가 아닌 일반칼럼은 모두 기본키에 의해 지배되어야 한다. 키에의해 지배되어야 한단느 것은 위의 사원 테이블에서 사원번호를 알면 그 사원에 대한 이름, 주소, 성별, 입사일을 알 수 있음을 의미한다. 만약 사원 테이블에 상품명이라는 칼럼이 들어와 있다고 하자. 상품명이 사원번호에 의조적인가? 그렇지 않다. 이런 칼럼들은 전혀 의미가 없으며 걸러져 제자를 찾아가야만한다. 기본적으로 테이블의 키가 아닌 모든 칼럼들은 기본키에 의존적이어야만 한다. 만약 테이블의 기본키가 여러 컬럼으로 구성된 경우 즉, 복합키인 경우도 역시 모든 칼럼들은 복합키 전체에 의존적이어야 한다. 만약 복합키 전체에 의존하지 않는 컬럼이 존재하는 경우 기본 테이블에서 제거시켜 새로운 테이블을 생성해 주어야 한다. 평가코드는 학번, 과정코드 전체에 의존적이지만 과정명은, 기간은 복합키의 일부분인 과정코드에 의해서 지배됨을 알 수 있다. 이렇게 테이블이 설계되었을 경우의 문제점은 과정명, 기간에 중복되는 데이터가 계속 쌓이게 된다. 또한 이렇게 설계되었을 경우에 데이터의 무결성을 유지하는데 어려움이 따른다. 만약 'JAVA' 과정명이 C++로 수정되었을 경우에 그에 해당하는 모든 데이터를 수정해야 한다. 제 2정규화 이론을 적용시켜 복합키의 일부분 즉, 과정코드에 의존적인 속성인 과정명, 기간을 기본 테이블에서 제거시켜 새로운 테이블을 구성하면 다음과 같은 두 개의 테이

(데이터베이스) 1정규화

이미지
1. 제 1정규화 "반복되는 그룹 속성을 제거한 뒤 기본 테이블의 기본키를 추가해 새로운 테이블을 생성하고 기존 테이블과 1:N의 관계를 형성한다." 만약 홍길동이라는 사람이 운전면허1종, MCSE, 정보처리기사 자격증을 갖고 있다고 하자. 이럴 경우 홍길동의 데이터를 모두 저장하기 위해서는 아래와 같이 3개의 레코드가 필요할 것이다. 이렇게 하면  몇 가지 문제가 생길 수 있다. 즉 쓸데없는 데이터베이스의 공간이 낭비가 발생한다. 또한 만약 홍길동의 주소나 핸드폰번호가 바뀌게 되면 3개의 레코드를 모두 변경해야 한다. 그래서 1차 정규화의 대상이 되는 것이다. 이를 해결하기 위해서는 반복 되어지는 그룹 속성을 제거한 뒤 새로운 테이블을 생성하고 기존의 테이블과 1:N의 관계를 형성하면 된다. <2번째 예제> 어떤 학원에서 진행 중인 각 과정들의 데이터를 과정이라는 테이블에서 관리한다고 하자. 그리고 각 과정에 소요되는 교재를 과정 테이블에서 컬럼으로 관리한다면 다음과 같다. 이 테이블엣 교재 컬럼의 개수는 학원의 과정들 중에서 가장 많은 교재를 사용하는 과정을 기준으로 설정되어야 하며 아래의 견본 데이터에서는 5권이라 가정했다. 이렇게 데이터가 들어갈 경우 교재가 5권인 웹프로그래밍의 컬럼들은 모두 채워지지만 그외의 과목은 최소 1개 이상의 NULL값이 들어가지게된다. 테이블에 NULL값이 많다는 것은 쓸데없는 데이터 저장 공간의 낭비이다. 그래서 교재컬럼처럼 반복되는 속성을 갖는 칼럼의 경우 따로 분리해서 기존의 테이블과 1:N의 관계형성을 해야 한다.

(스프링) 스프링 MVC 프레임워크 동작방식

이미지
*src/main/webapp/WEB-INF/web.xml 파일에 DispatcherServlet를 설정한다. DispatcherServlet은 전달받은 설정 파일을 이용해서 스프링 컨테이너를 생성하는데, HandlerMapping, HandlerAdapter, 컨트롤러, ViewResolver등의 빈은 DispatcherServlet이 생성하는 스프링 컨테이너로부터 구한다. <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/appServlet/servlet-   context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/root-context.xml</param-value> </context-param> ---->contextConfiguration 초기화 파라미터를 설정하지 않은 경우, DispatcherServlet은 WEB-INF/[서블릿이름]-servlet.ml 파일을 설정파일로 사용한다. 여기서는 다음과 같다. /WEB-INF/spring/appSe

(R) 7장 조건문

이미지
7.1 조건문 for문, while문, 7.1.2 벡터 이외의 유형을 사용하는 반복문 lapply() 를 사용한다. 반복문의 반복이 각각 순서가 상관없는 독립적인 데이터에 적용될 때 사용할 수 있다. get()을 사용한다. 함수명이 말해주듯이 함수는 객체의 이름을 뜻하는 문자열을 인수로 받아 해당 이름의 객체를 반환해 준다. 별것 아닌 것처럼 들리지만 get()은 매우 강력한 함수다. 여기서 m에는 첫 번째로 u가 들어간다. 그 후 u를 z에 할당해 다음에서 u에 대해 lm()이 호출되도록 한다. 7.2 산술 및 불리언 연산과 값 x^y : 제곱 x%/%y : 정수 나눗셈 x&&y : 불리언 AND(정수형) x&y : 불리언 AND(벡터 x,y,result) x/y : 나눗셈 x||y : 불리언 OR(정수형) x|y : 불리언 OR(벡터 x,y,result) * R은 함수 안에 다른 함수를 감싸 안을 수 있다. function(y){   d<-8   h<-function(){      return(d*(w+y))   }   print(environment(h))   return(h()) } *R에서 함수는 지역변수가 아닌 변수를 바꾸지 않는다는 것이다. 이 말은 일반적으로  '부작용 side effect'이 없다는 뜻이다. 간단히 말해 만약 지역변수내에서 값을 바꾸게 되면 값이바뀌는 것처럼 보이지만 지역 복사본이 바뀌는 것 뿐이다.

(R) 6장 팩터와 레벨

이미지
R팩터는 간단하게 벡터에 추가 정보가 더해진 것으로 보면된다. 추가정보는 벡터의 값 가운데 겹치지 않는 값의 기록으로 이뤄져 있고, 이를 '레벨level'이라고 한다. 예) x<-c(5,12,13,12) xf<-factor(x) xf는 [1] 5 12 13 12 Levels: 5 12 13 *팩터의 길이는 레벨의 수가 아닌 데이터의 길이로 정의된다. *다음처럼 세 레벨을 추가할 수 있다. x<-c(5,12,13,12) xff<-factor(x,levels=c(5,12,13,88)) xff는 [1] 5 12 13 12 Levels: 5 12 13 88 >xff[2]<-88 >xff [1] 5 88 13 12 Levels: 5 12 13 88 만약 레벨에 없는 겂 xff[2]<-28을 하게되면 에러가 발생한다. 6.2 팩터에 사용되는 일반적인 함수 6.2.1 tapply()함수 tapply()는 임시로 x를 팩터의 각 레벨(혹은 팩터가 여러 개일 경우 팩터의 레벨 간의 조합)에 대응되는 그룹별로 나눈 후 이에 따른 x의 부분 벡터에 g()를 적용한다. >ages<-c(25,26,55,37,21,42) >affils<-c("R","D","D","R","U","D") >tapply(ages,affils,mean) D    R    U 41  31   21 만약 팩터가 2개이상이면 어떻게 될까? 그럼 각 팩터는 앞의 예제처럼 각 그룹을 만들고, 각 그룹 간에 AND연산이 일어난다. 예를들어 성별, 나이, 수입에 대한 변수를 포함하는 데이터 세트에 tapply(x,f,g)에서 x는 수입, f는 성별과 해당 사람이 25살을 기준으로 아래인지 위인지가 표기된 두 개의 팩터가 될 것이다