'데이터분석' 카테고리의 다른 글
Kaggler's Day #9 (0) | 2017.01.12 |
---|---|
Kaggler's Day #8 (0) | 2016.06.10 |
Kaggler's Day #7 (0) | 2016.06.08 |
Kaggler's Day #6 (0) | 2016.05.31 |
Kaggler's Day #5 (0) | 2016.05.27 |
Kaggler's Day #9 (0) | 2017.01.12 |
---|---|
Kaggler's Day #8 (0) | 2016.06.10 |
Kaggler's Day #7 (0) | 2016.06.08 |
Kaggler's Day #6 (0) | 2016.05.31 |
Kaggler's Day #5 (0) | 2016.05.27 |
오후 금일 4시간짜리 IBM Bluemix 선수과정을 들여댜보았습니다.
Bluemix가 Barematal에서부터 Container, VM, CloudFoundry, OpenWhisk까지 다 지원을 하는데
CF에 어플리케이션 등록/배포하는걸 실제 해보며 BlueMix 라는 큰 플랫폼을 살짝 들여다보았습니다.
우선 로컬의 Node JS어플리케이션(DB포함)을 CLI와 Ecilpse Plugin을 통해 등록/배포하는 과정이 아주 심플하네요,
또한 DB툴 또한 제공하여 플랫폼에서 데이터 수정이 가능하네요. 미국 남부, 호주 시드니, 영국에 주요 거점으로
128군데의 데이터센터가 있다네요. 그리고 130개의 구성가능한 서비스가 매력적입니다.
Watson API부터 TWC(The weather company)데이터까지 가져다 쓸수 있으며 데이터 분석 서비스또한 NoSQL, SQL DB
물론 ElasticSearch지원하구요 또한 IoT나 DevOps등에 대한 환경 관리도 가능합니다. 이 모든걸 서비스라 총칭하여 구분합니다.
데브옵스쪽을 업무유관이니 교육가서 5주간 더 깊게 들여다보겠습니다.
개인적으로 스타트업정도는 아니지만 간단한 서비스를 만들려고 하는데 OpenWhisk라는걸 사용하면 꽤 합리적인 요금으로
클라우드 사용도 가능할 것 같습니다. AWS의 Labmda와 같이 미들웨어 없이 클라우드에 앱 등록하면 이를 통해 비지니스 처리를
해주는 서비스인데 사용한만큼만 요금을 낼수 있는 기똥찬 서비스네요. 상당히 맘에 듭니다 오픈소스화가 되어 있고 한번 뜯어봐도
좋을거 같네요. 정말 말그대로 SaaS도 Application/Data영역만 신경쓰는게 아니라 더 나뉘어져서 비지니스로직만 신경써주게 하는
그런게 트랜드인가보네요. 한번씩 만들어봐도 좋을것같습니다.
그리고 선수과정은 아래들어가서 ID만들고 가입하고 들으시면 됩니다. 빠르게 보면 할거 다하면서 3시간 이내로 봅니다.
그리고 Bluemix도 1 Month Free Trial을 제공하니 써봐도 좋구요.
참, IBM에 Open Badge가 있는데 MOOC의 Verified Certificate처럼 나중에 유용할 수료증도 준다고 합니다.
○ 사전 교육 (필수 학습)
아래 Link로 들어가시면, IBM Bluemix Essential 이라는 온라인 교육을 진행할 수 있습니다.
https://developer.ibm.com/courses/all-courses/bluemix-essentials/
Excel fuction
. DCOUNT
. INDEX
. RANDBETWEEN
VBA
Excel : 4_DECISION_TREE_CASE_STUDY_마케팅엔지니어코리아_이정훈.xlsm
First of all, Let's suppose that we have some information and whether they buy computer or not about customers so that we want to extract good factor to predict for customer to buy computer like the following. Like the decision tree, we want to make many rules that also get a percentage of people who bought the computer. .
In this case, we can make 4 variables to save a value from RANDBETWEEN(). First two variables, the value's range would be between 1 and 4 and will point out the index of the column to be used. (the two values above the table below). Next two variables's range would between 1 and 14 and point out a index of rows number to be used as a condition's value. (the two values under the table below)Then we can use DCOUNT function to count up rows that has 1 value in the last column where it was converted bit value that means whether or not a customer boiught a computer.
we almost to finish a preparation to generate the rule. The last step is to make VBA macro that clear the region where it displays and copy the rule increasing row number. The vba logic is like the followings.
Sub RULE_GENERATOR()
Range("O2").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.ClearContents
Range("O2").Select
For K = 1 To 1000
Range("O2").Offset(K - 1, 0) = K
Range("O2").Offset(K - 1, 1) = Range("M3")
Next K
End Sub
It's done!
※ 멀티캠퍼스에서 진행되는 이정훈의 데이터분석과정 자료임을 밝힙니다.
특정 주제 목록 캡쳐그림/목록 가져오기 (Python) (0) | 2016.08.11 |
---|
늦게 연재하는 9번째 Kaggler's Day입니다.
이번 차수에서는 직접 Kaggle Competition에 올라온걸 EDA에서 그치는게 아니라 직접 예측 모델까지 돌려서 예측까지 해보는걸 해볼려고 합니다. 우선 오늘은 데이터셋 탐색까지 진행토록 하곘습니다.
주제는 부동산 가격 예측(여기)입니다.
아이오와주의 에이메스(Ames)라는 도시의 부동산 가격 에측을 할려고 합니다. 80여개의 다양한 주택 관련 피쳐를 제공하고 이를 가지고 부동산 가격을 예측하는게 목표인데요, 한국 부동산 시장하고는 미국 부동산 시장은 참 많이 다른것 같습니다. 왜냐하면 한국하면 지하철 역세권 여부와 거리, 좋은 학군에 속하는 학교와 거리 등등이 중요하다고 보면 여기 피쳐들은 몇 개는 일부 유관해보이지만 대부분의 피쳐가 집의 상태들이 중요합니다.
데이터를 한번 살펴보겠습니다.
LotFrontAge
Street 의 경우 두가지 타입중에서 자갈일 경우는 싸고, pave는 다양하게 걸쳐져 있다
Alley(골목)도 마찬가지로 Pave가 Gravel보다 높은 가격을 대체적으로 형성
Lotshape의 경우은 IR 시리즈보다 가격이 Reg로 된 집이 좀 낮다
LandContour도 마찬가지로 가격이 타입별로 다르게 형성
Utilities는 AllPubs가 가격범위가 크고 NoSeWa는 거의 1.5? 고정
NeighborHood는 확실히 동네가 어디인지에 따라 가격대가 다르게 형성
YearBuilt 확실히 오래된 아파트는 비싼게 없군
HouseStyle 1층과 2층짜리 집이 가격이 높게 형성
OverallQual 당연히 품질이 좋을수록 집이 비쌈
OverallCond 5인 경우에는 가격 범위가 전체에 걸쳐 있다는게 이상 나머지는 정상대로 비례관계
YearRemoteAdd 리모델링 날짜를 말하는 것으로써, 당연히 최근일수록 비싸나 생각보다 그리 비례비가 높지 않고 또 아래 박스권에 대부분 몰려 있음
RoofStyle: Type of roof , 그닥 차이가 없음 Hip이 그나마 가격이 좀 높은 정도? 차이가 그리 없음.
Flat Flat
Gable Gable
Gambrel Gabrel (Barn)
Hip Hip
Mansard Mansard
Shed Shed
RoofMatl: Roof material, Wood Shingles이 가격이 쌔고, Gravel & Tar / Wood Shakes 이 그다음 가격대 그리고 Membrane, Metal, Roll의 경우는 집 가격대가 아주 좁게 형성되어있는점이 특이!!
ClyTile Clay or Tile
CompShg Standard (Composite) Shingle
Membran Membrane
Metal Metal
Roll Roll
Tar&Grv Gravel & Tar
WdShake Wood Shakes
WdShngl Wood Shingles
Exterior1st: Exterior covering on house , 집 외부 마감재가 뭐에 따라 다르다. PreCast, Vinyl Siding 같은 경우는 비싼편
AsbShng Asbestos Shingles
AsphShn Asphalt Shingles
BrkComm Brick Common
BrkFace Brick Face
CBlock Cinder Block
CemntBd Cement Board
HdBoard Hard Board
ImStucc Imitation Stucco
MetalSd Metal Siding
Other Other
Plywood Plywood
PreCast PreCast
Stone Stone
Stucco Stucco
VinylSd Vinyl Siding
Wd Sdng Wood Siding
WdShing Wood Shingles
Exterior2nd: Exterior covering on house (if more than one material) 가격이 위와 비슷
AsbShng Asbestos Shingles
AsphShn Asphalt Shingles
BrkComm Brick Common
BrkFace Brick Face
CBlock Cinder Block
CemntBd Cement Board
HdBoard Hard Board
ImStucc Imitation Stucco
MetalSd Metal Siding
Other Other
Plywood Plywood
PreCast PreCast
Stone Stone
Stucco Stucco
VinylSd Vinyl Siding
Wd Sdng Wood Siding
WdShing Wood Shingles
MasVnrType: Masonry veneer type Stone > Brick Face > Brick Common, None
BrkCmn Brick Common
BrkFace Brick Face
CBlock Cinder Block
None None
Stone Stone
MasVnrArea: Masonry veneer area in square feet 관계성이 생각보다 너무 없다.ㄷ
ExterQual: Evaluates the quality of the material on the exterior, Excellent가 최고
Ex Excellent
Gd Good
TA Average/Typical
Fa Fair
Po Poor
ExterCond: Evaluates the present condition of the material on the exterior, Excellent > Average/Typical 순으로 높다
Ex Excellent
Gd Good
TA Average/Typical
Fa Fair
Po Poor
Foundation: Type of foundation , Poured Contrete, Stone, Wood가 높다
BrkTil Brick & Tile
CBlock Cinder Block
PConc Poured Contrete
Slab Slab
Stone Stone
Wood Wood
BsmtQual: Evaluates the height of the basement 높이가 높을수록 퀄리티가 높은가 봄.
Ex Excellent (100+ inches)
Gd Good (90-99 inches)
TA Typical (80-89 inches)
Fa Fair (70-79 inches)
Po Poor (<70 inches
NA No Basement
BsmtCond: Evaluates the general condition of the basement , Excellent가 빠져있고 마찬가지!
Ex Excellent
Gd Good
TA Typical - slight dampness allowed
Fa Fair - dampness or some cracking or settling
Po Poor - Severe cracking, settling, or wetness
NA No Basement
BsmtExposure: Refers to walkout or garden level walls , walkout은 외부로 연결된 집안의 통로를 말하는 것으로, 이것도 집 가격이 가겨갣가 별도로 형성된다ㅣ
Gd Good Exposure
Av Average Exposure (split levels or foyers typically score average or above)
Mn Mimimum Exposure
No No Exposure
NA No Basement
BsmtFinType1: Rating of basement finished area 이것도 마찬가지로 지하실 상태를 나타내는 거 같음.
GLQ Good Living Quarters
ALQ Average Living Quarters
BLQ Below Average Living Quarters
Rec Average Rec Room
LwQ Low Quality
Unf Unfinshed
NA No Basement
BsmtFinSF1: Type 1 finished square feet, 비례관계
BsmtFinType2: Rating of basement finished area (if multiple types), 그닥 관계성이 없다능.
GLQ Good Living Quarters
ALQ Average Living Quarters
BLQ Below Average Living Quarters
Rec Average Rec Room
LwQ Low Quality
Unf Unfinshed
NA No Basement
BsmtFinSF2: Type 2 finished square feet, 이것도 마찬가지 그리 관계가 없다.
BsmtUnfSF: Unfinished square feet of basement area, 관계 없다.
TotalBsmtSF: Total square feet of basement area, 비례관계
Heating: Type of heating, 이거는 가스가 높은 집값을 보증해준다는거 GasA, GasW가 둘다 상위권
Floor Floor Furnace
GasA Gas forced warm air furnace
GasW Gas hot water or steam heat
Grav Gravity furnace
OthW Hot water or steam heat other than gas
Wall Wall furnace
HeatingQC: Heating quality and condition, 이것 또한 상태가 좋은게 집값 결정이 영향을 미침.
Ex Excellent
Gd Good
TA Average/Typical
Fa Fair
Po Poor
CentralAir: Central air conditioning 중앙냉방이 있으면 가격이 쎄다
N No
Y Yes
Electrical: Electrical system SBrkr > FuseA > FuseF > FuseP > Mix
SBrkr Standard Circuit Breakers & Romex
FuseA Fuse Box over 60 AMP and all Romex wiring (Average)
FuseF 60 AMP Fuse Box and mostly Romex wiring (Fair)
FuseP 60 AMP Fuse Box and mostly knob & tube wiring (poor)
Mix Mixed
1stFlrSF: First Floor square feet , 비례관계
2ndFlrSF: Second floor square feet 2층이 없는거 제외하고 비례관계
LowQualFinSF: Low quality finished square feet (all floors) , 영향 없음
GrLivArea: Above grade (ground) living area square feet 비례관계
BsmtFullBath: Basement full bathrooms, 개수가 증가할수록 가격 범위 시작가격이 조금 올라가나 영향은 없다고 볼 수 있음
BsmtHalfBath: Basement half bathrooms, 개수가 증가할수록 가격 범위 시작가격이 조금 올라가나 영향은 없다고 볼 수 있음
FullBath: Full bathrooms above grade, 개수가 증가할수록 가격 범위 시작가격이 조금 올라가나 영향은 없다고 볼 수 있음
HalfBath: Half baths above grade, 개수가 증가할수록 가격 범위 시작가격이 조금 올라가나 영향은 없다고 볼 수 있음
Bedroom: Bedrooms above grade (does NOT include basement bedrooms) ??
Kitchen: Kitchens above grade ??
KitchenQual: Kitchen quality, 마찬가지 비례
Ex Excellent
Gd Good
TA Typical/Average
Fa Fair
Po Poor
TotRmsAbvGrd: Total rooms above grade (does not include bathrooms) 살짝 비례관계???!
Functional: Home functionality (Assume typical unless deductions are warranted)
Typ Typical Functionality
Min1 Minor Deductions 1
Min2 Minor Deductions 2
Mod Moderate Deductions
Maj1 Major Deductions 1
Maj2 Major Deductions 2
Sev Severely Damaged
Sal Salvage only
Fireplaces: Number of fireplaces
FireplaceQu: Fireplace quality, 이것도 비례관계
Ex Excellent - Exceptional Masonry Fireplace
Gd Good - Masonry Fireplace in main level
TA Average - Prefabricated Fireplace in main living area or Masonry Fireplace in basement
Fa Fair - Prefabricated Fireplace in basement
Po Poor - Ben Franklin Stove
NA No Fireplace
GarageType: Garage location, BuiltIn, Attchd 가 비싸다.
2Types More than one type of garage
Attchd Attached to home
Basment Basement Garage
BuiltIn Built-In (Garage part of house - typically has room above garage)
CarPort Car Port
Detchd Detached from home
NA No Garage
GarageYrBlt: Year garage was built , 창고가 지어진 년도도 최근게 당연히 비쌈
GarageFinish: Interior finish of the garage, 비례관계 Fin > RFn > Unf
Fin Finished
RFn Rough Finished
Unf Unfinished
NA No Garage
GarageCars: Size of garage in car capacity, 이것도 비례관계가 구성이 될 듯. 차대수가 많을수록 가격 범위가 점점 올라간다.
GarageArea: Size of garage in square feet, 800 square feet까지는 맞으나 그뒤로는 비례관계가 깨진다.
GarageQual: Garage quality, 가격에 영향이 없다. Ex = Gd가 같다.
Ex Excellent
Gd Good
TA Typical/Average
Fa Fair
Po Poor
NA No Garage
GarageCond: Garage condition, 유의하지 않다. 오히려 Excellent가 Good보다 집 가격이 못하다.
Ex Excellent
Gd Good
TA Typical/Average
Fa Fair
Po Poor
NA No Garage
PavedDrive: Paved driveway 포장일수록 가격이 높다. Y > P > N
Y Paved
P Partial Pavement
N Dirt/Gravel
WoodDeckSF: Wood deck area in square feet , 약간 비례관계, 400 square feet이후는 데이터가 별로 없다.
OpenPorchSF: Open porch area in square feet , 200 square feet 이후에는 데이터가 별로 없다.
EnclosedPorch: Enclosed porch area in square feet, 유의하지 않다.
3SsnPorch: Three season porch area in square feet, 데이터가 별로 없다.
ScreenPorch: Screen porch area in square feet, 데이터가 별로 없어 유의한지 판단하기 어렵다.
PoolArea: Pool area in square feet 데이터가 너무 없어 유의한지 판단하기 어렵다.
PoolQC: Pool quality, Excellent같은 경우 확실히 가격대가 높고 Gd가 오히려 Fa보다 가격이 낮아 유의할지 의문
Ex Excellent
Gd Good
TA Average/Typical
Fa Fair
NA No Pool
Fence: Fence quality, Good Privacy는 높으나 나머지가 비교하기 어려울듯, GdPrv와 나머지로 분류해서 categorical factor로 만들지 고민
GdPrv Good Privacy
MnPrv Minimum Privacy
GdWo Good Wood
MnWw Minimum Wood/Wire
NA No Fence
MiscFeature: Miscellaneous feature not covered in other categories, Tennis Court가 있음 비쌈 , 창고가 하나 더있어도 비쌈.
Elev Elevator
Gar2 2nd Garage (if not described in garage section)
Othr Other
Shed Shed (over 100 SF)
TenC Tennis Court
NA None
MiscVal: $Value of miscellaneous feature, 데이터도 별로 없음, 유의하지 않음
MoSold: Month Sold (MM) 3,4,7이 더 높은 판매가격을 자랑함.
YrSold: Year Sold (YYYY) 유의하지 않으며 매년 비슷한 모습
SaleType: Type of sale, New와 Con이 시세가 비싸 보이며, 나머지는 비슷
WD Warranty Deed - Conventional
CWD Warranty Deed - Cash
VWD Warranty Deed - VA Loan
New Home just constructed and sold
COD Court Officer Deed/Estate
Con Contract 15% Down payment regular terms
ConLw Contract Low Down payment and low interest
ConLI Contract Low Interest
ConLD Contract Low Down
Oth Other
SaleCondition: Condition of sale, Partical이 가격대가 높아 보인다.
Normal Normal Sale
Abnorml Abnormal Sale - trade, foreclosure, short sale
AdjLand Adjoining Land Purchase
Alloca Allocation - two linked properties with separate deeds, typically condo with a garage unit
Family Sale between family members
Partial Home was not completed when last assessed (associated with New Homes)
킥오프용 문서입니다 (0) | 2017.04.24 |
---|---|
Kaggler's Day #8 (0) | 2016.06.10 |
Kaggler's Day #7 (0) | 2016.06.08 |
Kaggler's Day #6 (0) | 2016.05.31 |
Kaggler's Day #5 (0) | 2016.05.27 |
파이선 컨을 앞두고 파이선 재미난 코드 snippet 을 보다가 하나 따라해봄. (출처)
주피터에 있는걸 복붙. 사전에 webkit2png 설치가 필요하며 그리고 실행하는 경로에 images라는 폴더 생성을 해야한다.
import requests # http
import bs4 # beautiful soup
import re # reqular expression
import subprocess # capture screen
import json #json util
import os # os util 사용하기 위
# Requests
BASE_URL_SDS = "http://search.daum.net/search?nil_suggest=btn&w=news&DA=SBC&cluster=y&q=%EC%82%BC%EC%84%B1sds"
data = requests.get(BASE_URL_SDS)
# row개수 확인
data = bs4.BeautifulSoup(data.text)
# 아래는 reqular expression을 이용하여 totalCount를 가져오는 예제
match = re.search("totalCount: [0-9]+", data.text)
# total Count를 가져오는 부분이며 두번째 인덱스에 숫자가들어있것지
total_count = int(match.group(0).split("totalCount: ")[1])
# 총 페이지 개수 (페이지당 10개)
pages = total_count / 10 + 1
article_data = [] #아티클 보관할 배열 생성
# 오호라 이 문법은 정말 신기하구먼 자바랑 좀 다른건가 for in 하고 비슷하긴한데 range라는게 있구먼..
for page in range(1, pages+1):
TARGET_URL = BASE_URL_SDS + "&p=" + str(page)
data = requests.get(TARGET_URL)
data = bs4.BeautifulSoup(data.text)
articles = data.findAll("div", attrs={'class': 'cont_inner'})
for article in articles:
title_and_link = article.findAll("a")[0]
title = title_and_link.text.encode('utf-8')
link = title_and_link["href"]
date_and_media = str(article.findAll("span", attrs={'class': 'date'})[0])
date = date_and_media.split("\n")[1]
media = date_and_media.split("\n")[2].split("</span> ")[1]
article_data.append(
{
"title": title,
"link": link,
"date": date,
"media": media,
}
)
# 아래를 실행하기 위해서는 http://www.paulhammond.org/webkit2png/ 에서 우선 webkit2png가 필요!!
# ScreenShot
subprocess.call([
"webkit2png",
"-F", # only create fullsize screenshot
"--filename=temporary",
"--dir=" + os.path.join(os.getcwd(), "images"),
link
])
# Rename Screenshot
# webkit2png --filename=FILENAME 옵션을 사용하면 한글깨짐 문제 발생
for filename in os.listdir("./images/"):
if filename.startswith("temporary"):
os.rename(
os.path.join(os.getcwd(), "images", filename),
os.path.join(os.getcwd(), "images",
"Screenshot_" + date + "_" + media + "_" + title.replace(" ", "_") + ".png")
)
# Result as JSON
# 단, ensure_ascii 옵션으로 UTF-8 ( 한글로 보이도록 ) 출력한다.
with open('result.json', 'w') as outfile:
json.dump(article_data, outfile, ensure_ascii=False)
주식 회복 탄력성 지수 구하는 모듈 ver 1.0 (0) | 2017.03.09 |
---|
7일차에 올린 내용에 이어서 올릴려고 하니 Tistory에서 에러를 뱉어서 별도로 빼서 올립니다. ㅜ.ㅜ
Update
네 업데이트입니다. 마저 끝내겠습니다.
경쟁업체가 오픈하면 어떤일이 벌어질까요? 이 효과를 평과하기 위해 우리는 가게중 처음 CompetitorDistance 의 값이 NA로 되어 있다가 후에 의미있는값으로 채워지는 것을 가져옵니다.
특정 날짜가 아닌 경쟁업체의 개업 달만 알려져있다고 합니다. 그래서 우리는 효과를 보기 위해 꽤 큰 window 하다고 합니다.(100일)
위에 볼드체로 원문에도 적혀있는데 무슨말인지 함 보죠. 147개의 가게가 이용가능한 기간동안 그들의 영역에 옮겨왔다고 합니다. 이 경쟁은 기간을 어떻게 잡느냐에 따라 달라지는 판매량에서 움픅 들어간 모습을 보여준답니다. 그래서 우리는 아래 plot에 기초한 통계에 대해서 aruge를 하지 말자고 합니다. 여튼 보는것은 유익하니까요.
# Sales before and after competition opens
train_store$DateYearmon <- as.yearmon(train_store$Date) # 소스가 길어 주석을 달자면 월로 truncate
train_store <- train_store[order(Date)] # R을 보면서 항상 이런게 대박인것 같습니다. vectorize연산이 이리 쉽게 되죠. Date순으로 order줍니다.
timespan <- 100 # Days to collect before and after Opening of competition
그리고 바로 함수를 만듭니다. 실제로 이 함수를 만들어서 list에 verctorize연산을 할려고 합니다. 인자로 받은 가게와 일치하는 가게들만 뽑아서 아까 truncate한 DateYerMon하고 경쟁업체 개업월을 비교하죠 그게 daysWithComp에 담기고 TTTT가다가 FFFF 로 되겠죠. 그리고 그 사이에 경쟁업체 개장월이 경계에 있을테고. 그럼 여기에서 FFF가 있어야만 해당 가게가 운영하다가 경쟁업체가 없다가 생긴걸로 판단이 되겠죠? 당근??! 그래서 any()를 써서 있다면 comOpening(경쟁업체 오픈되는 시점의 인덱스)를 구하고 그리고 timespan즉 100일이 전후로 있다고 하면 그 부분만 잘라서 리턴을 하는거죠 comOpening 시점으로 앞뒤 100일치의 데이터를 말이죠!! 그래서 코드는 다음과 같네요.
beforeAndAfterComp <- function(s) {
x <- train_store[Store == s]
daysWithComp <- x$CompetitionOpenSince >= x$DateYearmon
if (any(!daysWithComp)) {
compOpening <- head(which(!daysWithComp), 1) - 1
if (compOpening > timespan & compOpening < (nrow(x) - timespan)) {
x <- x[(compOpening - timespan):(compOpening + timespan), ]
x$Day <- 1:nrow(x)
return(x)
}
}
}
자 이제 r 함수를 만들었죠. 전에도 언급했으나 모르겠으나 여튼 여기 함수를 만든건 처음인듯 . 뭐 자바스크립트랑 별반 다르지 않네요. 벡터연산이 있다는 거 말고는
그리고 뭘해야할까요? 네 이 함수를 전체 데이터에 적용해서 가게별로 뽑아서 list를 만들어볼까합니다. 바로 unique()를 써서 store를 unique하게 뽑고 바로 우리가 위에 만든 함수를 돌려서 temp라는걸 만듭니다요. 그리고 이걸 row로 붙여줍니다. 뭐시냐.. do.call은 앞의 인자가함수고 그다음 인자가 함수에 들어갈 파라메터라고 보시면 됩니다. temp가 storeId별 list로 되어있는걸 하나의 list로 만들어주고 그 row가 147개 정도의 데이터가 되는걸 볼수 있습니다.
temp <- lapply(unique(train_store[!is.na(CompetitionOpenSince)]$Store), beforeAndAfterComp)
temp <- do.call(rbind, temp)
# 147 stores first had no competition but at least 100 days before the end
# of the data set
length(unique(temp$Store))
## [1] 147
자 한번 만든걸 뿌려보죠!
ggplot(temp[Sales != 0], aes(x = Day, y = Sales)) +
geom_smooth() +
ggtitle(paste("Competition opening around day", timespan))
## geom_smooth: method="auto" and size of largest group is >=1000, so using gam with formula: y ~ s(x, bs = "cs"). Use 'method = x' to change the smoothing method.
확실히 전후로 매출에 변화가 급감하였다가 다시 회복하는 기조를 보이네요..
그리고 마지막입니다. 드디어.. 후화 vote를 제일 많이 받은 녀석이기도 해서 그런지 길이도 어마어마하네요. 제가 본 exploratory analysis 중에 가장 length가 깁니다...
여튼 끝낼게요. 다른 plot을 가져옵니다. Seaonal plot(spsrini)이라고 합 대신에 missing value나 closed store 대신하여 더 값을 잘표현할수 있는 평균값으로 보여주는 plot이라고 합니다.
판매량 평균값으로 계절 추이를 볼수 있는거 같습니다.
temp <- train
temp$year <- format(temp$Date, "%Y")
temp$month <- format(temp$Date, "%m")
temp[, StoreMean := mean(Sales), by = Store]
temp <- temp[, .(MonthlySalesMean = mean(Sales / (StoreMean)) * 100),
by = .(year, month)]
temp <- as.data.frame(temp)
SalesTS <- ts(temp$MonthlySalesMean, start=2013, frequency=12)
col = rainbow(3)
seasonplot(SalesTS, col=col, year.labels.left = TRUE, pch=19, las=1)
결론
우선 몇차례 올리진 않았지만 본 script중에 가장 잘 정리가 된 kaggle script인것 같습니다. 저도 인사이트도 얻고 지금 계획 중인 아이디어 하나에 실제 접목도 하고 싶은 생각이 드네요. 그럼 토요일이나 일요일쯤.. 뭐 Google calendar의 setting된 goal이 알려주는데로 또 글을 올리겠지만 여튼 수고하세요!!
킥오프용 문서입니다 (0) | 2017.04.24 |
---|---|
Kaggler's Day #9 (0) | 2017.01.12 |
Kaggler's Day #7 (0) | 2016.06.08 |
Kaggler's Day #6 (0) | 2016.05.31 |
Kaggler's Day #5 (0) | 2016.05.27 |
7일차네요!!!
저번의 Rossman 가게 마케팅 분석 3번째로 이어서 진행을 하는군요 이번 차수에서는 끝을 봐야 또 새로운 스크립트를 맛볼텐데..
저번까지 박스플롯으로 학교 휴일이냐 아니냐에 따라서 Rossman 가게들의 판매 실적을 보았구요.
이번에는 이어서 ggplot으로 Sales & Customers가 0 이 아닌 train 데이터를 가지고 scatter plot을 그려보겠습니다.
ggplot(train[train$Sales != 0 & train$Customers != 0],
aes(x = log(Customers), y = log(Sales))) +
geom_point(alpha = 0.2) + geom_smooth()
## geom_smooth: method="auto" and size of largest group is >=1000, so using gam with formula: y ~ s(x, bs = "cs"). Use 'method = x' to change the smoothing method.
당연한 얘기지만 역시 Customers가 많아야 Sales가 많다는 건 당연한건가보네요. 마치 y=x같은 그래프와 유사한 모습을 보여주네요. 상관분석을 했는데 이렇게 이쁘게 나오면 참 기분이 좋을텐데 여튼 넘어가겟습니다.
이번에는 Promo 행사여부에 따른 판매량 추이를 보죠
ggplot(train[train$Sales != 0 & train$Customers != 0],
aes(x = factor(Promo), y = Sales)) +
geom_jitter(alpha = 0.1) +
geom_boxplot(color = "yellow", outlier.colour = NA, fill = NA)
그릐고 바로 Customers는 얼마나 끌어들이나도 같이 보죠 -> 바로 전 boxplot과 비교를 할 목적인줄 알았는데 한단계 더 나가네요.. 위의 scatter plot 대신에 box plot으로 Cutomers를 카운트해보네요.
ggplot(train[train$Sales != 0 & train$Customers != 0],
aes(x = factor(Promo), y = Customers)) +
geom_jitter(alpha = 0.1) +
geom_boxplot(color = "yellow", outlier.colour = NA, fill = NA)
절대적이진 않지만 학교휴무여부보다 프로모션여부가 확실히 판매량 차이가 더 극명하네요 그리고 한번 더 강조합니다. Sales와 Customers가 0인것은 제외를 함으로써 biased될 가능성이 있기 때문이라고 합니다. 판매량은 고객수와 꽤 연관이 있다고 언급했고.. 그런데 여기에서 Promo가 보면 고객수의 차이가 그닥 없죠잉? 즉 뭐냐면 Promo가 결국 온 손님들이 물건을 더 사게 만드는 효과가 있지 더 끌어들이는 효과는 없다는걸 알수가 있죠. Promo의 factor 변수값이 0인 boxplot과 1의 boxplot은 상당히 overlap되니깐요.. Customers는 그닥 변화가 없지만 Sales은 꽤 차이나는걸 보고 우린 알수가 있어야 합니다. 고객별 소비금액을 봅시다!
with(train[train$Sales != 0 & train$Promo == 0], mean(Sales / Customers))
## [1] 8.941128
with(train[train$Sales != 0 & train$Promo == 1], mean(Sales / Customers))
## [1] 10.17896
이게 유로인데요 한 1유로 이상을 더 지갑에서 여는걸 볼수가 있습니다
여기에서 테이블로 가게 오픈여부와 프로모션 여부에 대한 카운팅 테이블을 봅시다.
table(ifelse(train$Sales != 0, "Sales > 0", "Sales = 0"),
ifelse(train$Promo, "Promo", "No promo"))
##
## No promo Promo
## Sales = 0 161666 11205
## Sales > 0 467463 376875
가게들이 문을 닫았을 때 프로모션기간인 경우가 좀 있네요 그리고 가게 문을 열었을 경우 45프로의 가게가 프로모션 진행중이구요
다음은 웃픈 얘기인데 오픈해서 손님이 있어도 판매가 없는 가게가 54곳이나 뽑히네요.
table(ifelse(train$Open == 1, "Opened", "Closed"),
ifelse(train$Sales > 0, "Sales > 0", "Sales = 0"))
##
## Sales = 0 Sales > 0
## Closed 172817 0
## Opened 54 844338
그 54개를 자세히 보죠....
# That tends to happen on consecutive days. Some stores even had customers
# (who bought nothing?)
train[Open == 1 & Sales == 0]
## Store DayOfWeek Date Sales Customers Open Promo StateHoliday
## 1: 762 4 2013-01-17 0 0 1 0 0
## 2: 232 4 2013-01-24 0 0 1 1 0
## 3: 339 3 2013-01-30 0 0 1 0 0
## 4: 339 4 2013-01-31 0 0 1 0 0
## 5: 259 4 2013-02-07 0 0 1 1 0
## 6: 353 6 2013-03-16 0 0 1 0 0
## 7: 948 4 2013-04-25 0 5 1 1 0
## 8: 589 1 2013-04-29 0 0 1 1 0
## 9: 364 2 2013-05-07 0 0 1 0 0
## 10: 364 3 2013-05-08 0 0 1 0 0
## 11: 681 5 2013-05-10 0 0 1 0 0
## 12: 700 3 2013-06-05 0 0 1 1 0
## 13: 665 5 2013-06-28 0 0 1 0 0
## 14: 665 6 2013-06-29 0 0 1 0 0
## 15: 1039 2 2013-07-09 0 0 1 0 0
## 16: 1039 3 2013-07-10 0 0 1 0 0
## 17: 927 4 2013-08-08 0 0 1 0 0
## 18: 391 3 2013-08-28 0 0 1 1 0
## 19: 663 1 2013-09-02 0 0 1 0 0
## 20: 983 5 2014-01-17 0 0 1 0 0
## 21: 983 6 2014-01-18 0 0 1 0 0
## 22: 623 5 2014-01-24 0 0 1 1 0
## 23: 623 6 2014-01-25 0 0 1 0 0
## 24: 25 3 2014-02-12 0 0 1 0 0
## 25: 25 4 2014-02-13 0 0 1 0 0
## 26: 327 3 2014-03-12 0 0 1 0 0
## 27: 986 2 2014-03-18 0 0 1 1 0
## 28: 850 6 2014-03-29 0 0 1 0 0
## 29: 661 5 2014-04-04 0 0 1 1 0
## 30: 1100 2 2014-04-29 0 3 1 1 0
## 31: 1100 3 2014-04-30 0 0 1 1 0
## 32: 1017 3 2014-06-04 0 0 1 1 0
## 33: 1017 4 2014-06-05 0 0 1 1 0
## 34: 57 2 2014-07-01 0 0 1 1 0
## 35: 925 4 2014-07-03 0 0 1 1 0
## 36: 102 6 2014-07-12 0 0 1 0 0
## 37: 882 3 2014-07-23 0 0 1 0 0
## 38: 887 3 2014-07-23 0 0 1 0 0
## 39: 102 4 2014-07-24 0 0 1 0 0
## 40: 238 4 2014-07-24 0 0 1 0 0
## 41: 303 4 2014-07-24 0 0 1 0 0
## 42: 387 4 2014-07-24 0 0 1 0 0
## 43: 28 2 2014-09-02 0 0 1 1 0
## 44: 28 3 2014-09-03 0 0 1 1 0
## 45: 28 4 2014-09-04 0 0 1 1 0
## 46: 548 5 2014-09-05 0 0 1 1 0
## 47: 835 3 2014-09-10 0 0 1 0 0
## 48: 227 4 2014-09-11 0 0 1 0 0
## 49: 835 4 2014-09-11 0 0 1 0 0
## 50: 357 1 2014-09-22 0 0 1 0 0
## 51: 708 3 2014-10-01 0 0 1 1 0
## 52: 699 4 2015-02-05 0 0 1 1 0
## 53: 674 4 2015-03-26 0 0 1 0 0
## 54: 971 5 2015-05-15 0 0 1 0 0
## Store DayOfWeek Date Sales Customers Open Promo StateHoliday
## SchoolHoliday
## 1: 0
## 2: 0
## 3: 0
## 4: 0
## 5: 0
## 6: 0
## 7: 0
## 8: 0
## 9: 0
## 10: 0
## 11: 0
## 12: 0
## 13: 0
## 14: 0
## 15: 0
## 16: 0
## 17: 1
## 18: 1
## 19: 1
## 20: 0
## 21: 0
## 22: 0
## 23: 0
## 24: 0
## 25: 0
## 26: 0
## 27: 0
## 28: 0
## 29: 0
## 30: 0
## 31: 0
## 32: 0
## 33: 0
## 34: 0
## 35: 0
## 36: 0
## 37: 1
## 38: 0
## 39: 1
## 40: 1
## 41: 1
## 42: 1
## 43: 1
## 44: 1
## 45: 0
## 46: 1
## 47: 0
## 48: 0
## 49: 0
## 50: 0
## 51: 0
## 52: 0
## 53: 0
## 54: 1
## SchoolHoliday
가슴 아프지만 우리는 이 가게들을 캐내서 판매부진 아니.. 판매불능의 상황을 따져봅시다...!! 우선 Store의 리스트를 가져와 sales가 0인것들이 많은 순대로 sort를 했네요. 여기에서 sort는 별로 무의미해보이고요 여튼 zeroPerStore의 가게를
zerosPerStore <- sort(tapply(train$Sales, list(train$Store), function(x) sum(x == 0)))
hist(zerosPerStore,100)
여기에서는 이 구한 zerosPerStore은 sort가 되어 있죠 default가 ascending order라 판매가 0인 날이 가장 많은 가게들 10개를 가져와봅니다. 그리고 그 가게별로 plot을 찍어보네요 Sales에 대한 ploat을 찍고 보니 특정 구간에 판매량이 0으로 몰린다는겁니다. 중간에 뻥 아니면 시작부분에 뻥
# Stores with the most zeros in their sales:
tail(zerosPerStore, 10)
## 105 339 837 25 560 674 972 349 708 103
## 188 188 191 192 195 197 240 242 255 311
# Some stores were closed for some time, some of those were closed multiple times
plot(train[Store == 972, Sales], ylab = "Sales", xlab = "Days", main = "Store 972")
plot(train[Store == 103, Sales], ylab = "Sales", xlab = "Days", main = "Store 103")
plot(train[Store == 708, Sales], ylab = "Sales", xlab = "Days", main = "Store 708")
물론 판매량에 있어 0을 안 찍은 가게들도 있고 일요일/휴무일날 오픈해서 판매한 exceptions들도 있다고 합니다. 특히 일요일은 판매가 잘된다고 하네요..
ggplot(train[Store == 85],
aes(x = Date, y = Sales,
color = factor(DayOfWeek == 7), shape = factor(DayOfWeek == 7))) +
geom_point(size = 3) + ggtitle("Sales of store 85 (True if sunday)")
ggplot(train[Store == 262],
aes(x = Date, y = Sales,
color = factor(DayOfWeek == 7), shape = factor(DayOfWeek == 7))) +
geom_point(size = 3) + ggtitle("Sales of store 262 (True if sunday)")
그리고 주일별로 한번 판매량을 boxplot찍어보니!!! 일요일은 판매량의 변동성이 꽤 높네요 ㄷㄷㄷㄷ
ggplot(train[Sales != 0],
aes(x = factor(DayOfWeek), y = Sales)) +
geom_jitter(alpha = 0.1) +
geom_boxplot(color = "yellow", outlier.colour = NA, fill = NA)
자 이제 train데이터는 그만 잠시 접어두고 주어진 데이터 셋중에 store 즉 가게 자체애 대한 정보를 받았죠. 가게 대장이라고 부를께요.
이데이터를summary()함수를 통해서 살펴보겠습니다.
summary(store)
## Store StoreType Assortment
## Min. : 1.0 Length:1115 Length:1115
## 1st Qu.: 279.5 Class :character Class :character
## Median : 558.0 Mode :character Mode :character
## Mean : 558.0
## 3rd Qu.: 836.5
## Max. :1115.0
##
## CompetitionDistance CompetitionOpenSinceMonth CompetitionOpenSinceYear
## Min. : 20.0 Min. : 1.000 Min. :1900
## 1st Qu.: 717.5 1st Qu.: 4.000 1st Qu.:2006
## Median : 2325.0 Median : 8.000 Median :2010
## Mean : 5404.9 Mean : 7.225 Mean :2009
## 3rd Qu.: 6882.5 3rd Qu.:10.000 3rd Qu.:2013
## Max. :75860.0 Max. :12.000 Max. :2015
## NA's :3 NA's :354 NA's :354
## Promo2 Promo2SinceWeek Promo2SinceYear PromoInterval
## Min. :0.0000 Min. : 1.0 Min. :2009 Length:1115
## 1st Qu.:0.0000 1st Qu.:13.0 1st Qu.:2011 Class :character
## Median :1.0000 Median :22.0 Median :2012 Mode :character
## Mean :0.5121 Mean :23.6 Mean :2012
## 3rd Qu.:1.0000 3rd Qu.:37.0 3rd Qu.:2013
## Max. :1.0000 Max. :50.0 Max. :2015
## NA's :544 NA's :544
1115개의 가게별로 StoreType / Assortment 같은 구분이 있고 경쟁업체 위치 그리고 경쟁업체 오픈 년월과 Promotion 에대한 추가 정보가 있네요. 프로모션2는 뭐지? 흠흠..
table(store$StoreType)
##
## a b c d
## 602 17 148 348
table(store$Assortment)
##
## a b c
## 593 9 513
# There is a connection between store type and type of assortment
table(data.frame(Assortment = store$Assortment, StoreType = store$StoreType))
## StoreType
## Assortment a b c d
## a 381 7 77 128
## b 0 9 0 0
## c 221 1 71 220
이렇게 구분 변수 2개는 살펴보았습니다. 넘어가죠!
hist(store$CompetitionDistance, 100)
경쟁업체거리는 있다면 뭐 가까운데 제일 많이 있다라는거죠 거리가 멀수록 경쟁업체가 있어도 없다고 체크하겠죠 뭐 정보관리할때 말이죠..
뭐 이건 년월을 "-"로 묶어서 CompetitoinOpenSince라는 값에 담았습니다. 그리고 2015년 10월 기준으로 오픈한 년수를 구해서 historgram으로 찍어봤을때 보통 20년 이내의 역사를 가지고 있는 가게가 대부분이네요.
# Convert the CompetitionOpenSince... variables to one Date variable
store$CompetitionOpenSince <- as.yearmon(paste(store$CompetitionOpenSinceYear,
store$CompetitionOpenSinceMonth, sep = "-"))
# One competitor opened 1900
hist(as.yearmon("2015-10") - store$CompetitionOpenSince, 100,
main = "Years since opening of nearest competition")
그다음은 promo2가 시작된 이후의 날수를 계산하네요... 이건 머여 날수를 구해서 머하자는건지....넘어가거씁니다. 아마 제가 데이터셋 설명을 다시 봐서 업데이트하든가 해야겠네요.
Convert the Promo2Since... variables to one Date variable
# Assume that the promo starts on the first day of the week
store$Promo2Since <- as.POSIXct(paste(store$Promo2SinceYear,
store$Promo2SinceWeek, 1, sep = "-"),
format = "%Y-%U-%u")
hist(as.numeric(as.POSIXct("2015-10-01", format = "%Y-%m-%d") - store$Promo2Since),
100, main = "Days since start of promo2")
프로모션 주기구요.
table(store$PromoInterval)
##
## Feb,May,Aug,Nov Jan,Apr,Jul,Oct Mar,Jun,Sept,Dec
## 544 130 335 106
이건 프로모션 주기별로 boxplot을 그렸는데 글쎄요 뭐 둘쑥날쑥하네요 프로모션기별마다.
# Merge store and train
train_store <- merge(train, store, by = "Store")
ggplot(train_store[Sales != 0], aes(x = factor(PromoInterval), y = Sales)) +
geom_jitter(alpha = 0.1) +
geom_boxplot(color = "yellow", outlier.colour = NA, fill = NA)
그다음으로 store type과 assortment types을 시각분석을 통해 한번 뭔지 보자.
그래프가 마치 지렁이같이 그려지는건 geom_smooth 때문이고 여튼 factor를 storeType과 assortment type을 넣고 돌려봤더니 뭔가 차이가 확실히 있네요.
ggplot(train_store[Sales != 0],
aes(x = as.Date(Date), y = Sales, color = factor(StoreType))) +
geom_smooth(size = 2)
## geom_smooth: method="auto" and size of largest group is >=1000, so using gam with formula: y ~ s(x, bs = "cs"). Use 'method = x' to change the smoothing method.
ggplot(train_store[Customers != 0],
aes(x = as.Date(Date), y = Customers, color = factor(StoreType))) +
geom_smooth(size = 2)
## geom_smooth: method="auto" and size of largest group is >=1000, so using gam with formula: y ~ s(x, bs = "cs"). Use 'method = x' to change the smoothing method.
ggplot(train_store[Sales != 0],
aes(x = as.Date(Date), y = Sales, color = factor(Assortment))) +
geom_smooth(size = 2)
## geom_smooth: method="auto" and size of largest group is >=1000, so using gam with formula: y ~ s(x, bs = "cs"). Use 'method = x' to change the smoothing method.
ggplot(train_store[Sales != 0],
aes(x = as.Date(Date), y = Customers, color = factor(Assortment))) +
geom_smooth(size = 2)
## geom_smooth: method="auto" and size of largest group is >=1000, so using gam with formula: y ~ s(x, bs = "cs"). Use 'method = x' to change the smoothing method.
storetype과 assortment type을 보면 b가 우세하네요. 고객수면이나 판매량측면에서 말이죠!!
그리고 경쟁업체와의 거리는 좀 보면 직관적이지 못합니다. 여기에서 이러네요. 아마 자기 추측에는 다음 경쟁업체와의 거리가 가까운 가게의 경우는 일반적으로 도심안과 같은 이미 붐비는 지역이라 그럴거라고. 그러니 경쟁업체가 몰려있겠죠... 그래서 good bad를 가리기엔 그냥 뭐.cancel out 즉 상쇄된다는 말인듯합니다.
salesByDist <- aggregate(train_store[Sales != 0 & !is.na(CompetitionDistance)]$Sales,
by = list(train_store[Sales != 0 & !is.na(CompetitionDistance)]$CompetitionDistance), mean)
colnames(salesByDist) <- c("CompetitionDistance", "MeanSales")
ggplot(salesByDist, aes(x = log(CompetitionDistance), y = log(MeanSales))) +
geom_point() + geom_smooth()
## geom_smooth: method="auto" and size of largest group is <1000, so using loess. Use 'method = x' to change the smoothing method.
CompetitionOpenSinceYear값이 없을 경우때문인지 걍 CompetitionOpenSinceYear의 값 존재여부를 가지고 체크한거같습니다. 보시죠.
ggplot(train_store[Sales != 0],
aes(x = factor(!is.na(CompetitionOpenSinceYear)), y = Sales)) +
geom_jitter(alpha = 0.1) +
geom_boxplot(color = "yellow", outlier.colour = NA, fill = NA) +
ggtitle("Any competition?")
별차이가 없어보이는데 우선 뭐.. Sales가 있는경우가 더 높네요. 방금 말한 그런 이유의 연장선인거같습니다.
이 다음은 아주 쪼금남았는데 시간 나면 바로 업데이트하는걸로하고. 마칩니다.
캐글도 뭔가 완전하진 않습니다. 결국 데이터 모델을 만들어내느걸 해야하는데 그런건 안다뤄지고 Exploratory Analysis 단계까지만 공개되는거 같네요. 금주와 다음달부터 빅데이터/통계스터디를 하게 되는데 심화해서 진행되는건 업데이트해서 공유를 하도록 하겠슴니다. 그럼 조만간 업데이트할게요~~
Kaggler's Day #9 (0) | 2017.01.12 |
---|---|
Kaggler's Day #8 (0) | 2016.06.10 |
Kaggler's Day #6 (0) | 2016.05.31 |
Kaggler's Day #5 (0) | 2016.05.27 |
Kaggler's Day #3 (0) | 2016.05.16 |
Google Calendar에 추가한 Goal Alarm이 오질 않네요 여튼 그래서 수동으로 다시 시작합니다. 5일차때 다룬 Rossmann Store Sales 풀이 이어서 나가도록 하겠습니다. 저번에 제공 데이터를 str. summary 등의 함수를 가지고 한번 훑어보았데 train데이터만 보여줬는데 마저 test 데이터도 조회해보죠
summary(test)
## Id Store DayOfWeek Date
## Min. : 1 Min. : 1.0 Min. :1.000 Min. :2015-08-01
## 1st Qu.:10273 1st Qu.: 279.8 1st Qu.:2.000 1st Qu.:2015-08-12
## Median :20544 Median : 553.5 Median :4.000 Median :2015-08-24
## Mean :20544 Mean : 555.9 Mean :3.979 Mean :2015-08-24
## 3rd Qu.:30816 3rd Qu.: 832.2 3rd Qu.:6.000 3rd Qu.:2015-09-05
## Max. :41088 Max. :1115.0 Max. :7.000 Max. :2015-09-17
##
## Open Promo StateHoliday SchoolHoliday
## Min. :0.0000 Min. :0.0000 Length:41088 Length:41088
## 1st Qu.:1.0000 1st Qu.:0.0000 Class :character Class :character
## Median :1.0000 Median :0.0000 Mode :character Mode :character
## Mean :0.8543 Mean :0.3958
## 3rd Qu.:1.0000 3rd Qu.:1.0000
## Max. :1.0000 Max. :1.0000
## NA's :11
test[is.na(test$Open), ] # Only store 622
## Id Store DayOfWeek Date Open Promo StateHoliday SchoolHoliday
## 1: 10752 622 6 2015-09-05 NA 0 0 0
## 2: 9040 622 1 2015-09-07 NA 0 0 0
## 3: 8184 622 2 2015-09-08 NA 0 0 0
## 4: 7328 622 3 2015-09-09 NA 0 0 0
## 5: 6472 622 4 2015-09-10 NA 0 0 0
## 6: 5616 622 5 2015-09-11 NA 0 0 0
## 7: 4760 622 6 2015-09-12 NA 0 0 0
## 8: 3048 622 1 2015-09-14 NA 1 0 0
## 9: 2192 622 2 2015-09-15 NA 1 0 0
## 10: 1336 622 3 2015-09-16 NA 1 0 0
## 11: 480 622 4 2015-09-17 NA 1 0 0
test$Open[test$Store == 622]
## [1] 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0
## [24] 1 1 1 1 1 1 0 1 1 1 1 1 NA 0 NA NA NA NA NA NA 0 NA NA
## [47] NA NA
여기에서 보면 위에 제가 볼드체로 표시한 부분 즉 실제 rows수를 보면 train데이터가 월등히 많네요. 1017209rows에 비해 test데이터는 턱없이 부족하고 그리고 dashboard에 issue로 올라온 것보면 622개의 데이터가 Open 컬럼이 NA로 되어있어 못쓴다라고 올라와있는데요. 하지만 이 row를 못쓰는건 아닙니다. 여기를 보면 아시다시피 Sale라는 컬럼이 닫혀있다면 0일수가 없으니 1로 간주하면 될거 같습니다. 이런걸 data munging이라고도 하는데 저희가 도메인을 파악하고 어떤 이유에서인지 알수 없거나 정리가 안된걸 직접 수정하여 trim처리를 하는 센스는 있어야 합니다. 게다가 테스트 데이터에는 Customers컬럼이 아예 빠져있는걸 알수 있습니다. 사후 데이터이기 때문이라네요 ?
여튼 그래서 아래와 같은 처리 합니다. NA인 녀석들을 싹다!!!! 1로 만들어버립시다
test[is.na(test)] <- 1
위의 문법은 test의 컬럼중 NA를 다 1로 채우는걸로 이해하면 됩니다
그다음에 다시
test[is.na(test$Open), ]
# Unique values per column
train[, lapply(.SD, function(x) length(unique(x)))]
## Store DayOfWeek Date Sales Customers Open Promo StateHoliday
## 1: 1115 7 942 21734 4086 2 2 4
## SchoolHoliday
## 1: 2
test[, lapply(.SD, function(x) length(unique(x)))]
## Id Store DayOfWeek Date Open Promo StateHoliday SchoolHoliday
## 1: 41088 856 7 48 2 2 2 2
# All test stores are also in the train data
sum(unique(test$Store) %in% unique(train$Store))
## [1] 856
# 259 train stores are not in the test data
sum(!(unique(train$Store) %in% unique(test$Store)))
## [1] 259
table(train$Open) / nrow(train) # Percent Open Train
##
## 0 1
## 0.1698933 0.8301067
table(test$Open) / nrow(test) # Percent Open Test
##
## 0 1
## 0.1456386 0.8543614
table(train$Promo) / nrow(train) # Percent of the time promo in train
##
## 0 1
## 0.6184855 0.3815145
table(test$Promo) / nrow(test) # Percent of the time promo in test
##
## 0 1
## 0.6041667 0.3958333
table(train$StateHoliday) / nrow(train) # Percent of the time holiday in train
##
## 0 a b c
## 0.969475300 0.019917244 0.006576820 0.004030637
table(test$StateHoliday) / nrow(test) # no b and c = no easter holiday and no christmas
##
## 0 a
## 0.995619159 0.004380841
table(train$SchoolHoliday) / nrow(train) # Percent of the time school holiday in train
##
## 0 1
## 0.8213533 0.1786467
table(test$SchoolHoliday) / nrow(test) # Percent of the time school holiday in test
##
## 0 1
## 0.5565129 0.4434871
plot(train$Date, type = "l")
plot(test$Date, type = "l")
# As expected all 856 stores to be predicted daily
all(table(test$Date) == 856)
## [1] TRUE
hist(train$Sales, 100)
hist(aggregate(train[Sales != 0]$Sales,
by = list(train[Sales != 0]$Store), mean)$x, 100,
main = "Mean sales per store when store was not closed")
hist(train$Customers, 100)
hist(aggregate(train[Sales != 0]$Customers,
by = list(train[Sales != 0]$Store), mean)$x, 100,
main = "Mean customers per store when store was not closed")
가게 넘버가 500~1000으로 부여된것이 실적이 좋네요 ㅎㅎ
그리고 ggplot으로 이제 뿌릴건데요 boxplot도 안에 껴서 그릴수가있습니다.
학교 휴일이냐 아니냐에 따라서 판매량을 한번 볼게요
ggplot(train[Sales != 0], aes(x = factor(SchoolHoliday), y = Sales)) +
geom_jitter(alpha = 0.1) +
geom_boxplot(color = "yellow", outlier.colour = NA, fill = NA)
box plot으로는 차이가 별로 없고 판매량은 휴일이 아닌경우 가 확실히 더 많네요. 까만영역이 더 높죠?!
후배님께서 술먹자고 가자고 하네요. 후아. 오늘도 여기까지. 아직 반도 안왔네요. 이거 !! 그래도 다음 차에는 확 끝내겠습니다!
Kaggler's Day #8 (0) | 2016.06.10 |
---|---|
Kaggler's Day #7 (0) | 2016.06.08 |
Kaggler's Day #5 (0) | 2016.05.27 |
Kaggler's Day #3 (0) | 2016.05.16 |
Kaggler's Day #1 (0) | 2016.05.12 |
벌써 5번째 Kaggler Day이군요 쨌든 오늘은 가장 kaggle script중에 가장 많은 관심을 받은 script 하나를 들고 왔습니다. 물론 이문제 또한 kaggle competition이 이루어진 문제구요.
문제 설명을 하자면,, 가게, 프로모션, 그리고 경쟁자 정보를 가지고 판매량을 예측하는 겁니다. Rossman이라는 브랜드가 있나봅니다 여튼 여기서 아마 competition 문제를 의뢰한거 같구요. 이 회사가 머하는 곳이냐면 7개의 유럽 국가에 3000개의 약국을 운영하고 있는 회사입니다. 현재 Rossmann 가게 매니저들은 미리 6주되기까지 그들의 daily 판매량을 예상하는 일을 받았다고 합니다. 가게 판매는 많은 인자 즉 프로모션, 경쟁 업체, 학교, 그리고 주의 휴일, 계절, 지역특성에 등등 많은 인자에 의해 영향을 받고 수천명의 개별 매니저들과 그들의 특정 환경을 토대로 판매량을 예측하는함에 있어 결과의 정확성은 꽤 변동이 클것이라고 합니다.
그래서!! 캐글에서 Rossman은 독일에 있는 1,115개의 약국의 6개월간의 판매량을 예측하는걸 목표로 한다고 하네요? 신뢰할만한 판매 예측은 가게 매니저에게 생산성과 동기부여를 증가시킬수 있는 효율적인 직원 스케쥴을 만들수 있게 해준다고 하네요. Rossmann이 견고한 예측 모델을 만들도록 도와주면서 우리는 그들에게 고객과 그들의 팀에게 무엇이 가장 중요한지 알려주고자 합니다.
자 문제 설명은 마쳤구요.. 여기 가보면 데이터셋을 확보할수 있습니다.
데이터셋을 보니
손님 수, 가게 오픈여부, 주휴일, 학교휴일, 가게타입. assortment(무슨 factor중의 하나겠죠?) 그리고 경쟁업체와의 거리, 그리고 가장가까운 경쟁업체의 오픈 년월일. 프로모션, 프로모션2, 프로모션 주기가 주어져있습니다..
과연 이걸로 얻을수 있을까... 궁금하시죠? 그럼 award를 흠 그러니까 1등한분거는 공개가 안되는거 같으니.. 35k달러의 후보가 될뻔 한 소스를 한번 살펴볼까요.....!!!!
탐색전 분석(Exploratory Analysis)을 해보죠!!
사용한 라이브러리 들이 나오고요 data.table을 사용하여 속도를 높였다고 합니다. 특정 해석을 가능케 하기 위해 unmasked data가 중요하다합니다.
library(data.table)
library(zoo)
##
## Attaching package: 'zoo'
##
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
library(forecast)
## Loading required package: timeDate
## Loading required package: methods
## This is forecast 6.2
저번에는 ggplot을 보았는데 이번엔 ggplot2가 나왔습니다. 그리고 문제에서 주어지는 데이터가 이번엔 아예 test / train 으로 나뉘어져 있군요. 그리고 별도로 store라는 데이터셋이 있어서 가게 대장 정보가 별도로 잇네요.
library(ggplot2)
test <- fread("../input/test.csv")
train <- fread("../input/train.csv")
store <- fread("../input/store.csv")
아래는 입력받은 데이터셋을 간략하게 보기 좋은 함수죠~~
str(train)
## Classes 'data.table' and 'data.frame': 1017209 obs. of 9 variables:
## $ Store : int 1 2 3 4 5 6 7 8 9 10 ...
## $ DayOfWeek : int 5 5 5 5 5 5 5 5 5 5 ...
## $ Date : chr "2015-07-31" "2015-07-31" "2015-07-31" "2015-07-31" ...
## $ Sales : int 5263 6064 8314 13995 4822 5651 15344 8492 8565 7185 ...
## $ Customers : int 555 625 821 1498 559 589 1414 833 687 681 ...
## $ Open : int 1 1 1 1 1 1 1 1 1 1 ...
## $ Promo : int 1 1 1 1 1 1 1 1 1 1 ...
## $ StateHoliday : chr "0" "0" "0" "0" ...
## $ SchoolHoliday: chr "1" "1" "1" "1" ...
## - attr(*, ".internal.selfref")=<externalptr>
str(test)
## Classes 'data.table' and 'data.frame': 41088 obs. of 8 variables:
## $ Id : int 1 2 3 4 5 6 7 8 9 10 ...
## $ Store : int 1 3 7 8 9 10 11 12 13 14 ...
## $ DayOfWeek : int 4 4 4 4 4 4 4 4 4 4 ...
## $ Date : chr "2015-09-17" "2015-09-17" "2015-09-17" "2015-09-17" ...
## $ Open : int 1 1 1 1 1 1 1 1 1 1 ...
## $ Promo : int 1 1 1 1 1 1 1 1 1 1 ...
## $ StateHoliday : chr "0" "0" "0" "0" ...
## $ SchoolHoliday: chr "0" "0" "0" "0" ...
## - attr(*, ".internal.selfref")=<externalptr>
str(store)
## Classes 'data.table' and 'data.frame': 1115 obs. of 10 variables:
## $ Store : int 1 2 3 4 5 6 7 8 9 10 ...
## $ StoreType : chr "c" "a" "a" "c" ...
## $ Assortment : chr "a" "a" "a" "c" ...
## $ CompetitionDistance : int 1270 570 14130 620 29910 310 24000 7520 2030 3160 ...
## $ CompetitionOpenSinceMonth: int 9 11 12 9 4 12 4 10 8 9 ...
## $ CompetitionOpenSinceYear : int 2008 2007 2006 2009 2015 2013 2013 2014 2000 2009 ...
## $ Promo2 : int 0 1 1 0 0 0 0 0 0 0 ...
## $ Promo2SinceWeek : int NA 13 14 NA NA NA NA NA NA NA ...
## $ Promo2SinceYear : int NA 2010 2011 NA NA NA NA NA NA NA ...
## $ PromoInterval : chr "" "Jan,Apr,Jul,Oct" "Jan,Apr,Jul,Oct" "" ...
## - attr(*, ".internal.selfref")=<externalptr>
# head(train); tail(train)
# head(test); tail(test)
train[, Date := as.Date(Date)]
test[, Date := as.Date(Date)]
store
## Store StoreType Assortment CompetitionDistance
## 1: 1 c a 1270
## 2: 2 a a 570
## 3: 3 a a 14130
## 4: 4 c c 620
## 5: 5 a a 29910
## ---
## 1111: 1111 a a 1900
## 1112: 1112 c c 1880
## 1113: 1113 a c 9260
## 1114: 1114 a c 870
## 1115: 1115 d c 5350
## CompetitionOpenSinceMonth CompetitionOpenSinceYear Promo2
## 1: 9 2008 0
## 2: 11 2007 1
## 3: 12 2006 1
## 4: 9 2009 0
## 5: 4 2015 0
## ---
## 1111: 6 2014 1
## 1112: 4 2006 0
## 1113: NA NA 0
## 1114: NA NA 0
## 1115: NA NA 1
## Promo2SinceWeek Promo2SinceYear PromoInterval
## 1: NA NA
## 2: 13 2010 Jan,Apr,Jul,Oct
## 3: 14 2011 Jan,Apr,Jul,Oct
## 4: NA NA
## 5: NA NA
## ---
## 1111: 31 2013 Jan,Apr,Jul,Oct
## 1112: NA NA
## 1113: NA NA
## 1114: NA NA
## 1115: 22 2012 Mar,Jun,Sept,Dec
train <- train[order(Date)]
test <- test[order(Date)]
summary(train)
## Store DayOfWeek Date Sales
## Min. : 1.0 Min. :1.000 Min. :2013-01-01 Min. : 0
## 1st Qu.: 280.0 1st Qu.:2.000 1st Qu.:2013-08-17 1st Qu.: 3727
## Median : 558.0 Median :4.000 Median :2014-04-02 Median : 5744
## Mean : 558.4 Mean :3.998 Mean :2014-04-11 Mean : 5774
## 3rd Qu.: 838.0 3rd Qu.:6.000 3rd Qu.:2014-12-12 3rd Qu.: 7856
## Max. :1115.0 Max. :7.000 Max. :2015-07-31 Max. :41551
## Customers Open Promo StateHoliday
## Min. : 0.0 Min. :0.0000 Min. :0.0000 Length:1017209
## 1st Qu.: 405.0 1st Qu.:1.0000 1st Qu.:0.0000 Class :character
## Median : 609.0 Median :1.0000 Median :0.0000 Mode :character
## Mean : 633.1 Mean :0.8301 Mean :0.3815
## 3rd Qu.: 837.0 3rd Qu.:1.0000 3rd Qu.:1.0000
## Max. :7388.0 Max. :1.0000 Max. :1.0000
## SchoolHoliday
## Length:1017209
## Class :character
## Mode :character
##
##
##
summary(test)
## Id Store DayOfWeek Date
## Min. : 1 Min. : 1.0 Min. :1.000 Min. :2015-08-01
## 1st Qu.:10273 1st Qu.: 279.8 1st Qu.:2.000 1st Qu.:2015-08-12
## Median :20544 Median : 553.5 Median :4.000 Median :2015-08-24
## Mean :20544 Mean : 555.9 Mean :3.979 Mean :2015-08-24
## 3rd Qu.:30816 3rd Qu.: 832.2 3rd Qu.:6.000 3rd Qu.:2015-09-05
## Max. :41088 Max. :1115.0 Max. :7.000 Max. :2015-09-17
##
## Open Promo StateHoliday SchoolHoliday
## Min. :0.0000 Min. :0.0000 Length:41088 Length:41088
## 1st Qu.:1.0000 1st Qu.:0.0000 Class :character Class :character
## Median :1.0000 Median :0.0000 Mode :character Mode :character
## Mean :0.8543 Mean :0.3958
## 3rd Qu.:1.0000 3rd Qu.:1.0000
## Max. :1.0000 Max. :1.0000
## NA's :11
데이터가 흠 가게 Id는 정수형이고 다 주 5일제고 뭐...손님수는 다양하네요 500~1500명까지.... 휴일여부는 0,1로 나뉘어져있고 네..
여튼 데이터 구경은 이정도면 충분하고. 넘어갑니다. 그리고 summary함수를 통해서 또 최대/최소/최빈값등등을 보면서 대략적이나마 data distribution 형태를 좀 예측할 수 가 있지요...
앗!!! 다음에 이어하겠습니다.
좀 더 해야하는데.. 다음 6일차때 추가하겠습니다.
Kaggler's Day #8 (0) | 2016.06.10 |
---|---|
Kaggler's Day #7 (0) | 2016.06.08 |
Kaggler's Day #6 (0) | 2016.05.31 |
Kaggler's Day #3 (0) | 2016.05.16 |
Kaggler's Day #1 (0) | 2016.05.12 |