Edytor zbliżeniowy i opowiadanie historii, czyli ceny aut używanych w segmencie C część 3

Ostatnio, w tym wpisie, przedstawiałem wizualizacje cen aut używanych z segmentu C. Obiecałem też przedstawienie tych wizualizacji w postaci prezentacji. Złożyłem ta obietnicę celowo, by mieć pretekst do przetestowania programu ze strony prezi.com, reklamowanego jako ,,zooming presentation editor”. Dotąd przygotowywałem prezentacje w Beamerze i byłem z nich zadowolony, ale warto testować nowe rozwiązania.

Prezentacje wykonane w programie prezi wyglądają jak seria zbliżeń jednego dużego rysunku, przez co ma się wrażenie ciągłości historii i łatwiej zbudować w głowie mapę prezentacji. Edytor prezi jest dosyć ograniczony (we flashu można zrobić więcej), ale łatwo i intuicyjnie się go używa, wyniki są też dosyć przyjemne dla oka. Oczywiście aby wrażenie ciągłości i spójności pojawiło się w głowie odbiorcy, trzeba poświęcić trochę czasu na projektowanie prezentacji, więcej niż w przypadku zwykłych slajdów.

Prezentację z dodanym głosem umieszczam poniżej (nagrana z ekranu za pomocą programu Camtasia, wersja 30 dniowa). Zależało mi bardziej na zaprezentowaniu efektu zbliżeń niż na budowaniu emocjonującej historii, więc proszę wybaczyć usterki w audio i brak porywającej narracji. W każdym razie moje wrażenia po wykonaniu pierwszej prezentacji z użyciem ,,edytora zbliżeniowego” są bardziej niż pozytywne.

Może by w ten sposób przygotować materiały wideo do kursu ze statystyki?

(Jeżeli poniżej nie otwiera się materiał wideo, to proszę kliknąć na ten link)
 

Jak wyglądają ceny aut używanych w segmencie C, część 2

 

W poprzednim tygodniu (w tym wpisie) pisałem o tym jak modelować można cenę aut używanych, na przykładzie aut z segmentu C.

Dziś pokażę trzy wizualizacje tego zbioru danych, mam nadzieję, że interesujące.

Zobaczymy więc jak zmieniają się ceny aut w zależności od wieku aut, jak wygląda liczba oferowanych aut różnych marek i również jak wygląda wyposażenie aut różnych marek.

Zacznijmy od ceny.

[Rysunek 1. Rozkład cen ofertowych aut używanych w rozbiciu na markę i wiek auta. Czarna kropka odpowiada medianie, pudełka dolnemu i górnemu kwartylowi. Dla zwiększenia czytelności oś OY przedstawiono w skali logarytmicznej. ]

Spójrzmy teraz na dostępność ofert dla różnych marek. Dodatkowo przedstawimy liczbę oferowanych aut w danym roku w podziale na typy nadwozia.

[Rysunek 2. Liczba ofert sprzedaży używanego auta w rozbiciu na typ nadwozia, wiek auta i markę.  Dla niektórych modeli widoczna jest duża podaż +-5-letnich samochodów. Prawdopodobnie kończą się okresy gwarancyjne, auto się amortyzuje i takie auta są sprzedawane przez firmy leasingujące.]

I jeszcze rzut oka na wyposażenie.

[Rysunek 3. Na osi OY przedstawiono procent używanych aut oferowanych do sprzedaży, posiadających określony element wyposażenia. Najwięcej aut serwisowane w ASO stanowią auta mające 4 lata. Ciekawe trendy obserwuje się dla przyciemnianych szyb. Nowsze Astry, C4 i Cee’dy mają je coraz częściej, podczas gdy dla Audi A4 mamy odwrotny trend, przynajmniej  w ostatnich latach. Coraz więcej aut jest wyposażonych w takie elementy jak czujnik parkowania czy ESP (hmm, dziwny jest ten trend z ESP w Ceed’ach)]

 

Btw: wszystkie powyższe wykresy zostały wykonane funkcją xyplot() lub bwplot() w R z użyciem pakietu lattice.

Jak wyglądają ceny aut używanych w segmencie C i problemy modelowania

W poprzedni piątek, w tym wpisie, opisałem trzecią wersję zbioru danych o cenach aut używanych.  W trzech najbliższych wpisach przyjrzymy się bliżej temu zbiorowi danych. Wpisy będą znacznie bardziej technicznie niż poprzednie, ale mam nadzieję że ciekawie dla osób zaczynających przygodę z modelowaniem statystycznym.

Dzisiaj przedstawię kilka umiarkowanie złożonych podejść do modelowania ceny samochodu z użyciem modeli liniowych. Będzie kod w R i trochę narzekań na niezrównoważony zbiór danych. Kolejny wpis przedstawiać będzie przykładowe wizualizacje zbioru danych o cenach aut. A w trzecim wpisie przedstawię krótką prezentację wykonaną z użyciem narzędzia dostępnego online na stronie prezi.com. Narzędzie to jest bezpłatne w wersji średniej dla studentów i nauczycieli akademickich. Ciekawe jestem jak wypadnie prezentacja w nim wykonana, czy lepiej niż w Beamerze?

Pomimo iż większość (żmudnej) pracy związanej z wyborem modelu nie zostanie przedstawiona, i tak będzie dzisiaj bardzo technicznie.

Zaznaczę jeszcze, że modelowana jest cena używanego auta a nie zmiana ceny czy spadek wartości. Modelując cenę mogę dodać efekt wieku auta i mówić, że auta o rok starszy są o x PLN tańsze, ale to są inne auta! W innej wersji i innym wyposażeniem. Efekt wyposażenia można jeszcze usunąć ale efektu związanego z wersja nie. Można porównywać średnią cenę Passata z roku 2006 z ceną Passata z roku 2005. Ale z tego porównania nie można wyciągać wniosków co do utraty wartości tego auta. Są to różne wersje, z różnymi problemami estetyki wersji B5 czy problemów wieku młodzieńczego wersji B6. Modelowanie utraty wartości jest tematem ciekawym i wrócimy do tego gdy będziemy mieli ceny aut zebranych rok wcześniej i rok później.

Wybór podzbioru danych – filtrowanie

Zbiór danych o cenach aut z marca 2012 ma ponad 220 tys wierszy. Kusząca jest możliwość wykorzystania wszystkich tych wierszy do modelowania. Kuszące rzeczy często jednak są złe.

Zgodnie ze złotą zasadą ,,garbage in, garbage out” jeżeli do modelu włożymy śmieciowe dane, otrzymamy śmieciowe wyniki. Ponieważ będziemy wykorzystywać dosyć wrażliwe metody estymacji, w pierwszym kroku wyczyścimy zbiór danych tak by zawierał jak najmniej kłopotliwych zmiennych.

Nawet jeżeli czyszczenie danych jest dosyć żmudne, mało widowiskowe i potrafi zabrać więcej czasu niż cała reszta wizualizacji i modelowania to i tak jest to jeden z ważniejszych kroków. Co z tego, że użyjemy super wyrafinowanej metody estymacji skoro w danych mamy śmieci?

W tym przypadku proces czyszczenia danych polegał na wybraniu aut, które:

  • należą do segmentu C, jest to najpopularniejszy segment aut. Wybierałem z tego segmentu modele dla których znalazłem przynajmniej 100 ofert sprzedaży, co mam nadzieje wystarczy do rozsądnej estymacji. Wybrane modele to: Golf, Astra, A3, C4, Focus, Civic, i30, Cee’d, 308, Octavia.
  • mają mniej niż 12 lat, czyli rok produkcji to przynajmniej rok 2000,
  • ma nadwozie Kombi lub Hatchback, pozostałe wersje nadwozia są znacznie mniej popularne,
  • jest zarejestrowane w Polsce,
  • pochodzi z jednego z krajów: Polska, Wlochy, Czechy, Francja, Holandia, Belgia, Niemcy,
  • rodzaj paliwa to diesel, benzyna lub benzyna+LPG, inne bardziej egzotyczne źródła energii pomijam,
  • pojemność silnika jest z przedziału 1150 – 2200 cm3,
  • skrzynia biegów jest manualna,
  • auto nie jest uszkodzone a cena jest ceną brutto.

Po zastosowaniu tych filtrów pozostaje jedynie 13 419 aut, czyli mniej niż 10%. Wybrana grupa jest jednak bardziej jednorodna, mniej jesteśmy więc narażeni na ,,niespodziewane” problemy związane z brakiem zrównoważenia danych. Np. nie musimy się przejmować artefaktem związanym z tym, że najstarsze golfy mają po kilkadziesiąt lat, a modele i30 są co najwyżej kilkuletnie.

#
# Filtrujemy dane. Pozostawiamy tylko auta pasujące do powyższego opisu.
# W wyniku otrzymujemy trochę ponad 13 tys aut
#
load("cenyAutIII2012.Rdata")
modele <- c("Golf", "Astra", "A3", "C4", "Focus", "Civic", "i30", "Cee'd", "308", "Octavia") 
segmentC <- cenyAutIII2012[(cenyAutIII2012$Model %in% modele) & 
                 (cenyAutIII2012$Nadwozie %in% c("Kombi", "Hatchback")) & 
                 (cenyAutIII2012$Kraj.aktualnej.rejestracji == "Polska" | cenyAutIII2012$Kraj.aktualnej.rejestracji == "") & 
                 (cenyAutIII2012$Kraj.pochodzenia %in% c("Wlochy", "Czechy", "Francja", "Holandia", "Belgia", "Polska", "Niemcy", "")) & 
                 (cenyAutIII2012$Rodzaj.paliwa %in% c("benzyna+LPG", "benzyna", "olej napedowy (diesel)")) &
                 (cenyAutIII2012$Pojemnosc.skokowa > 1150 & cenyAutIII2012$Pojemnosc.skokowa < 2201) &
                 cenyAutIII2012$Rok.produkcji > 2000 & 
                 cenyAutIII2012$Skrzynia.biegow == "manualna" & 
                 cenyAutIII2012$Brutto.netto == "brutto" & (cenyAutIII2012$Liczba.drzwi %in% c("2/3", "4/5")) & cenyAutIII2012$Pojazd.uszkodzony == "",]
segmentC <- segmentC[!is.na(segmentC$Cena),]

Kodowanie zmiennych i wstępne transformacje

Zanim zaczniemy cokolwiek modelować, trzeba zastanowić się jak zakodować zmienne w modelu. Po serii prób wybrałem następujące transformacje przygotowujące dane

  • zamiast roku produkcji analizowany będzie wiek auta, czyli 2012 – rok produkcji. Ułatwi to interpretację ceny efektu wieku auta (porównywałem też wyniki z wiekiem traktowanym jako zmienna jakościowa, ale nie były lepsze, więc wiek pozostał zmienną ilościową)
  • pojemność silnika została zamieniona na zmienną jakościową z poziomami co 100cm3.
  • z adresu auta wyciągnąłem informację o kodzie pocztowym, odpowiednio pierwszej cyfrze kodu pocztowego, dwóch pierwszych cyfrach i wszystkich pięciu cyfrach.
  • z kolumn wyposażenie dodatkowe i informacje dodatkowe wyciągnąłem elementy wyposażenia pojawiające się w przynajmniej 100 ofertach. Dodałem kolumny kodujące binarnie czy auto posiada: niezalezne ogrzewanie, instalacja gazowa, szyberdach, bagażnik na dach, blokada skrzyni biegow, skorzana tapicerka, ksenony, EDS, system nawigacji, hak, podgrzewane fotele, pod. przednia szyba, przyciemniane szyby, czujnik deszczu, czujnik parkowania, tempomat, kierownica wielofunkcyjna, welurowa tapicerka, ASR, garażowany, ESP, alufelgi, autoalarm, lwiatla przeciwmglowe, pierwszy wlasciciel, serwisowany w ASO, bezwypadkowy, komputer, el. lusterka, radio / CD, immobiliser, el. szyby, poduszka powietrzna, klimatyzacja, centralny zamek, ABS, wspomaganie kierownicy.
  • cenę wyrażoną w różnych walutach zamieniłem na cenę w PLN.
  • zmienną do analizy będzie logarytm dwójkowy ceny. Analiza ceny z użyciem modeli gaussowskich nie ma sensu, mając do wyboru transformację ceny albo rozważanie bardziej złożonych klas modeli wybrałem transformację. Z rodziny transformacji Boxa Coxa najlepiej wypadała transformacja y^0.2, ale nie różniła się ona znacząco od logarytmu więc wybrałem logarytm bo łatwiej go interpretować.
#
# Dodajemy do zbioru danych zmienne po transformacji.
#
# Zamieniamy rok produkcji na wiek
segmentC$wiek <- 2012 - segmentC$Rok.produkcji
 
# Zamieniamy ilościową zmienną pojemność na zmienną jakościową
segmentC$pojemnosc <- factor(((segmentC$Pojemnosc.skokowa - 50) %/% 100) * 100 + 50)            
 
# konstruujemy zmienną opisująca lokalizację geograficzną, 
# odpowiadającą pierwszej cyfrze kodu (mniej więcej województwo), 
# dwóm pierwszym cyfrom kodu pocztowego lub wszystkim pięciu cyfrom kodu pocztowego.
segmentC$kodPocztowy5 <- factor(substr(segmentC$Adres, 1,6))
segmentC$kodPocztowy1 <- factor(substr(segmentC$Adres, 1,1))
segmentC$kodPocztowy2 <- factor(substr(segmentC$Adres, 1,2))
 
# usuwamy zbędne puste poziomy
segmentC$Model = factor(segmentC$Model)
segmentC$Nadwozie = factor(segmentC$Nadwozie)
segmentC$Rodzaj.paliwa = factor(segmentC$Rodzaj.paliwa)
 
# Konstruujemy macierz cech dodatkowych, najpierw identyfikujemy listę nazw wyposażenia dodatkowego 
# a następnie budujemy odpowiednią ramkę danych
tmp <- paste(as.character(segmentC$Wyposazenie.dodatkowe),as.character(segmentC$Informacje.dodatkowe), sep=", ")
tmps <- strsplit(tmp, split=", *")
cechy <- names(sort(table(factor(unlist(tmps))))[10:46])
ncechy <- sapply(cechy, function(x) grepl(x, tmp))
 
# Składamy nowe zmienne w ramkę danych segmentC2
segmentC2 <- data.frame(segmentC[,c("Cena.w.PLN", "Model", "Nadwozie", "Pojemnosc.skokowa", "Rodzaj.paliwa", 
  "wiek", "kodPocztowy2", "kodPocztowy1")], ncechy)

 

Model 1. Najistotniejsze czynniki

Korzystając z tzw. wiedzy eksperckiej i po kilkunastu próbach eksperymentalnych jako trzy najważniejsze czynniki wpływające na cenę samochodu wybrałem: model samochodu, nadwozie i wiek auta. Jeżeli w modelu uwzględni się wiek to okazuje się, że deklarowany przebieg w km ma minimalne znaczenie, więc na tym etapie został pominięty.

Poniżej przedstawiam wyniki estymacji współczynników modelu. W kolejnym wpisie, gdy pokażemy wizualizacje naszych danych łatwiej będzie uwierzyć, że otrzymany model jest sensowny. Btw: poniższy model tłumaczy 85% zmienności ceny auta, całkiem dużo jak na trzy zmienne.

Co ciekawego można zauważyć? Audi A3 jest średnio najdroższe bez względu na to czy w wersji Kombi czy nie (droższe przynajmniej o 1/4), czy jest to efekt samej marki czy wyposażenia okaże się z później. Dla różnych modeli auta z nadwoziem kombi są średnio droższe (Octavia, Cee’d) lub tańsze (Civic, Focus) od hatchbacków. W salonach wersja kombi jest zawsze droższa (podobnie jak diesel) ale jak się okazuje dla Forda lub Civica na rynku może być więcej aut w nadwoziu kombi ze słabszym wyposażeniem lub większym przebiegiem lub sprowadzonych lub z inną cechą która odbija się na cenie.

#
# Pomocnicza funkcja, przedstawiająca tabelę efektów w bardziej zwartej i czytelnej postaci. Przekształcamy efekty liczone na logarytmach tak by przedstawiały ,,efekt multiplikatywny'' czyli porównanie procentowej ceny aut.
#
opisz <- function(x, filtr="") {
 tt <- data.frame(round(2^x[grepl(filtr, rownames(x)),1,drop=F]*1000)/10, 
       signif = cut(x[grepl(filtr, rownames(x)),4,drop=F], c(-1,0.001,0.01,1), c("**","*","")))
 tt[order(tt[,1]),]
}
 
#
# Wyniki analizy wariancji
# Jak widzimy największy wpływ na cenę auta ma wiek, w drugiej kolejności model auta i typ nadwozia
#
> anova(model <- lm(log(Cena.w.PLN,2)~Model:Nadwozie+wiek, segmentC2))
Analysis of Variance Table
 
Response: log(Cena.w.PLN, 2)
                  Df Sum Sq Mean Sq  F value    Pr(>F)    
wiek               1 5873.4  5873.4 67373.01 < 2.2e-16 ***
Model:Nadwozie    18  706.9    39.3   450.47 < 2.2e-16 ***
Residuals      13399 1168.1     0.1                       
---
Signif. codes:  0***0.001**0.01*0.05 ‘.’ 0.1 ‘ ’ 1 
#
# Referencyjnym poziomem jest Skoda Octavia Kombi
# Wartość w kolumnie ,Estimate' odpowiada mniej więcej temu ile procent średniej ceny 
# Skody Octavii Kombi  stanowi średnia cena danego auta w określonej wersji nadwozia. 
# Czyli np. cee'd kombi jest o 15% tańszy od octavii kombi (przyjmując tę samą utratę 
# wartości z uwagi na wiek), za to Audi A3 kombi jest średnio o 35% droższe niż Octavia Kombi.
#
# Wartość przy zmiennej wiek oznacza że auta średnio tracą około 14% wartości na rok.
# 
> opisz(summary(model)$coefficients)
                                Estimate signif
ModelCivic:NadwozieKombi            69.7       
ModelFocus:NadwozieKombi            70.2     **
ModelC4:NadwozieHatchback           72.9     **
Modeli30:NadwozieHatchback          73.9     **
ModelCee'd:NadwozieHatchback        74.5     **
ModelAstra:NadwozieKombi            75.3     **
ModelFocus:NadwozieHatchback        75.4     **
Modeli30:NadwozieKombi              78.0     **
ModelAstra:NadwozieHatchback        78.5     **
Model308:NadwozieKombi              79.6     **
Model308:NadwozieHatchback          80.6     **
ModelCee'd:NadwozieKombi            86.3     **
ModelOctavia:NadwozieHatchback      93.4     **
ModelGolf:NadwozieKombi             93.6     **
ModelCivic:NadwozieHatchback        96.0     **
ModelGolf:NadwozieHatchback         98.8       
ModelA3:NadwozieHatchback          124.5     **
ModelA3:NadwozieKombi              135.4     **
wiek                                86.0     **

Model 2. Wyposażenie dodatkowe

Opisując transformacje zmiennych napisałem że do zbioru danych dodałem 37 binarnych zmiennych opisujących wyposażenie auta. Zobaczmy, które elementy wyposażenia mają największy wpływ na cenę auta.

Aby zmniejszyć objętość poniższego przykładu przedstawiam wyniki tylko dla wybranych elementów wyposażenia. Cztery elementy wyposażenia najdroższych aut to kseony, ESP, klimatyzacja i elektryczne lusterka. Auta, które w opisie wyposażenia miały wymienione wspomaganie kierownicy lub poduszkę powietrzną są o kilka procent tańsze od aut bez tych elementów w opisie. Nie oznacza to oczywiście, że z dwóch aut podobnych to bez wspomagania kierownicy jest droższe. Oznacza to raczej, że w opisie auta jeżeli pojawia się wspomaganie kierownicy to nie pojawiają się inne elementy jeszcze bardziej zwiększające ceny auta. Należy więc być bardzo ostrożnym interpretując wyniki z modelowania cen.

Poniższy model wyjaśnia już ponad 90% wariancji.

#
# Auta z kseonowymi lampami, klimatyzacją, ESP, elektrycznymi lusterkami są 
# średnio o kilka procent droższe od aut bez tych elementów. 
# Większość elementów wyposażenia nie różnicuje istotnie ceny auta
#
> model <- lm(log(Cena.w.PLN,2)~Model*Nadwozie+wiek+.-kodPocztowy1-kodPocztowy2, segmentC2)
> opisz(summary(model)$coefficients, "TRUE")
                              Estimate signif
wspomaganie.kierownicy        91.4     **
poduszka.powietrzna           94.6     **
welurowa.tapicerka            96.2     **
...
pierwszy.wlasciciel          100.2       
serwisowany.w.ASO            100.5       
bezwypadkowy                 100.7       
przyciemniane.szyby          101.0       
czujnik.deszczu              101.3       
system.nawigacji             101.9      *
tempomat                     101.9     **
bagaznik.na.dach             102.1       
skorzana.tapicerka           102.3      *
podgrzewane.fotele           102.5     **
el..szyby                    102.5      *
alufelgi                     103.0     **
kierownica.wielofunkcyjna    103.1     **
komputer                     103.2     **
klimatyzacja                 103.3     **
el..lusterka                 103.8     **
ESP                          104.3     **
ksenony                      108.2     **

 

Model 3. Lokalizacja, lokalizacja, lokalizacja

Kuszące jest dodać do modelu informację o kodzie pocztowym aby sprawdzić czy miejsce w którym oferowane jest auto istotnie wpływa na cenę ofertową.

#
# Różnice pomiędzy cenami aut są ,,istotne statystycznie''
# Nie jest to jednak duże osiągnięcie, biorąc pod uwagę 13 tysięcy ofert 
# na których przeprowadzamy testowanie.
# Wartość różnic nie jest duża w porównaniu do efektu wieku, modelu czy typu nadwozia.
#
> anova(model <- lm(log(Cena.w.PLN,2)~Model:Nadwozie+wiek+kodPocztowy1+kodPocztowy2+kodPocztowy5, segmentC2))
Analysis of Variance Table
 
Response: log(Cena.w.PLN, 2)
                  Df Sum Sq Mean Sq    F value    Pr(>F)    
wiek               1 5873.4  5873.4 72953.9503 < 2.2e-16 ***
kodPocztowy1      10    7.4     0.7     9.1992 2.489e-15 ***
kodPocztowy2      88   39.0     0.4     5.5087 < 2.2e-16 ***
kodPocztowy5    1091  240.8     0.2     2.7419 < 2.2e-16 ***
Model:Nadwozie    18  604.7    33.6   417.2709 < 2.2e-16 ***
Residuals      12210  983.0     0.1                         
---
Signif. codes:  0***0.001**0.01*0.05 ‘.’ 0.1 ‘ ’ 1

 

Model 4. Te wszystkie nieistotne zmienne

Ciekawym eksperymentem może być samodzielne znalezienie innych czynników istotnie różnicujące cenę auta. Szybko jednak się okazuje, że wyniki rozjeżdżają się z intuicją. I jest to za każdym razem efekt niezrównoważonych zmiennych (porównując diesle i silniki benzynowe trudno uciec od tego że diesle mają większy przebieg). Drugi ciekawy problem to szybko rosnąca macierz modelu. Jeżeli uwzględnimy wiek jako zmienna jakościowo i będziemy analizować jego interakcje z kodem pocztowym to jedna interakcja generuje ponad 1000 kolumn do macierzy modeli.

Analiza takich danych jest znacznie ciekawsza niż analiza zależności pomiędzy szerokościami płatków irysów jest też znacznie trudniejsza. Ale też bliższa rzeczywistym problemom.

Więc życzę miłej zabawy!

Plan na kolejny wpis: przedstawić powyższe liczbowe wyniki graficznie.

Ceny używanych aut po raz trzeci

 

W październiku poprzedniego roku i 1 stycznia tego roku zebrałem na bazie serwisu www.otomoto.pl zbiór opisujący cen i wiele dodatkowych parametrów z ofert sprzedaży samochodów używanych (zobacz między innymi te wpisy). Dzisiaj dodaję zbiór danych o cenach samochodów z połowy marca roku 2012. Na podstawie tych trzech pomiarów będziemy mogli się przyjrzeć temu jak się zmieniały ceny używanych aut w przeciągu ostatnich 6 miesięcy.

Do pierwszego zbioru danych dołączyłem kilka analiz statystycznych i wizualizacji. Do drugiego zbioru danych dodałem szczegółowy opis jak takie dane pobierać. Zabrakło mi jednak czasu by przedstawić wyniki analiz statystycznych danych zebranych w styczniu.

Okazało się jednak, że nawet surowe dane mogą być przydatne. W tak zwanym między czasie otrzymałem od trzech osób informację, że ten zbiór danych bardzo im się przydał w projekcie licencjackim. A od jednej osoby otrzymałem nawet napisaną już pracę licencjacką poświęconą różnym technikom analizy danych z przykładami na zbiorze danych o samochodach pobranym z tego bloga.
Super!!!
Więcej takich projektów!
Jeżeli autorzy się zgodzą to podlinkuję ich wyniki do odpowiednich wpisów.

Jeden z częściej pojawiających się komentarzy od osób pracujących na zebranych danych dotyczył braku informacji o typie nadwozia. W poprzednio zbieranych danych typ nadwozia nie był bezpośrednio identyfikowalny.

Mając to na uwadze tym razem listę zmiennych opisujących ofertę sprzedaży auta rozszerzyłem o dwie nowe zmienne. Pierwszą jest typ nadwozia a drugą jest kod pocztowy i nazwa miejscowości z której pochodzi dane ogłoszenie.

Ponieważ ostatnio interesowałem się analizą danych przestrzennych i funkcjami do przedstawiania danych na mapach, więc postaram się w najbliższych dniach pokazać co ciekawego można zrobić z cenami samochodów używanych mając też informacje o miejscu złożenia oferty sprzedaży.

Skrypt wczytujący do programu R dane zebrane w marcu 2012 znajduje się tutaj.

Dane w postaci tekstowej i binarnej znajdują się w tym katalogu.

Prosty pająk sieciowy, czyli parsowanie stron internetowych, część 2

Jakiś czas temu we wpisie ,,Prosty pająk sieciowy‘’ (link tutaj) przedstawiłem połączenie skryptu w Perlu i skryptu w R, które wykorzystywałem do zbierania danych o samochodach z serwisu otomoto.pl.

W komentarzach do wpisu użytkownik Maciej opisał podobne rozwiązanie, ale zamiast skryptu w Perlu wykorzystujące pakiet XML (dostępny dla programu R w repozytorium CRAN). Rozwiązanie Maćka ma kilka zalet nad hybryda R+Perl, z mojego punktu widzenia, największa zaleta jest taka, że ,,wszystko’’ dzieje się w R. Łatwiej utrzymać, przenosić i rozwijać rozwiązanie, które jest bardziej jednolite.

Spodziewany koszt tej jednolitości to czasu działania. Wydawało (mi) się, że Perl jako narzędzie do przetwarzania tekstów i działania na stronach internetowych powinien być szybszy od R. Pytanie jaka będzie różnica w czasach działania?

Maciej Beręsewicz przygotował dwa skrypty w R, które wykonują praktycznie te same operacje co mój skrypt w Perlu. Pierwszy skrypt (wersjaStrsplitMB.R) wykorzystuje funkcję getURL() aby ściągnąć źródła strony a następnie używa funkcji strsplit() by wydobyć ze źródła HTML interesujące rzeczy. Drugi skrypt (wersjaXMLMB.R) wykorzystuje funkcję htmlParse() od odczytania i parsowania dokumentu HTML, a następnie xpathApply() do operacji na przetworzonym wstępnie dokumencie. Oba skrypty są dostępne w tym katalogu.

 

Aby porównać czasy działania uruchomiłem te trzy wersje (Perl, R z strsplit i R z XML) kilkukrotnie. Za każdym razem ściągając informacje o 4 tyś aut. Testy rożnych rozwiązań odbyły się na tej samej maszynie, na szerokopasmowym łączu (wykorzystywany tylko jeden węzeł  o wydajności odpowiadającej intel i7). Testy wykonałem o różnych godzinach by zobaczyć jak wpływ na czasy będzie miało natężenie ruchu w sieci, ale koniec końców otrzymałem bardzo powtarzalne wyniki, bez względu na godzinę czy dzień wykonania testów. Więc niżej pokażę tylko medianowe wyniki  z różnych uruchomień.

Porównywane wersje:

  • Wersja P = Perl + wczytanie danych do R
  • Wersja R1 = R ściąganie getURL() i parsowanie z użyciem funkcji strsplit()
  • Wersja R2 = R ściąganie i parsowanie z użyciem funkcji htmlParse()

Medianowe czasy działań i odpowiadająca im wydajność liczna w liczbie ,,przetworzonych’ 'stron opisujących kolejne auta na sekundę

 

Wersja testowana    Wydajność               Czas pobierania
                    liczona aut/sec         i przetwarzania 4tys aut

Wersja P            4.61 aut/sec            867 sekund ( < 15 min)
Wersja R1           2.93 aut/sec           1365 sekund ( < 23 min)
Wersja R2           4.19 aut/sec            954 sekund ( < 16 min)

 

Ponieważ profilowanie kodu w R jest cudownie proste sprawdziłem też, które elementy ,,zżerają’’ najwięcej czasu w obu wersja Rowych. Poniżej wyniki dla medianowego czasu działania (tylko operacje najbardziej czasochłonne)

Wersja R1
                        total.time  total.pct
getURL                      714.08      52.53
strsplit                    633.30      46.58

Wersja R2
                        total.time  total.pct
htmlParse                   919.01      96.21

W wersji R1, ponad 99% czasu zużyte jest te dwie operacje. Dodatkowy narzut związany z pętlami, zapisywaniem na dysku itp to mniej niż 1%. Z tych dwóch operacji mniej więcej tyle samo czasu trwa odczytywanie HTML przez sieć co jego parsowanie.

W wersji R2 większość czasu przetwarzania to wywołanie htmlParse(), która jest opakowaniem odwołania do funkcji napisanej w C.

 

Pointa?

Wersja perlowa jest najszybsza, ale wersja używająca pakietu XML jest niewiele wolniejsza. Biorąc pod uwagę dodatkowo długość kodu, jednolitość bardziej podoba mi się rozwiązanie Macka używające pakietu XML.

 

Ceny używanych aut po nowym roku a prosty pająk sieciowy

Trzy miesiące temu opisywałem zbiór danych o ofertach sprzedaży samochodów z serwisu otomoto.pl (zobacz tutaj). Po kwartale ponownie zebrałem informacje o ofertach sprzedaży. Porównując te dwa zbiory będzie można sprawdzić jak zmieniają się ceny różnych modeli w odpowiedzi na podwyższoną akcyzę na olej napędowy. Kolejne interesujące pytanie to globalna zmiana cen aut używanych w ,,czasach kryzysu’’. Interesujący będize trend zmian w liczbie ofert samochodów sprowadzanych z zagranicy. Efekt starzenia się auta, z dnia na dzień auto staje sie o rok starsze, ciekawe czy dla aut używanych wiek w latach ma duzy wpływ na cenę auta.

Nowy zbiór danych jest dostępny w postaci csv i Rdata pod tym adresami [csv 80Mb], [Rdata 5,5 MB].

Skrypt wczytujący dane bezpośrednio z Internetu do R znajduje się tutaj.

 

Ponieważ ostatnio pojawiały się pytania o skrypty użyte do parsowania stron interntowych i zbierania automatycznego danych, więc do tych danych dołączam wszystkie skrypty potrzebne do ich zebrania i przetworzenia. Poniżej krótko je opiszę. Wykorzystuję tutaj głównie Perla i wyrażenia regularne pozwalające na łatwe i szybkie parsowanie tekstu. Z pewnością istnieją lepsze (łatwiejsze) sposoby parsowania stron HTML, chętnie usłyszę sugestie.

W moim rozwiązaniu proces zbierania danych jest dwuetapowy. Pierwszy etap to przejrzenie hierarchicznej struktury ofert sprzedaży samochodów oraz zapisanie z każdej oferty wybranych pól. Dodatkowo należy zatroszczyć się o to by to samo auto nie zostało dwukrotnie dodane do listy aut. Ponieważ parsowanie 200 tys ofert trochę trwa, a tym czasie do serwisu dodawane są nowe oferty, więc potrzebna jest dodatkowa tablica haszująca pamiętająca, które auta zostały już przetworzone. Skrypt perlowy, który wykorzystałem w tym celu znajduje się tutaj [skrypt perl]. Plik wynikowy, z zebranymi danymi znajduje się tutaj [surowe dane po pierwszym etapie 140MB].

Ponieważ dla różnych ofert sprzedaży  przedstawiane są różne charakterystyki, niektórych opisów brakuje, niektóre parametry są w różnych formatach, dlatego też w drugim kroku wykorzystuję skrypt R obrabiający surowe dane i przekształcający je do postaci tabelarycznej, łatwiejszej w obróbce. Przy okazji cena aut w walucie przeliczana jest na PLN, liczona jest pojemność skokowa, moc i inne parametry, które w surowych danych sa zapisane w formacie tekstowym. Skrypt użyty do transformacji znajduje sie tutaj [skrypt r], a plik wynikowy znajduje się tutaj [plik csv].

Smacznego!

 

Mapa wartości samochodów

Wczoraj graficznie przedstawialiśmy jak wygląda rozkład cen w zależności od roku produkcji. Co ciekawe w skali logliniowej zależność pomiędzy ceną a rokiem produkcji jest bardzo bliska liniowej dla wielu marek. Zakładając zależność liniową możemy wyznaczyć dwie liczby dla każdej marki. Średnią procentową zmianę ceny w ciągu roku i orientacyjną średnią cenę auta wyprodukowanego w roku 2006. Rok 2006 został wybrany by móc porównywać ceny różnych marek ze sobą, oczekiwaną cenę w roku 2006 wyznaczmy bez względu na to czy dany samochód był produkowany w tym roku czy nie (wykorzystamy liniową zależność aby oszacować średnią cenę w roku 2006).
Na poniższej mapie zaznaczono każdą markę w układzie dwóch współrzędnych, utraty wartości w ciągu roku oraz orientacyjnej ceny w roku 2006. Należy zaznaczyć, że wartość procentowa na osi OX to różnica pomiędzy średnimi cenami dwóch kolejnych roczników, a nie różnica pomiędzy ceną danego rocznika w dwóch kolejnych latach. Tą drugą wartość będzie można ustalić za rok.

 

Dodatkowo na tej mapie wielkością punktu zaznaczono jak wiele aut było wykorzystanych do oszacowania obu wskaźników (cztery wielkości do 100, od 100 do 200, od 200 do 500, powyżej 500) oraz z jakiego kraju pochodzi dana marka. Jeżeli chodzi o pochodzenie to z uwagi na przejęcia oraz przenoszenie produkcji do innych krajów należy tę informację traktować z dystansem.

To co ciekawego widać na tej mapie to że są auta tanie, które nie tracą wiele z czasem na wartości (np Fiat Uno), drogie, które też dużo na wartości tracą (Porche Cayenne), tanie które dużo tracą (Dacia Logan), drogie które mało tracą (Volkswagen Bora) i całe spektrum innych możliwości.

Aby łatwiej ten wykres się analizowało możemy dokonać zbliżenia

Volkswagen Passat traci średni 16% na rok i kosztuje z roku 2006 około 40tys. W otoczeniu znaleźć można np Toyote Corolle Verso. Na prawo znajdziemy Forda S-Maxa o podobnej cenie ale za to znacznie większej utracie na wartości.

Zobaczmy co się stanie jeżeli zagregujemy modele z tej samej marki.

 

Otrzymujemy mapę marek, im bardziej na lewo tej mapy tym mniejsza utrata na wartości im niżej tym tańsze auta.

 

 

 

 

 

 

 

 

Zakup kontrolowany, czyli wybieramy auto dla rodziny

Od prawie czterech lat szukam rodzinnego auta. Ostatnio rozmawiałem ze znajomym, który był zdziwiony dlaczego to taki trudny wybór. Jak to stwierdził wystarczy wprowadzić dane do komputera, określić funkcje celu i wybrać najlepszą opcję. Hmmm, może i tak.

Mamy już dane zebrane  z serwisu otomoto.pl, więc spróbujmy zobaczyć jak wyglądają rozkłady cen w czasie różnych marek. Informacje o zmianach cen znaleźć można na wielu serwisach, np. autocentrum.pl, ale tutaj przedstawimy te zmiany lepiej i czytelniej. Tak jest, konkurujemy z eutotax.

Aktualnie wysoko na liście rozważanych marek stoi Passat. Poniższe wykresy będą wykonane dla prawie każdej marki obecnej w zbiorze danych cenyAut2011. Ale dla ustalenia uwagi zobaczmy  wygląda cena Passata i jak ta cena zależy od roku produkcji (oś OX), pojemności i typu silnika (poszczególne panele) oraz wersji marki (rożne kolory kropek).

Na panelu po prawej stronie podana jest nazwa marki, liczba ofert sprzedaży aut tej marki, oraz informacja o rozkładzie cen dla aut produkowanych w danym roczniku. Każda niebieska kropka to jedna oferta sprzedaży. Czerwona kropka oznacza medianę cen, czerwone kreski oznaczają odpowiednio kwantyle 5-25% i 75-95%. Ceny są w skali logarytmicznej. Na wykresie mamy tylko dane o autach używanych, w tej kategorii mediany cen układają się prawie idealnie w linii prostej, co odpowiada stałej procentowej zmianie w cenie. Tę informację jeszcze wykorzystamy.

Z wykresów widzimy, że passaty  w dieslu z silnikiem 1900cm3 są dosyć popularne. 5 lat to jeszcze wersja B6. Zobaczmy teraz jak wyglądają podobne wykresy dla konkurencji.

 

Obrazki dla innych marek można znaleźć w katalogu tutaj.

Lub korzystając z poniższej listy marek, dla której zebrano takie wykresy.
Alfa Romeo 147, Alfa Romeo 156, Alfa Romeo 159, Alfa Romeo 166, Alfa Romeo GT,
Audi A2, Audi A3, Audi A4, Audi A5, Audi A6, Audi A6 Allroad, Audi A7, Audi A8, Audi Q5, Audi Q7, Audi TT,
BMW 118, BMW 316, BMW 318, BMW 320, BMW 325, BMW 330, BMW 520, BMW 525, BMW 530, BMW 535, BMW 730, BMW 740, BMW X3, BMW X5, BMW X6,
Chevrolet Aveo, Chevrolet Lacetti,
Chrysler 300C, Chrysler Grand Voyager, Chrysler Pacifica, Chrysler PT Cruiser, Chrysler Sebring, Chrysler Town & Country, Chrysler Voyager,
Citroen Berlingo, Citroen C1, Citroen C2, Citroen C3, Citroen C4, Citroen C4 Picasso, Citroen C5, Citroen C8, Citroen Saxo, Citroen Xsara, Citroen Xsara Picasso,
Dacia Logan,
Daewoo Lanos, Daewoo Matiz, Daewoo Nubira,
Dodge Grand Caravan, Dodge RAM,
Fiat 500, Fiat Brava, Fiat Bravo, Fiat Croma, Fiat Doblo, Fiat Ducato, Fiat Grande Punto, Fiat Marea, Fiat Multipla, Fiat Palio, Fiat Panda, Fiat Punto, Fiat Seicento, Fiat Stilo, Fiat Uno,
Ford C-MAX, Ford Fiesta, Ford Focus, Ford Focus C-Max, Ford Fusion, Ford Galaxy, Ford KA, Ford Mondeo, Ford Mustang, Ford S-Max, Ford Transit,
Honda Accord, Honda Civic, Honda CR-V, Honda Jazz,
Hyundai Accent, Hyundai Coupe, Hyundai Getz, Hyundai i30, Hyundai Matrix, Hyundai Santa Fe, Hyundai Tucson,
Jaguar S-Type, Jaguar X-Type,
Jeep Cherokee, Jeep Grand Cherokee,
Kia Carens, Kia Carnival, Kia Cee’d, Kia Picanto, Kia Rio, Kia Sorento, Kia Sportage,
Lancia Lybra,
Land Rover Discovery, Land Rover Freelander, Land Rover Range Rover,
Lincoln Town Car,
Mazda 2, Mazda 3, Mazda 323, Mazda 323F, Mazda 5, Mazda 6, Mazda 626, Mazda CX-7, Mazda MPV, Mazda Premacy, Mazda RX-8,
Mercedes-Benz A 140, Mercedes-Benz A 160, Mercedes-Benz A 170, Mercedes-Benz A 180, Mercedes-Benz B 180, Mercedes-Benz C 180, Mercedes-Benz C 200, Mercedes-Benz C 220, Mercedes-Benz CLK 200, Mercedes-Benz E 200, Mercedes-Benz E 220, Mercedes-Benz E 270, Mercedes-Benz E 280, Mercedes-Benz E 320, Mercedes-Benz E 350, Mercedes-Benz ML 270, Mercedes-Benz ML 320, Mercedes-Benz ML 350, Mercedes-Benz S 320, Mercedes-Benz S 350, Mercedes-Benz S 500, Mercedes-Benz SLK 200, Mercedes-Benz Sprinter, Mercedes-Benz Vito,
Mini Cooper,
Mitsubishi Carisma, Mitsubishi Colt, Mitsubishi Eclipse, Mitsubishi Galant, Mitsubishi L200, Mitsubishi Lancer, Mitsubishi Outlander, Mitsubishi Pajero, Mitsubishi Space Star,
Nissan Almera, Nissan Almera Tino, Nissan Micra, Nissan Navara, Nissan Note, Nissan Patrol, Nissan Primera, Nissan Qashqai, Nissan Terrano, Nissan X-Trail,
Opel Agila, Opel Astra, Opel Combo, Opel Corsa, Opel Frontera, Opel Insignia, Opel Meriva, Opel Omega, Opel Signum, Opel Tigra, Opel Vectra, Opel Vivaro, Opel Zafira,
Peugeot 106, Peugeot 107, Peugeot 206, Peugeot 206 CC, Peugeot 207, Peugeot 306, Peugeot 307, Peugeot 308, Peugeot 406, Peugeot 407, Peugeot 607, Peugeot 807,
Peugeot Partner,
Porsche 911, Porsche Cayenne,
Renault Clio, Renault Espace, Renault Grand Espace, Renault Grand Scenic, Renault Kangoo, Renault Laguna, Renault Megane, Renault Modus, Renault Scenic, Renault Thalia, Renault Trafic, Renault Twingo,
Renault Vel Satis,
Rover 25, Rover 45, Rover 75,
Saab 9-3, Saab 9-5,
Seat Alhambra, Seat Altea, Seat Arosa, Seat Cordoba, Seat Ibiza, Seat Leon, Seat Toledo,
Skoda Fabia, Skoda Felicia, Skoda Octavia, Skoda Roomster, Skoda Superb,
Smart Fortwo,
Subaru Forester, Subaru Impreza, Subaru Legacy,
Suzuki Grand Vitara, Suzuki Jimny, Suzuki Swift, Suzuki SX4,
Toyota Auris, Toyota Avensis, Toyota Aygo, Toyota Camry, Toyota Celica, Toyota Corolla, Toyota Corolla Verso, Toyota Land Cruiser, Toyota RAV-4, Toyota Yaris,
Volkswagen Bora, Volkswagen Caddy, Volkswagen Caravelle, Volkswagen Fox, Volkswagen Golf, Volkswagen Golf Plus, Volkswagen Jetta, Volkswagen Lupo, Volkswagen Multivan, Volkswagen New Beetle, Volkswagen Passat, Volkswagen Passat CC, Volkswagen Polo, Volkswagen Sharan, Volkswagen Tiguan, Volkswagen Touareg, Volkswagen Touran, Volkswagen Transporter,
Volvo C30, Volvo S40, Volvo S60, Volvo S80, Volvo V40, Volvo V50, Volvo V70, Volvo XC 70, Volvo XC 90

Zbiór danych o cenach ofertowych aut z 1 października 2011

Kilka dni temu napisałem mały skrypt w perlu, który zbiera dane o ofertach sprzedaży samochodów z serwisu otomoto.pl.

W sumie przez kilka godzin udało się zgromadzić zbiór danych o prawie 200 tys ofertach sprzedaży auta. Katalog z danymi znajduje się tutaj. Link do programu R który wczytuje te dane znajduje się tutaj. Uwaga! plik tekstowy z danymi to 75MB.

Dla każdej oferty zebrane są takie cechy jak: cena, marka, model, wersja, moc, silnik, liczba drzwi,  rodzaj paliwa, deklarowany przebieg, rok produkcji, opis, wyposażenie, kraj pochodzenia, kolor itp.

Myślę, że to bardzo ciekawy zbiór danych. Proste podsumowania przedstawione w pliku wczytującym dane pokazują np. że prawie 1/4 z tych aut pochodzi z Niemiec. Cztery najczęściej oferowane modele to Passat (7tys ofert), Golf (6.3tys ofert), Astra (6tys ofert) i Focus (5.2tys ofert). Ciekawie będzie zobaczyć jak ceny tych aut zmieniają się w zależności od wersji, roku produkcji, przebiegu, wyposażenia. Może nawet uda się zbudować coś konkurencyjnego do eurotaxu.