728x90

1. URI(Uniform Resource Identifier)

  • Uniform : 리소스를 식별하는 통일된 방식
  • Resource : 자원, URI로 식별할 수 있는 모든 것(제한 없음)
  • Identifier : 다른 항목과 구분하는데 필요한 정보

 

URI? URL? URN?

  • URI(Resource Identifier) : 자원을 식별하는 통일된 방식
  • URL(Resource Locator) : 리소스의 위치를 지정
  • URN(Resource Name) : 리소스의 이름을 부여 (이름만으로 리소스를 찾는 방법은 어렵다..잘 사용x)

URL 전체 문법

  • scheme://[userinfo@]host[:post][/path][?query][#fragment]
  • https://www.google.com:433/search?q=hello&hl=ko 

shema

  • 주로 프로토콜 사용
  • 프로토콜 : 어떤 방식으로 자원에 접근할 것인가 하는 약속 ( http, https, ftp 등)
  • http는 80 포트, https는 443 포트를 주로 사용, 포트 생략 가능
  • https는 http에 보안이 추가(HTTP Secure)

userinfo

  • URL에 사용자 정보를 포함해서 인증, 거의 사용하지 않음

host

  • 호스트명 / 도메인명 또는 IP주소

PORT

  • 생략가능 / 생략시 http는 80, https는 443

path

  • 리소스 경로(path), 계층적 구조
  • 예시
    • /home/file1.jpg
    • /members /members/100
    • /items/iphone12

query

  • key=value 형태
  • ?로 시작, &로 추가 가능 - ?keyA=valueA&keyB=valueB
  • query parameter, query string 등으로 불림, 웹서버에 제공하는 파라미터, 문자 형태

fragment

  • html 내부 북마크 등에 사용
  • 서버에 전송하는 정보는 아님

2. 웹 브라우저 요청 흐름

  1. DNS 조회, 생략 PORT 생성
  2. HTTP 요청 메세지 생성GET /search?q=hello&hl=ko HTTP/1.1
    Host: www.google.com
  3. SOCKET 라이브러리를 통해 전달
  4. TCP/IP 연결(IP, PORT)
  5. 인터넷으로 전송, 수 많은 노드를 거쳐 서버로 전송
  6. 서버에서 HTTP 응답 메세지 생성, 전송
728x90
728x90

 

https://www.conventionalcommits.org/ko/v1.0.0/

 

Conventional Commits

커밋 메세지에 사용자와 기계 모두가 이해할 수 있는 의미를 부여하기 위한 스펙

www.conventionalcommits.org

https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional

 

conventional-changelog/commitlint

📓 Lint commit messages. Contribute to conventional-changelog/commitlint development by creating an account on GitHub.

github.com

 

사실 팀에서 정해야하는 것이고 
이렇게 해야한다는 법은 아니지만 팀에서 룰을 정할때 참고하면 좋을듯하다.

728x90
728x90

유용한 정보 가져왔습니다.

[출처] blog.naver.com/adamdoha/222294541672

필자 환경 : Mac OS Big Sur

(Window 유저는 ssh보다 Putty로 접속하는게 편합니다.)

지난번에는 EC2에 접속한 뒤에 비밀번호를 입력해서 들어갔었습니다.

요약하자면, EC2를 대여받고 EC2에 pem키로 한 번은 접속을 한 뒤, 비밀번호를 설정하면 이후에도 비밀번호로 접속할 수 있는 방식이었습니다.

한 서버를 여러명이 사용할 때, 한 사람이 지난 번 방식으로 접속 설정을 해두면, 다른 사람들은 pem key를 몰라도 접속할 수 있었는데요. 이번에는 조금 다릅니다. ec2로 ssh 접속하려는 컴퓨터에서 pem key를 가지고 있어야 합니다.

이번에는 어찌말하면 그냥 ssh -i ~.pem host alias를 설정하는 느낌인데요.

요런 방법도 있고 저런 방법도 있구나 가볍게 보시면 될 것 같습니다.

1. AWS EC2를 생성할 때 .pem key 다운로드.

2. ssh 접속을 할 것이니, 이 파일을 복사하자.

보통은 다음과 같이 접속하겠죠. IdentityFile은 AWS에서 만들어준 pem key, 그리고 user와 host 입력.

ubuntu를 빌리셨다면 ubuntu@host가 되겠죠. 저는 Amazon Linux를 빌려가지고 user가 ec2-user입니다.

$ ssh -i yourec2.pem ec2-user@host

이게 사실 접속할 때마다 pem key가 있는 곳을 일일이 찾아야 하고, 우분투를 빌렸었나, 리눅스를 빌렸었나 알아야하고, 또 host 주소도 알고 있어야 해서 굉장히 귀찮습니다..

그래서 ssh 접속을 할 것이기에, 이걸 .ssh 폴더로 복사해줍시다.

$ cp ./yourec2.pem ~/.ssh/

3. pem key 권한을 변경하자.

복사했다면 위 pem key 권한을 변경해줍니다.

그냥 접속해보시면 아시겠지만, 터미널이 "야 이거 너무 오픈된거 아님? 이래놓고 Key라고 할 수 있겠어?"라고 뭐라고 합니다.

일단 제대로 복사 됐는지 .ssh 디렉터리가서 확인해봅니다.

$ cd ~/.ssh

그리고 권한을 다음과 같이 수정합니다.

$ chmod 600 yourec2.pem

4. config 파일을 만들자

그리고 config 파일을 생성해줄 건데요.

$ vi ~/.ssh/config

여러분의 에디터를 이용해서 다음과 같이 작성하시면 됩니다.

# my-application 여기에다가 Host를 구분하기 위한 주석을 작성해주는 것이 좋습니다. Host {서비스 이름} # 여기에 입력하는 값으로 -i yourec2.pem ec2-user@eip 를 대신합니다. HostName {여기엔 eip를 주로 넣습니다} User ec2-user # 우분투를 빌린 분들은 여기에 ubuntu가 들어가야 합니다. IdentityFile ~/.ssh/yourec2.pem # 이전 단계에서 복사했으니, 이 경로로 지정하면 되겠죠.

그리고 :wq 저장!

이 파일은 실행이 필요합니다. x권한(실행 권한)이 추가되면 좋겠네요.

따라서 다음과 같이 권한을 주겠습니다.

$ chmod 700 ~/.ssh/config

5. 접속

이제 다음과 같이 바로 접속 가능해집니다.

$ ssh {config에 입력한 서비스 이름}

문두에 왜 alias를 설정하는 느낌이라고 했는지 이해하셨을 겁니다.

 

 

728x90
728x90

AWS EC2에 접속하려면 pem키를 가지고 접속을 해야하는데 

조금 귀찮다. 

 

그래서 password를 설정해서 접속하는 방법을 알아보자

 

pem 키로 ssh접속하기

우선 pem키로 ssh 접속하는 방법을 알아보자 

 

ssh -i keyname.pem ubuntu@ip

 

입력하면 접속이된다. keyname에 본인 pem 이름을 넣어주면 된다.

귀찮다.... 그래서 password로!

 

password로 접속하기

ssh ubuntu@ip

 

그래서 위와 같이 비밀번호 쳐서 들어가게 바꾸려고 한다.

우선은 pem키를 통해서 우분투에 접속한다.

$ sudo vim /etc/ssh/sshd_config

라고 치면 설정하라고 나온다.

그대로 쳐주자!

PasswordAuthentication가 yes인게 포인트!

 

그리고 password 설정!

sudo URpasswd ubuntu

 

나중에 key pair로 로그인하기 위해서 키페어를 복사하는 작업을 해주자.

ec2에선 이미 다음 경로에 .ssh 폴더가 있으니 복사만 해주면 된다.

(없는 경우엔 다음 경로에 .ssh 만드시면 됩니다.)

sudo cp /home/ubuntu/.ssh/authorized_keys /root/.ssh

 

ssh 재부팅!

sudo service ssh restart

 

다시 접속해보면 password만 입력하면되는 것을 볼 수 있다!

728x90
728x90

이 전글에서 전통적인 회귀 방법을 알아보았다.

 

다시 정리하자면 

전통적인 회귀의 목적은 최적의 방정식을 찾는것이다.

Y = AX + B (최적방정식)을 통해 parameter A,B를 찾아야한다.

 

MSE를 최소로하는 LMS(최소제곱법)을 사용하여 찾을 수 있는데

사람이 MSE를 구하려면 일일이 계산을 해야한다.(쌩노가다. 특히, 데이터가 커질 수록 노가다 양은 증가!!!)

 

그래서 사람들은 LMS값과 결과가 비슷한 공식을 만들어 사용하였다.

r = 상관계수, S = 표준편차, X바, Y바 = 평균

하지만! 머신러닝은 노가다를 해준다!!

머신러닝의 목표 예측, 분류
머신러닝도 최속제곱법을 사용한다.

 

머신러닝으로 모델링하는 과정

  1. Y=AX+B와 같은 학습 목표를 정해준다.
  2. A,B에 램덤으로 초기값을 주고 아무렇게나 선을 그리게한다.
  3. MSE를 일일이 계산해가면서, 최적의값을 구한다.

결국 목적은 parameter를 찾는거! 똑같다.

728x90
728x90

상관분석 !

상관분석의 목적 ⇒ 유사도를 구하기 위해서 (유사도 = 관계성) 유사하다는 의미를 무엇을 기반으로 어떻게 정의할것인가?? 가장 많이 쓰는 방법은

  1. 데이터 간 떨어진 거리 ⇒ 거리가 멀면 유사도가 낮다!, 거리가 가까우면 유사하다!
  2. 원점에서 데이터까지 각도 ⇒ 코사인 각도, 두 데이터 사이의 각도가 작을수록 가까운 데이터 (코사인 유사도)
  3. 데이터의 변화량(유사도) ⇒ 1차 방정식 (pearson-r, R) ⇒ 데이터의 변화패턴(변화량)으로 유사도를 구한다.

상관분석이라하믄 보통 R을 나타낸다.

r = 서로 같이 변하는 정도 / 서로 각기 변하는 정도 = 공분산/ 분산 = a교집합b / a합집합b

 

S 표본 집단의 표준편차

루트를 씌우는 이유는 뻥튀기된 거리를 되돌리기

분모 ⇒ x,y 데이터의 변화량(분산)의 총량

분자 ⇒ 두 데이터의 변화 패턴이 동일한 구간의 변화량의 총량, 공통된 변화량의 총량, 공통된 분산(공분산)

 

분산 복습하기

편차 ⇒ 평균에서 각 데이터까지의 거리, 편차의 항상 0

분산 ⇒ 편차 제곱의 평균

분산이 크다 ⇒ 데이터들이 평균에서 거리가 많이 떨어져있다. ⇒ 데이터 변화량이 크다 ⇒델타x가 크다.

분산이 작다 ⇒ 데이터간의 거리가 줄어든다. ⇒데이터 변화량이 작다. ⇒ 델타x가 작다.

 

상관강도 (유사도가 강한 정도) : 절대값을 씌운다.

피어슨 r에서 알고싶은건 !!!!! ⇒ 변화 패턴이 유사한가 ?

 

Pearson-r은 -1에서 1사이의 값이 나올 수 있고요.

Pearson-r에서의 부호, -,+는 유사도의 강도를 나타내는 것이 아니라 지금처럼 증가함수인지 감수함수인지 그 방향성만을 알려주게 되구요.

 

상관 강도, 즉 유사도의 강한 정도는 -와 +가 그냥 방향성만을 나타내 주는 거기 때문에 절대값을 이용해서 나타냅니다.

r이 0인 경우 두 유사도의 강도는 절대값으로 파악해야한다.

 

해석방법 !!!!!!

상관을 구한다는것은 데이터 간 유사도를 알아보는것

예시 ) 우리나라 20대 성인의 신장과 몸무게 간의 상관값으로 r=0.7이 나왔다. 신장과 몸무게는 관계성이 있는가 ? ⇒ 모르지 ! 기준이 없는데!!!!!

그래서 기준은 어떻게 설정할것인가 ? (절대값)유사도(lrl) < 0.3 : 낮은 상관 0.3 ≤ lrl < 0.7 : 보통 (어느정도 관계성이 있다.) lrl ≥ 0.7 : 아주 강한 관계성이 있다. 아주 높다.

 

R^2(R스퀘어) ⇒ 설명력, 결정계수 요건 회귀분석할때 적합성같은것을 확인할 때 이 회귀선이 잘찾은건지 확인할 때 많이 보는 수치

예를 들어 신장과 몸무게 간의 상관값이 0.7이면 R스퀘어는 0.49 이 값을 퍼센트로 바꾸면 49%!

즉, 신장과 몸무게 49%정도 관계가 있고 나머지 51%는 식습관, 환경 등등에 관계가 있다.

 

하지만, 이를 오용하거나 왜곡해서 해석하면 안좋은 결과를 가져올 수 있는데

예를 들어 데이터 x,y가 r=1이면 두 데이터는 아주 높은 상관 관계를 가지고 있다고 볼 수 있다.

그렇기 때문에 x가 y의, y가 x의 원인인다. 라고 생각하면 안된다는것!!!!

이렇게 해석하면 상관 관계로 해석한것이 아닌 인과 관계로 해석하게 된것이다 .

 

예를 들어 두 데이터 아이스크림 판매수, 익사자 수가 있다고 쳐보자 유사도가 굉장히 높게 나올것이다. 그렇다고 두 데이터가 서로의 원인이 되는가 ?? 아니다 !

상관은 ! 데이터간의 유사도를 파악하기 위함이지 그 이상도 이하도 아니다 이 유사도를 이용해서 회귀 (regression)을 통해서 예측을 할것이다 .

 

 

회귀 분석 ! ⇒ 예측을 해보자 !!~!~!~!~!~! 입력값 : 예측에 이용할 값! 출력값 : 예측 결과 X로 Y를 예측 ⇒ 입력은 X, 출력은 Y

예측을 한다는건은 방정식을 정의하는것이다 .

그래야 예측할 수 있으니까~!

상관 : 데이터 간의 변화 패턴으로 유사도(관계성)를 찾는것

회귀 : 정의된 변화 패턴을 이용해서 데이터 간의 관계성을 가장 잘 나타내는 방정식을 찾는 것

회귀분석(Regression) == Data-fitting == Modeling

 

근데 현실에서는 r = 1인 데이터는 없다. (r = -1, r = 0 이런거 역시 없다 !! ㅠㅠ) 그래서 y=x 처럼 단번에 팍 나오는 방정식도 구하기 어려운데 이런 상황에서 우리는 어떻게 방정식을 구할 것인가 ..ㅠㅠ

특히, 최적의 선 어찌 구할 수 있을까 ?

 

매개변수(Parameter) = Model을 구하기 위해 반드시 필요한 변수 (기울기와 절편)

Model = 원하는 목표 방정식 (Y = AX + B)

 

그래프에서 여러 데이터의 점(.)들 ⇒ 산포도(datapoints) 산포도를 선으로 나타낸 것 ⇒ 방정식(Regression) ⇒

오차의 평균이 가장 작은 선 = 최적의 방정식이다 ...

 

근데 오차를 구하면 방향성이 있따..ㅠㅠㅠ 그러니까 전부 제곱을 해서 부호를 똑같이 만들자.

 

즉, 최적의 Model이란?

  1. (실제값 - 예측값)을 오차로 정의하고, 모든 데이터의 오차를 다 구한다.
  2. 오차를 일일이 다 제곱하고 그 제곱 오차의 평균을 구한다.
  3. 제곱 오차의 평균이 가장 작은 것이 최적의 Model이다.

이렇게 구해진 값을 최소 제곱법(LMS) 이라한다.

오차 제곱 평균(MSE) : Mean Squared Error

MSE가 작다 라는 의미는 ⇒ 오차가 작다 ⇒ 예측력이 높다. 근데 제곱을 했었으니까 루트를 씌운다.

그래서 RMSE라고 부른다.

 

Root(루트) Mean(평균) Squared(제곱) Error(오차) ⇒ 예측 모델의 정확도를 나타낼때 자주 사용한다.

Model : 회귀의 목적인 방정식

Parameter : Model을 구해내는데 필요한 매개변수(기울기, Y절편)

즉, '모델의 구하라'라는 말 == '최적의 Parameter를 찾아라'

실제 데이터 - 예측 데이터 = 오차

최소 제곱법(LMS) : 오차 제곱 평균을 구한 후 최소로 만들면 최적이라고 할 수 있다.

오차 제곱 평균(MSE) : 제곱되어 있는 값, 제곱되어 있기떄문에 RMSE를 예측 모델의 정확도를 나타내는데 많이 쓰인다.

RMSE : 예측 모델의 정확도를 나타내는데 많이 사용됨. RMSE가 낮을수록 오차 평균이 작다는 의미이므로 좋은 예측 모델이다.

 

 

회귀의 종류

우리는 지금까지 y=ax+b로 입력값이 1개인 경우만 공부하였다. 하지만 실제로는 2개 이상인 경우도 많다.

예를 들어 온도(X1), 습도(X2)로 아이스크림 판매량 (Y) 예측 Y = AX1 + BX2 + C 이렇듯 입력값이 1개인 회귀는 단순 회귀(simple regression)이라고 부른다.

입력값(input)이 2개 이상인 회귀는 다중 회규(중다, Multiple regression)이라고 부른다.

그렇다면 변수가 많으면 더 좋은 결과값을 구하는걸까 ? NO!! 필요없는 변수를 줄이는 것이 결과에 더 좋다.

데이터로 봤을 때 예측 성능에 높은 영향을 끼칠 변수를 찾아라

1차 방정식 모델 ⇒ Linear regression,

선형회귀 2차 이상 ⇒ Non Linear regression, 비선형회귀

회귀는 예측말고 분류도 할 수 있다.

그러한 회귀는 로지스틱 회귀이다.

입력 변수 개수에 따라 Simple regression과 Multiple regression으로 나뉜다.

Modeling 해야 되는 방정식 차수에 따라 Linear regression과 Non-linear regression으로 나뉜다.

데이터 분석의 최종 목적이 예측 또는 분류로 나뉜다.

728x90
728x90

www.multicampus.com/em/enrolment/courseDetai?p_menu=NzUjU1VC&p_gubun=Qw==&corsCd=A51671&corsYr=2002&corsDgrCd=00021

 

멀티캠퍼스 :: 직무교육전문

데이터사이언스, 프로그래밍, UXUI, 마케팅, 블록체인, 보안, 웹개발, 디자인 실무교육

www.multicampus.com

지루하지않게 10분정도씩 끊어주고 강사님도 재밌다.

 

 

데이터 분석 순서

☞목표정의 —> 전처리 —> 알고리즘 선택/분석 —> 검증 및 테스트

                            ↑_________________________________________⏌


머신러닝은 알고리즘 선택 및 분석에 해당한다. 목적이 명확하고 데이터에서 문제점들을 찾아내서 잘 정리하고 이해한 다음에 구체적으로 어떻게 목표에 원하는 수치를 얻어낼것인가!? (특정 목적에 쓰는 도구 ..) 머신러닝은 = 수단 머신러닝은 특정 결과를 도출하는 '수단'이지 '목적'이 아니다.

머신러닝 사용법

  1. 목적을 정의한다.
  2. 목적에 맞는 데이터가 있어야한다.
  3. 어떤 머신러닝 기법을 쓸지 선택한다. ⇒ 이에따라 결과의 정확도가 달라지게 된다.

데이터 분석을 위해서 알아야할 것

  1. 통계
  2. 수학 ( 선형대수, 미분 ) 미분은 틀린 정도를 알기 위해서 사용한다.
  3. 도구

통계를 조금 알아보자 !

모집단(population) ⇒ 내가 알고싶은 데이터 전체 ( 모든 20대의 키 )

표본(sample) ⇒ 모집단중 일부를 선택하여 얻어진 데이터

표집(sampling) ⇒ 모집단에서 표본을 뽑아내는 작업

표집수(N,number) ⇒ 모집단에서 샘플링을 할 때 몇 개를 뽑았는가? 샘플링은 어떻게 뽑을 것인가?!는 너무 중요하다.

그래서 보통 랜덤 샘플링을 한다. ⇒ 기준없이 무작위로 표집

 

왜! 랜덤 샘플링을 해야하는가!

편향된 데이터를 모을 가능성이 많다 ! ⇒ 편향(bias) 양보다 질 !

편향된 데이터를 줄이는 방법은 ? 기준을 두지않는거 !.....ㅎㅎ;

 

편향(bias) : 특정 기준을 두고 샘플링해서 데이터가 한쪽으로 치우치는 현상 불편향(unbias) : 편향의 반대, 우리가 목표하는 데이터의 상태 무선표집 (ramdom sampling) : 샘플링 시 어떠한 기준을 두지않고 무작위로 추출하는 과정. 편향을 막을 수 있는 가장 대표적인 방법

모수치와 표본수치

모집단의 데이터가 모두 있을 때의 모평균과 모표준편차 = 모수치 모평균(µ, 뮤) : 모집단의 평균

µ = ΣX/N ⇒ 모평균은 표본의 합을 표집수로 나눈것!

 

모표준편차 (σ, 시그마): 모집단의 표준편차

모수치를 얻는것은 매우 어렵다. 우리가 실제로 얻을 수 있는건 표본의 평균과 표준편차이다....ㅠㅠ 표본평균(엑스바) 표본표준편차(s)

표본수치 = 엑스바, s

 

데이터에서 맨 처음 봐야한는 것 !!!!

  1. 분포의 모양
  2. 집중경향치
  3. 분산과 표준편차

분포(distribution) : 데이터의 대략적인 형태 ⇒ 히스토그램으로 나타낸다. 분포는 데이터가 대략적으로 어떻게 생겼는가 알려준다 .

정규분포(nomal distribution, 정상분포) : 좌우대칭 종모양! 평균을 중심으로 좌우대칭으로 데이터가 골고루 퍼져있는 형태 ←→ 한쪽으로 쏠려있는 분포 : 편포

 

정규화(또는 정규분포)라고 가정하는 이유

  1. 전통적인 통계 방법 : 모집단이 정상분포라고 가정하고 만들어졌다.
  2. 중심극한정리 : N을 많이 뽑으면 모든 확률분포가 정규형태가 되고, 이때 표본의 평균은 모평균을 따른다.

이제 대표 데이터를 찾아야한다! 데이터가 너무 많기 때문에 대표할 수 있는 값을 정한다. ⇒ 집중경향치

  1. 수치적으로 가운데 ! ⇒ 평균(mean)
  2. 순서로 가운데 ! ⇒ 정렬하고 순서가 가운데 ⇒ 중앙치 (median)
  3. 데이터의 빈도를 따짐 ⇒ 최빈치(mode)

그래서 분산과 표준편차!

분산과 표준편차 ! 표준편차 ! 왜 구해야죠? 또 그 값은 구체적으로 무엇을 의미하는가 ?!

왜구하냐면 분포와 집중경향치만으로는 데이터의 특성을 다 알 수가 없기 때문이다.

그래서 평균과 각 데이터의 거리 차이를 통해서 데이터의 특성을 알아볼것이다.

편차 ⇒ 평균에서 각 데이터까지의 거리를 구한다. ⇒ 구해진 각각의 거리 = 편차 편차의 합은 항상 0이 나온다 !!

중요~~ 항상 0이 나오니까 데이터의 특성을 알 수가 없다 ㅠㅠ

 

거리의 합이 항상 0이 나오는 문제를 해결하기 위해서 편차의 제곱된 거리의 평균을 낸다.

이러면 비교가 가능하다 !

편차 제곱의 평균 = '분산' (시그마제곱) ! 분산을 통해서 데이터의 각 수치들이 평균에 수렴하는지, 아니면 알아서 넓게 흩어져있는지 그 정도를 알려고하는 것이다.

 

분산과 표준편차 ←→ 데이터와 관계

분산이 크다 ⇒ 평균에 수렴하지 않는다. (그래프가 낮고 넓게 분포된 형태를 띄게된다. )

분산이 작다 ⇒ 평균에 수렴하다.(데이터가 대부분 평균 근처에 있어서 분포 모양이 뾰족하다.)

근데 우리는 편차 제곱의 평균을 원한것이 아니고 편차의 평균을 원했잖아?! 그래서 Root를 씌워서 근사치를 알고싶어졌어

그게 '표준편차'이다.

 

아웃라이어 ! 를 배우기전에 데이터 분석을 왜하는가?

1.객관적 사실, 경향성을 파악하고 이를 통해서 의사결정을하려고.. 여기서 중요한건 객관적! 주관적 입장이 들어가면 분석 목적을 제대로 달성할 수 없다.

 

아웃라이어! 골치덩어리다. 모든 데이터에 무조건 존재하여 분석 결과를 왜곡한다.

직접 아웃라이어를 판단하고 얘네들을 다루어야한다.

다른 수치에 비해 극단적으로 크거나 극단적으로 작은 수치 ⇒ 아웃라이어 중앙치랑 평균을 비교해봐서 차이가 크다면 ⇒아웃라이어가 있다라는 뜻이다.

평균, 중앙치, 최대, 최소 등 각종 수치를 확인하면서 파악해야한다.

아웃라이어는 결과를 왜곡하기 때문에 반드시 제거 후 분석해야한다.

중앙치는 아웃라이어에 덜 민감하다... 없애는 방법

  1. 그냥 빼버린다.
728x90
728x90

https://www.acmicpc.net/problem/17822

 

17822번: 원판 돌리기

반지름이 1, 2, ..., N인 원판이 크기가 작아지는 순으로 바닥에 놓여있고, 원판의 중심은 모두 같다. 원판의 반지름이 i이면, 그 원판을 i번째 원판이라고 한다. 각각의 원판에는 M개의 정수가 적혀

www.acmicpc.net

 

처음 아이디어 : 시뮬레이션 문제로 조건을 다 구현해주면서 풀었다.

 

추가 : bfs 문제 + rotation 함수 사용

 

결론 : 시뮬 + bfs 문제라고 한다 

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import java.util.*;
import java.io.*;
 
public class Main {
    static int cir[][], n, m, t;
    static int[] di = { -1100 };
    static int[] dj = { 00-11 };
 
    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken()); // 원판의 크기
        m = Integer.parseInt(st.nextToken()); // 각 원판의 정점 갯수
        t = Integer.parseInt(st.nextToken()); // t번 회전 시킴
 
        cir = new int[n][m]; // 원판    
        int x = 0;
        int d = 0;
        int k = 0;
        for (int i = 0; i < n; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < m; j++) {
                cir[i][j] = Integer.parseInt(st.nextToken());
//                System.out.print(cir[i][j]+" ");
            }
//            System.out.println();
        }
        // t번 돌리자 
        for (int i = 0; i < t; i++) {
            st = new StringTokenizer(br.readLine());
            x = Integer.parseInt(st.nextToken()); // x배수 원판을 돌리자
            d = Integer.parseInt(st.nextToken()); // 0 시계 1 반시계
            k = Integer.parseInt(st.nextToken()); // k 칸 돌림
            
            start(x, d, k);
        }
        
        
        int ans = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                ans += cir[i][j];
            }
        }
        System.out.println(ans);
        br.close();
    }
    
    
    //
    static void start(int nx, int nd, int nk) {
        int temp = 0;
        for (int i = 1; i <= nk; i++) { // 몇 바퀴 돌릴꺼 ?
                for (int j = 1;; j++) {
                    // x 배수 원판을 돌리자 
                    int a = j * nx;
                    // 원판 크기 보다 커지면 멈춤 
                    if (a > n)
                        break;
                    
                    // 시계 방향
                    if (nd == 0) {
                        for (int k = m-1; k > 0; k--) {
                            temp = cir[a -1][k];
                            cir[a - 1][k] = cir[a - 1][k - 1];
                            cir[a - 1][k - 1= temp;
                        }
                        
                    } else { // 반시계
                        for (int k = 0; k < m - 1; k++) {
                            temp = cir[a -1][k];
                            cir[a - 1][k] = cir[a - 1][k + 1];
                            cir[a - 1][k + 1= temp;
                        }
                    }
                }
        }
        find(); 
    }
 
    static void find() {
        // 탐색
        int sum = 0// 원판의 총합
        boolean chk = false// true이면 인접한 수 중 같은 수가 있을 때  / false면 같은 수가 없을 때 
        int cnt = 0// chk가 false일때 써먹을거 0이 아닌 수가 몇개 인지 찾음 
 
        int[][] tcir = new int[n][m];// temp map
        for (int i = 0; i < n; i++) {
            Arrays.fill(tcir[i], -1);
        }
 
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                
                if(cir[i][j] != 0) {
                    cnt++;
                }
                
                sum += cir[i][j]; // 현재 위치 0 이면 패스
                for (int k = 0; k < 4; k++) {
                    int ni = i + di[k];
                    int nj = j + dj[k];
                    if (ni < 0)
                        continue;
                    if (ni >= n)
                        continue;
                    if (nj < 0) { // 1번 정점과 마지막 정점을 비교 해줌
                        if (cir[ni][m - 1== cir[ni][0
                                && (cir[ni][m - 1!= 0 && cir[ni][0!= 0)) {// 한번도 변한적 없는 것만 바꿔 주자
                            tcir[ni][m - 1= 0;
                            tcir[ni][0= 0;
                            chk = true;
                        }
                    }
                    if (nj >= m) // 위에 마지막 정점은 1번 정점과 비교해줬음
                        continue;
 
                    //위에서 예외는 다 처리해줬으니 그냥 찾아 보자
                    if (ni >= 0 && nj >= 0 && ni < n && nj < m 
                            && (cir[i][j] != 0 && cir[ni][nj] != 0)) {// 한번도 변한적 없는 것만 바꿔 주자
                        if (cir[i][j] == cir[ni][nj]) {
                            tcir[i][j] = 0;
                            tcir[ni][nj] = 0;
                            chk = true;
                        }
                    }
                }
            }
        }
        // 인접한 정점에 같은것이 하나도 없었을때 
        if (!chk) {
            float avg = (float)sum / cnt;
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    if ((float)cir[i][j] > avg && cir[i][j] != 0) {
                        cir[i][j] -= 1;
                    } else if ((float)cir[i][j] < avg && cir[i][j] != 0) {
                        cir[i][j] += 1;
                    }else if((float)cir[i][j] == avg && cir[i][j] != 0){
                        continue;
                    }
                }
            }
            // 인접한 정점에 같은것이 있었을 때 
        } else {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    if (tcir[i][j] == 0) {
                        cir[i][j] = tcir[i][j];
                    }
                }
            }
        }
    }
}
cs

 

728x90

+ Recent posts