본문 바로가기

R programming

공유자전거 데이터 분석(2)

반응형

그동안 ADsP공부한다고, 또 중간기말 공부한다고 R에서 손을 놨었다. 물론 변명이겠지만 ㅠㅠ


아무튼 그 전에 했었던 공유자전거 데이터 분석을 좀 더 진행해봤다. 추가되는데 실질적으로 소모한 시간은 5시간(?)정도 인 것 같다.

어제 카페가서 3시간+엊그제와 오늘 야금야금?해서 순수하게 코드입력하는데 쓴 시간은 5~6시간으로 보인다.

비루한 전체 코드는 github에 추가해놓았다. 꺠짝깨작 주석을 달아놨으니 다른 사람에게도 도움이 되길 바란다.


https://github.com/SangdoDong/my-R-code


1
2
3
4
5
library(ggplot2)
library(lubridate) #날짜 및 시간핸들링 패키지
library(dplyr)
library(plotly) 
cs
1
2
str(bike) 
cs

'data.frame': 132427 obs. of 16 variables: $ Trip.ID : int 1912818 1919661 1933383 1944197 1940317 1944075 1944073 1944067 1944062 1944063 ... $ Duration : int 180 1980 300 10860 420 780 600 600 2880 960 ... $ Start.Time : Factor w/ 97997 levels "2016-07-07T04:17:00",..: 1 2 3 4 5 5 6 7 8 8 ... $ End.Time : Factor w/ 90933 levels "2016-07-07T04:20:00",..: 1 2 3 20 4 5 5 7 23 12 ... $ Starting.Station.ID : int 3014 3014 3016 3016 3032 3021 3022 3076 3031 3031 ... $ Starting.Station.Latitude : num 34.1 34.1 34.1 34.1 34 ... $ Starting.Station.Longitude: num -118 -118 -118 -118 -118 ... $ Ending.Station.ID : int 3014 3014 3016 3016 3032 3054 3014 3005 3031 3078 ... $ Ending.Station.Latitude : num 34.1 34.1 34.1 34.1 34 ... $ Ending.Station.Longitude : num -118 -118 -118 -118 -118 ... $ Bike.ID : int 6281 6281 5861 5861 6674 6717 5721 5957 6137 6351 ... $ Plan.Duration : int 30 30 365 365 0 30 30 365 365 30 ... $ Trip.Route.Category : Factor w/ 2 levels "One Way","Round Trip": 2 2 2 2 2 1 1 1 2 1 ... $ Passholder.Type : Factor w/ 4 levels "Flex Pass","Monthly Pass",..: 2 2 1 1 4 2 2 1 1 2 ... $ Starting.Lat.Long : Factor w/ 126 levels "","{'longitude': '-118.231277', 'latitude': '34.034801', 'needs_recoding': False}",..: 19 19 32 32 81 18 6 72 63 63 ... $ Ending.Lat.Long : Factor w/ 128 levels "","{'longitude': '-118.231277', 'latitude': '34.034801', 'needs_recoding': False}",..: 19 19 32 32 81 17 19 96 63 29 ...


bike로 저장한 데이터는 16개의 칼럼과 132,427개의 열로 구성되어있다.





1
table(bike$Passholder.Type)
cs
Flex Pass Monthly Pass Staff Annual Walk-up
9517 81304 382 41224

passholder의 타입은 flex pass, monthly pass, staff Annual, walk-up 으로 총 4개로 구성된다.




각 사용자타입별로 이용시간을 알고 싶었다.


1
2
3
bike$usetime<-ymd_hms(bike$End.Time)-ymd_hms(bike$Start.Time)
bike$usetime<-as.numeric(bike$usetime)
summary(bike$usetime)
cs



종료시간-시작시간 을 계산하여 실제로 이용한 시간이 나왔다.


이미 usetime이 numeric 형식이었는데 확실하게 하고자 다시 한 번 입력했던 것 같다.


Min. 1st Qu. Median Mean 3rd Qu. Max.
1.00 6.00 10.00 28.19 18.00 8188.00



summary를 통해 확인해본 요약치는 값이 이상하다는 것을 확인할 수 있다. 특히 max의 값이 8188으로


자전거를 8188분이나 탔다는 것은 이상치라고 생각했다.


1
 boxplot(bike$usetime)$stats
cs



 
[,1]
[1,] 1

[2,] 6
[3,] 10
[4,] 18
[5,] 36



박스플롯 명령어를 입력하여 일반적이라고 여겨지지 않는 데이터를 제거했다. 명령어는 다음과 같다.

1
2
3
4
5
 
bike$usetime<-ifelse(bike$usetime<=1|bike$usetime>=36,NA, bike$usetime)
table(is.na(bike$usetime))
 
 
cs
 FALSE   TRUE 
118494  13933 
1
bike<- bike %>% filter(!is.na(usetime))
cs


이용시간이 1분이하와 36분 이상 탄 데이터를 날려버렸다


그러니깐 NA값으로 나온 것이 13933개나 되었다. 기존데이터에 10%가 좀 넘는 값이다.


물론 자전거를 더 오래타는 사람이 있을 것이기 때문에 이러한 점을 고려해서 제거했어야한다.



이후 ggplot을 이용해 이용자별 이용시간을 그림으로 나타내었다.


1
2
3
ggplot(data=bike, aes(x=Passholder.Type, y=usetime))+geom_boxplot()+ggtitle("usetime by pass holder")
 
 
cs







사용자별 이용시간을 한 눈에 파악할 수 있다.






1
2
3
hist(bike$usetime, breaks = 30,
     main = "Using time", col = "yellow", xlab="time", ylab = "number")
 
cs




히스토그램을 통해 전체이용자의 사용시간 빈도를 파악할 수 있다.


이후 사용시간에 따른 빈도수를 히스토그램으로 그렸다. 여기까지는 앞 전에 썼던 글과 내용의 차이가 없다.





다음으로 알고 싶었던 내용은 round trip과 one way 에서 어떤 차이가 있는가 였다.



Trip route category를 보면 그 round trip과 one way로 구분되어 있는 것을 확인할 수 있다.



먼저 다음과 같은 명령어로 round trip만을 뽑아보았다.


1
2
3
round_journey<- bike %>%
 filter(Trip.Route.Category=="Round Trip")
 
cs

이후 정의된 데이터로 이용자별 평균 사용시간값을 계산했다.



1
2
3
4
round_journey %>%
  group_by(Passholder.Type) %>%
  summarise(mean=mean(usetime))
 
cs



# A tibble: 4 x 2

Passholder.Type mean

<fct> <dbl>


1 Flex Pass 16.3

2 Monthly Pass 14.1

3 Staff Annual 10.4

4 Walk-up 22.4



이후 위와 같은 데이터가 나오는 것을 확인할 수 있다.







사용자별 공유자전거 사용시간의 통계를 한 눈에 파악하기 위해서 시각화 작업을 했다.


#1.1 round_journey의 passholder type별 사용통계

1
2
ggplot(data=round_journey, aes(x=Passholder.Type, y=usetime))+geom_boxplot()+ggtitle("round_journey")
 
cs










마찬가지 방식으로 oneway 루트도 아래와 같이 oneway루트만을 추출한 후 평균을 계산했다.


#2. onewaytrip 평균이용시간
1
2
3
4
5
6
7
oneway_journey<- bike %>%
filter(Trip.Route.Category=="One Way")
 
oneway_journey %>%
  group_by(Passholder.Type) %>%
  summarise(mean=mean(usetime))
 
cs

# A tibble: 4 x 2

Passholder.Type mean

<fct> <dbl>


1 Flex Pass 16.3

2 Monthly Pass 14.1

3 Staff Annual 10.4

4 Walk-up 22.4






이제 위와 같은 결과가 나온다. 위와 같은 결과를 다음 코드를 통해 그림을 나타내었다.



1
2
3
#2.1 oneway_journey의 passholder type별 사용통계
        ggplot(data=oneway_journey, aes(x=Passholder.Type, y=usetime))+geom_boxplot()+ggtitle("oneway_journey")
        
cs








다음으로 알고 싶던 내용은 어떤 station이 얼마나 많은 자전거가 반납되고 또 빌려지는지 였다.


해당 내용을 알기 위해서는 각 station별로 빌리는 자전거의 수와 또 반납되는 자전거 수를 파악해야한다.


round trip의 경우 동일 station에서 빌려지고 반납되기 때문에 문제가 되지않으나,

one way의 경우 한 station에서 과도하게 많이 반납되거나 혹은 과도하게 많은 자전거 수요가 있다면, 초과공급 혹은


초과수요가 발생한다. 따라서 이를 해결하기위해 자전거 공유업체에서는 과도하게 많은 반납이 이루어지는 station에서


자전거를 회수해서 자전거가 부족한 station을 파악해야한다.





1
2
3
4
#oneway 중에서 starting.station id와 passholder type만을 추출.
          oneway_starting_station_id<- bike %>%
            filter(Trip.Route.Category=="One Way") %>%
            select(Starting.Station.ID,Passholder.Type)
cs


명령어를 통해 one way 에 해당하는 데이터에서 station아이디와 passholder타입을 추출해서


새로운 변수로 지정했다.


이후 지정한 변수를 바탕으로 다음과 같은 방식으로 station id를 카운팅하였다.





1
2
3
4
#추출한 데이터에서 starting station ID 횟수
            oneway_starting_station_count<-oneway_starting_station_id %>%
              group_by(Starting.Station.ID) %>%
              tally()
cs







동일한 방식으로 반납이 이루어진 station id를 카운팅했다.

1
2
3
4
5
6
7
8
#oneway중에서 ending station id와 passholder type만을 추출
              oneway_ending_station_id<- bike %>%
                filter(Trip.Route.Category=="One Way") %>%
                select(Ending.Station.ID, Passholder.Type)
#추출한 데이터에서 ending station id 횟수
                oneway_ending_station_count<-oneway_ending_station_id %>%
                  group_by(Ending.Station.ID) %>%
                  tally()
cs




이후 아래 스크립트와 같이 진행했다.


복사본에 변수명을 비교적 간단하게 바꾸고 불필요한 데이터를 제거하는 작업을 수행했다.


마지막으로 total이라는 변수명으로 데이터를 합쳤다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
        
#데이터 통합을 위한 변수명 일치시키기
#시작스테이션데이터
                starting_count_new<-oneway_starting_station_count #복사본 만들기. 
                
                starting_count_new<-rename(starting_count_new, station = Starting.Station.ID) #변수명 변경
                starting_count_new<-rename(starting_count_new, startcount = n)
#종료스테이션데이터
                  ending_count_new<-oneway_ending_station_count #복사본 만들기
#변수명 변경
                ending_count_new<-rename(ending_count_new, station = Ending.Station.ID)
                  ending_count_new<-rename(ending_count_new, endingcount = n)
#불필요한 데이터 제거
                  starting_count_new<-starting_count_new[-c(65,66),]
                ending_count_new<-ending_count_new[-c(65,66),]
#데이터합치기
                
                total<-left_join(starting_count_new, ending_count_new, by="station")
cs




1
2
3
4
5
6
7
8
9
10
11
total_1<-melt(total, id=(c("station")))
head(total_1)
 
View(total_1)
 
f1<-ggplot(data=total_1, aes(x=station))
f2<-f1+geom_bar(aes(y=startcount), colour="Red", size=1)
f3<-f2+geom_bar(aes(y=endingcount), colour="blue", size=1)
 
head(total_1)
h1<-ggplot(data=total_1, aes(x=station, y=value, fill=variable))+geom_bar(stat="identity", position = "dodge")
cs


위와 같은 코드를 통해 아래와 같은 그림을 그릴 수 있다.
total에 합쳐진 데이터를 melt함수를 통해 재정렬했다.
빨간색으로 표시된 막대그래프는 대여된 자전거 수를, 파란색으로 표시된 막대그래프는 해당 스테이션에 반납된 자전거 수를 나타낸다.



따라서 위 그림을 통해 해당 station에서 대여된 자전거 수, 반납된 자전거 수의 차이를 한 눈에 비교할 수 있다. 

반응형