자전거 수요 예측 데이터에 대한 PCA/FA, Regression

201412047 오신엽

 

1. 분석 방향

다양한 독립변수들과 자전거 수요라는 종속변수를 가진 데이터셋에서 각 변수들에 대해 PCA, FA를 시행한다. 이를 통해 새롭게 추출된 변수들을 새로운 독립 변수로 이용하여 회귀분석을 실시한다. 이 결과와 기존데이터의 회귀분석 결과를 비교한다.

-주제 선정 및 분석 이유

요즈음 공유경제가 많이 활성화되었다. 그 중 가장 큰 인기를 얻고 있는 것이 자동차 공유, 자전거 공유 등이 있다. 얻은 데이터는 데이터 분석 경쟁 사이트인 Kaggle에 올라온 자전거 수요 데이터이다. 이 데이터를 통해 자전거 수요에는 어떤 변수들이 영향을 주는지 알아보고 자전거 공유 서비스 수요 예측에 활용될 것을 기대한다.

 

데이터셋

* datetime - hourly date + timestamp 

* season -  1 = spring, 2 = summer, 3 = fall, 4 = winter

* holiday - whether the day is considered a holiday

* workingday - whether the day is neither a weekend nor holiday

* weather - 1: Clear, Few clouds, Partly cloudy, Partly cloudy

* 2: Mist + Cloudy, Mist + Broken clouds, Mist + Few clouds, Mist

* 3: Light Snow, Light Rain + Thunderstorm + Scattered clouds, Light Rain + Scattered clouds

* 4: Heavy Rain + Ice Pallets + Thunderstorm + Mist, Snow + Fog

* temp - temperature in Celsius

* atemp - "feels like" temperature in Celsius

* humidity - relative humidity

* windspeed - wind speed

* casual - number of non-registered user rentals initiated

* registered - number of registered user rentals initiated

* count - number of total rentals

2. 데이터 전처리 및 데이터 정규화

독립변수와 종속변수를 다른 데이터프레임으로 분리시켰다. 이는 독립변수의 scailing을 진행하기 위함이다.

범주형 변수들에 대해 더미변수를 활용하여 전처리 하는 과정이다.

 전처리 후 총 16개의 변수가 만들어졌다.

 

모든 샘플 데이터에 대해 데이터 scailing을 진행하였다.

다시 종속변수값을 합성해줌으로써 전처리 과정이 모두 끝났다.

 

 

 

 

 

 

 

 

 

 

 

 

 

3. 고유값과 고유벡터

­­

Features 라는 변수에 전처리한 train_std의 트랜스폼한 결과를 저장한다. Numpy 라이브러리에서 제공해주는 cov method를 통해 covariance matrix를 출력한다. 16x16covariance matrix가 출력된다.

­

 

마찬가지로 numpy 라이브러리를 이용해 고유값과 고유벡터를 출력한다. 16개의 변수, 16차원의 데이터셋이므로 16개의 고유값과 고유벡터가 추출된다. 고유벡터중 1이상의 값을 가지는(, 1개 이상의 설명력을 가지는) 8개의 주성분을 얻을 수 있다.

8개의 주성분은 전체데이터의 88%를 설명한다. , 16차원의 데이터가 8차원의 데이터로 줄었음을 알 수 있다. 다시 말하면 기존 변수들을 주성분 1~8로 차원을 축소할 것이고, 이를 새로운 독립변수로 사용할 것이다.

 

4. PCA 라이브러리를 통한 확인

첫번째 코드에서 한 줄의 간단한 코드로 주성분 분석이 모두 이루어지는 것을 볼 수 있다. 만들어진 PCA모델과 기존 데이터셋을 내적하여 새로운 데이터셋을 만들어 냈다. 이후 회귀분석을 위해 종속변수 컬럼을 다시 추가 시켰다.

 

 

 

 

 

 

 

 

 

5. Factor Anaalysis

범주형 변수 제거

범주형 변수는 요인분석에 적합하지 않으므로 이를 제거한다.

 

바틀렛 검정과 KMO 검정을 통해 요인분석이 적합한지 확인

바틀렛 검정에서 P-value가 충분히 작고 KMO 값이 0.5이상이면 요인분석 하기에 적합하다. 본 데이터는 P-value0이고 KMO0.48인데, 기준치보다 약간 작지만, 무시하고 요인분석을 계속 진행한다.

 

 

FactorAnalyzer 라이브러리를 통해 요인분석을 실행한다. 처음엔 회전없이 요인분석을 진행했고, 두번째로는 직교회전인 varimax회전을 통해 진행했다. 진행한 결과 4개의 독립변수에 대해 2개의 요인이 추출된 것을 알 수 있다.

 

 

 요인1에는 온도와 체감온도의 많은 요인적재가 이루어졌다. 이는 외부 온도 라는 요인으로 차원 축소를 할 수 있음을 나타낸다. 요인2에는 습도와 풍속이 반대 방향으로 많은 적재가 이루어졌다. 습도가 낮을 수록, 풍속이 높을 수록 많은 수요가 있음을 나타낸다.

 

기존 데이터셋에 요인분석 결과를 내적하여 새로운 데이터셋을 만들어 준다. 이 데이터셋에 y값을 다시 합성해주고 이후 회귀분석을 실시한다..

 

 

 

 

6. 회귀분석

-정규화 하지 않은 데이터셋의 회귀분석 결과

R-square 값이 0.210으로, 이 회귀식은 무의미한 회귀식이란 것을 알 수 있다. 변수별 P-value값을 보면 season_sp, season_su, weather변수 전부, workingday_not 들이 p-value값이 매우 높으므로 변수에서 탈락시켜도 무방할 것으로 보인다.

-정규화만 진행한 데이터셋의 회귀분석 결과

마찬가지로 R-square값이 매우 낮으므로 적합한 선형모델은 아니다. PCAFA를 진해한 후 설명력에 변화가 있는지 확인하기 위해 결과를 보존한다.

-PCA를 진행한 데이터셋의 회귀분석 결과

PCA를 통해 얻은 새로운 톡립변수들로 회귀식을 만든 결과, 그 설명력은 더 떨어진 것을 알 수 있다. 주성분 5를 제외하면 모든 P-value값이 0이므로 변수로 사용해도 무방하고, 주성분5의 경우 p-value가 매우 높게 나왔으므로 변수에서 제외해도 무방하다. 또한 각 변수의 계수의 표준오차(std err)를 보면 주성분1이 가장 작고 뒤로 갈수록 커지는 것을 알 수 있다. 계수의 표준오차가 작을 수록 추정치의 정확도가 올라간다. 이는 PC1이 분산이 가장 큰 주축이라는 점을 다시 한번 증명해준다.

 

-요인분석을 진행한 데이터셋의 회귀분석 결과

PCA 회귀분석 보다 R-square값이 조금 더 내려갔다. 각 요인들의 p-value값은 모두 0으로 유의미한 변수들이라 할 수 있다.

결론

16차원의 데이터를 차원 축소를 하지 않은 경우와 2가지 방법으로 차원 축소를 하여 회귀분석을 진행한 결과, 후자의 경우가 설명력이 더 떨어진 것을 확인했다.

차원 축소가 이루어지기 전에 기존 데이터로 회귀분석을 실시해도 설명력이 21%밖에 안되기 때문에 주어진 데이터의 독립변수들은 자전거 수요 예측을 하는데 관련성이 없는 것으로 나타난다. 이에 대한 이유를 추측해보면, 맨 처음에 datetime 변수를 제거했다. 이 변수는 상식적으로는 수요에 많은 영향을 미칠 것이라 예상했지만, 전처리 과정이 너무 복잡할 것 같아 제거하고 분석을 진행했다. 이를 미루어보아 datetime 변수 자체와 이 변수와 다른 변수들간의 상관관계가 상당히 존재했음을 짐작할 수 있다.

데이터 자체의 설명력은 아주 낮아 무의미한 회귀식이 도출되었지만, 차원 축소 자체에 대해서는 과정의 의미가 있었다. 차원 축소는 고차원의 데이터를 해석하기 수월한 저차원으로 축소하여 시각화 하는데 편리함을 제공하는 방법이다. 다만, 모든 경우에 차원 축소가 유의미한것은 아니라는 결과가 나왔다. 이는 기존 정교하지 않은 데이터 전처리, 충분하지 않은 독립변수 등 많은 이유로 인해 발생할 수 있다. 그렇지만 주성분분석과 요인분석을 통해 내재적 의미를 도출해내고, 이를 통해 난해한 특성들 제거하고 더 좋은 특징들을 추출해내는 과정은 유의미하다고 생각한다. 데이터의 사회과학적, 개념적 의미를 도출해내는 점은 미흡했지만, 앞서 말한 차원 축소 과정을 통해 각 분석의 의미와 절차, 수학적 원리 등을 많이 공부한 분석 프로젝트였다.

3321 : 최고의 피자

numT = int(input()) #토핑수
costD, costT = map(int, input().split()) #도우가격, 토핑가격
calorieD = int(input()) #도우 칼로리
calorieT = [] #토핑 칼로리 리스트
for i in range(numT):
  calorieT.append(input())  #토핑 칼로리 
calD_1 = calorieD / costD

calAll = 0
for i in calorieT:
  calAll = calAll + int(i)
costAll = costD + numT * costT

calT_1 = []
for i in range(numT):
  calT_1.append(int(calorieT[i]) / costT )
calT_1.sort(reverse=True)

sumCal = calorieD
cnt = 0
for i in calT_1:
  if sumCal / (costD + cnt * costT) > i:
    continue
  elif sumCal / (costD + cnt * costT)  < i:
    sumCal = sumCal + i * costT
    cnt += 1

res = sumCal / (costD + cnt * costT)
print(int(res))
  

------------------------------------------------------------

numT = int(input()) #토핑수
costD, costT = map(int, input().split()) #도우가격, 토핑가격
calorieD = int(input()) #도우 칼로리
calorieT = [] #토핑 칼로리 리스트
for i in range(numT):
  calorieT.append(input())  #토핑 칼로리 
calD_1 = calorieD / costD


calT_1 = []
for i in range(numT):
  calT_1.append(int(calorieT[i]) / costT )
calT_1.sort(reverse=True)

sumCal = calorieD
cnt = 0
for i in calT_1:
  if sumCal / (costD + cnt * costT) > i:
    continue
  elif sumCal / (costD + cnt * costT)  < i:
    sumCal = sumCal + i * costT
    cnt += 1

res = sumCal / (costD + cnt * costT)
print(int(res))
  

------------------------------------------------------------



numT = int(input()) #토핑수
costD, costT = map(int, input().split()) #도우가격, 토핑가격
calorieD = int(input()) #도우 칼로리
calorieT = [] #토핑 칼로리 리스트
for i in range(numT):
  calorieT.append(input())  #토핑 칼로리 
calD_1 = calorieD / costD


calT_1 = []
for i in range(numT):
  calT_1.append(int(calorieT[i]) / costT )
calT_1.sort(reverse=True)

sumCal = calorieD
cnt = 0
for i in calT_1:
  if sumCal / (costD + cnt * costT) > i:
    continue
  elif sumCal / (costD + cnt * costT)  < i:
    sumCal = sumCal + i * costT
    cnt += 1

res = sumCal / (costD + cnt * costT)
print(int(res))
  

3301 : 거스름돈

n = int(input())
c1 = c2= c3 = c4 = c5 = c6 = c7 = c8 = 0
while n >= 50000:
    c1 = c1 + 1
    n = n - 50000
while n >= 10000:
    c2 = c2 + 1
    n = n - 10000  
while n >= 5000:
    c3 = c3 + 1
    n = n - 5000
while n >= 1000:
    c4 = c4 + 1
    n = n - 1000
while n >= 500:
    c5 = c5 + 1
    n = n - 500
while n >= 100:
    c6 = c6 + 1
    n = n - 100
while n >= 50:
    c7 = c7 + 1
    n = n - 50
while n >= 10:
    c8 = c8 + 1
    n = n - 10
print(c1+c2+c3+c4+c5+c6+c7+c8)
        

3120 : 리모컨 

a,b = map(int,input().split())
sum = 0
target11 = abs(a-b)
while target11 != 0:
  if target11 >= 8:
    target11 = abs(target11 - 10)
    sum = sum+1
  elif target11 <8 and target11 >=3:
    target11 = abs(target11 - 5)
    sum = sum+1
  elif target11 <3 and target11 >=1:
    target11 = abs(target11 - 1)
    sum = sum+1
print(sum)

(codeup) 2001 : 최소 대금

pasta1 = int(input())
pasta2 = int(input())
pasta3 = int(input())
juice1 = int(input())
juice2 = int(input())

costPasta=min(pasta1, pasta2, pasta3)
costJui = min(juice1, juice2)
result = (costPasta+costJui)*1.1
print ("%.1f"%result)

1912 : (재귀함수) 팩토리얼 계산

n = int(input())
def factorial(n,res):
  if n == 1:
    print(res)
  else:
    res = res * n
    factorial(n-1,res)
    
  
res=1
factorial(n,res)

+ Recent posts