Przygotowywanie, szkolenie i testowanie danych

Jak zawsze zaczniemy od konfiguracji naszych danych. W tym przypadku danymi są wiadomości otrzymane przez naszą fantastyczną firmę The Cake Factory. Znajdują się one w pliku client_messages.RDS, który utworzyliśmy wcześniej. Dane zawierają 300 obserwacji dla 8 zmiennych: SALE_ID, DATE, STARS, SUMMARY, MESSAGE, LAR, LNG i MULT_PURCHASE. W tej sekcji będziemy pracować ze zmiennymi MESSAGE i MULT_PURCHASE.

Skonfigurujemy nasze ziarno tak, aby dawało powtarzalne wyniki. Pamiętaj, że powinno to mieć miejsce przed każdym wywołaniem funkcji, które wiąże się z jakąś randomizacją. Pokażemy to tylko raz, aby zaoszczędzić miejsce i uniknąć powtarzania się, ale miej to na uwadze, próbując wygenerować odtwarzalne wyniki:

set.seed(12345)

Następnie musimy się upewnić, że w odpowiednich zmiennych nie brakuje żadnych danych. Aby to zrobić, używamy funkcji complete.cases() wraz z negacją (!) i funkcją sum(), aby uzyskać całkowitą liczbę wartości NA ‘w każdej zmiennej. Jak widać, nie mamy żadnych brakujących danych:

sum(!complete.cases(client_messages$MESSAGE))

#> 0

sum(!omplete.cases(client_messages$MULT_PURCHASES))

#> 0

Jeśli masz brakujące dane, zamiast korzystać z jakiegoś mechanizmu imputacji, który jest zwykle wykonywany w niektórych scenariuszach analizy danych, chcesz usunąć te obserwacje z tych danych, ponieważ łatwiej jest to błędne ze względu na nieciągłą charakterystykę danych tekstowych. Jak często można się przekonać podczas pracy nad interesującymi rzeczywistymi problemami w analizie predykcyjnej, nierzadko pracuje się z nieproporcjonalnymi danymi. W tym przypadku, jak widać na pokazanym kodzie, mamy około 63% zakupów wielokrotnych. Nie jest to zbyt nieproporcjonalne, ale nadal musimy grać po bezpiecznej stronie, utrzymując dane treningowe i testowe w podobnych proporcjach:

prop.table9tab;e(client_messages$MULT_PURCHASES))

#> FALSE TRUE

#> 0,3621262 0,6378738

W przypadku danych z problemem nieproporcjonalności utrzymanie tych samych proporcji w zestawach testowych i szkoleniowych jest ważne, aby uzyskać dokładne wyniki. Dlatego musimy upewnić się, że nasza metoda próbkowania zachowuje te proporcje. Aby to zrobić, użyjemy funkcji createDataPartitio() z pakietu caret, aby wyodrębnić indeksy dla każdego zestawu uczącego i testowego. Stworzy zbalansowane podziały danych iw tym przypadku wykorzysta 70% danych do uczenia z jedną partycją:

indexes <- createDataPartition(

client_messages$MULT_PURCHASES,

list = FALSE,

times= 1,

 p= 0.7

)

trai <- clinet_messages[ idexes, ]

test <- clinet-messages[-indexes, ]

Aby mieć pewność, że nasze proporcje są zachowane, możemy sprawdzić każdy z nich indywidualnie, tak jak robiliśmy to wcześniej z pełnymi danymi:

prop.table(table(train$MULT_PURCHASES))

#> FALSE TRUE

#> 0,3632075 0,6367925

prop.table(table(test$MULT_PURCHASES))

#> FALSE TRUE

#> 0,3595506 0,6404494

Teraz, gdy mamy już gotowe zestawy szkoleniowe i testowe, możemy rozpocząć czyszczenie i konfigurację naszych danych tekstowych, tak jak zrobimy to w następnej sekcji.

Co to jest analiza tekstu i jak działa?

Analiza tekstu to proces uzyskiwania informacji z tekstu. Informacje są zwykle uzyskiwane za pomocą technik, takich jak IR, NLP i SL, i obejmują one strukturyzację tekstu, wyprowadzanie wzorców z ustrukturyzowanych danych, a na końcu ocenę i interpretację wyników. Podstawowymi modelami używanymi do analizy tekstu są modele bag-of-words, model przestrzeni wektorowej i semantyczny model analizy. Model worka słów to uproszczona reprezentacja tekstu, w której tekst (w naszym przypadku recenzja) jest reprezentowany jako zbiór jego terminów (słów), pomijając gramatykę i kolejność słów, ale zachowując wielość (stąd termin torba). Po przekształceniu tekstu w worek słów i uporządkowaniu w korpus (uporządkowany zbiór danych tekstowych), możemy obliczyć różne miary, aby scharakteryzować tekst w przestrzeni wektorowej. Model bag-of-words jest powszechnie stosowany w metodach SL i będziemy go używać z losowymi lasami w tej części. W praktyce służy jako narzędzie do generowania cech. Poniższy obraz wyjaśnia model worka słów:

Model przestrzeni wektorowej wykorzystuje zbiór słów wyodrębniony z dokumentów w celu utworzenia wektora cech dla każdego tekstu, gdzie każdy element jest terminem, a wartość elementu jest wagą terminu. Termin waga może być wartością binarną (1 oznacza, że ​​termin wystąpił w dokumencie, a 0 oznacza, że ​​tak się nie stało), wartością częstotliwości terminu (TF) (wskazującą, ile razy termin wystąpił w dokumencie) lub terminem wartość odwrotnej częstotliwości dokumentu (TF-IDF) (wskazująca, jak ważny jest termin dla tekstu, biorąc pod uwagę jego korpus). Istnieją bardziej złożone mechanizmy ważenia, które koncentrują się na konkretnych problemach, ale są to najpowszechniejsze i na nich się skupimy. Biorąc pod uwagę to, o czym wspomnieliśmy wcześniej, tekst okazuje się być wektorem cech, a każdy wektor cech odpowiada punktowi w przestrzeni wektorowej. Model tej przestrzeni wektorowej jest taki, że istnieje oś dla każdego terminu w słowniku, a więc przestrzeń wektorowa jest n-wymiarowa, gdzie n jest rozmiarem słownictwa we wszystkich analizowanych danych (może to być ogromne) . Czasami warto pomyśleć o tych pojęciach w sposób geometryczny. Model worka słów i model przestrzeni wektorowej odnoszą się do różnych aspektów charakteryzowania tekstu i uzupełniają się wzajemnie. Poniższa ilustracja wyjaśnia model przestrzeni wektorowej:

Istotną słabością modelu bag-of-words jest to, że ignoruje on kontekst semantyczny terminów. Istnieją bardziej złożone modele, które próbują naprawić te niedociągnięcia. Jednym z nich jest parsowanie semantyczne, które polega na odwzorowywaniu zdania w języku naturalnym na formalną reprezentację jego znaczenia. Wykorzystuje głównie kombinacje programowania indukcyjnego i uczenia się statystycznego. Tego typu techniki stają się bardziej przydatne w przypadku złożonych tekstów. Chociaż nie będziemy ich dalej omawiać w tej książce, są one potężnym narzędziem i bardzo interesującym obszarem badań. Na przykład, jeśli spróbujesz pomyśleć o reprezentacji poniższego cytatu za pomocą modelu worka słów i semantycznego modelu parsowania, możesz intuicyjnie pomyśleć, że pierwszy z nich może dać nonsensowne wyniki, podczas gdy drugi może dostarczyć co najmniej trochę zrozumienia i miałbyś rację.

„Pułapka na ryby istnieje dzięki rybom. Gdy już zdobędziesz rybę, możesz zapomnieć o pułapce. Pułapka na królika istnieje z powodu królika. Kiedy już zdobędziesz królika, możesz zapomnieć o sidła. Słowa istnieją dzięki znaczenie. Kiedy już zrozumiesz znaczenie, możesz zapomnieć o słowach. Gdzie mogę znaleźć mężczyznę, który zapomniał słów, abym mógł z nim porozmawiać? ”

– Pisma Chuang Tzu, IV wiek p.n.e.

Wymagane pakiety

“Wspomóż rozwój naszego Bloga. Kliknij w Reklamę. Nic nie tracisz a zyskujesz  naszą wdzięczność … oraz lepsze, ciekawsze TEKSTY. Dziękujemy”

Konfiguracja pakietów dla tej części może być nieco uciążliwa, ponieważ niektóre z nich zależą od bibliotek systemu operacyjnego, które mogą się różnić w zależności od komputera

lsa: Obliczanie podobieństwa cosinusów

rilba :  Efektywny rozkład SVD

caret :  Framework uczenia maszynowego

twitteR: Interfejs do API Twittera

quanteda :  Przetwarzanie danych tekstowych

setimentr : Analiza nastrojów danych tekstowych

randomForest :  Losowe modele lasów

Będziemy używać pakietu rilba (który zależy od kodu C) do wydajnego obliczania części rozkładu wartości osobliwej (SVD) przy użyciu rozszerzonych niejawnie ponownie uruchomionych metod bidiagonalizacji Lanczosa, autorstwa Baglama i Reichel. Będziemy używać pakietu parallel do przetwarzania równoległego, ponieważ niektóre analizy tekstu mogą wymagać wielu obliczeń. Pakiet parallel jest obecnie najbardziej ogólnym pakietem zrównoleglania w języku R, ale zgłoszono, że nie działa poprawnie w niektórych systemach. Inne opcje to doParallel, doMC i do SNOW. Jeśli napotkasz problemy podczas używania jednego parallel, spróbuj przełączyć się na jeden z innych pakietów. Kod, który je uruchamia, jest bardzo podobny. Jeśli chodzi o dane tekstowe, istnieje kilka pakietów, których możesz użyć w R. Najpopularniejsze z nich to pakiet tm i pakiet quateda. Oba są doskonałe i różnią się głównie stylem. Wszystkie funkcje, które zobaczymy, mogą być używane z jednym z nich, ale zdecydowaliśmy się pracować z pakietem quanteda. Jest zbudowany z pakietem stringi do przetwarzania tekstu, pakietem data.table do dużych dokumentów i pakietem Matrix do obsługi rzadkich obiektów. Dlatego możesz oczekiwać, że będzie bardzo szybki i bardzo dobrze obsługiwał Unicode i UTF-8. Jeśli nie wiesz, czym są Unicode i UTF-8, proponuję zapoznać się z nimi. Z grubsza można myśleć o Unicode jako o standardzie identyfikatorów dla znaków, podczas gdy UTF-8 jest tłumaczeniem tych identyfikatorów na bajty, które komputery mogą zrozumieć. W tym rozdziale nie będziemy się martwić o kodowanie (wszystkie dane są w UTF-8), ale jest to coś, co często pojawia się podczas pracy z danymi tekstowymi i jest ważne, aby obsługiwać je poprawnie.

Zrozumienie recenzji za pomocą analizy tekstu

“Wspomóż rozwój naszego Bloga. Kliknij w Reklamę. Nic nie tracisz a zyskujesz  naszą wdzięczność … oraz lepsze, ciekawsze TEKSTY. Dziękujemy”

Powszechnie wiadomo, że bardzo duży procent istotnych informacji pochodzi z nieuporządkowanej formy, a ważnym graczem są dane tekstowe. Analiza tekstu, przetwarzanie języka naturalnego (NLP), wyszukiwanie informacji (IR) i uczenie statystyczne (SL) to niektóre obszary skoncentrowane na opracowywaniu technik i procesów radzenia sobie z tymi danymi. Te techniki i procesy odkrywają i prezentują wiedzę, fakty, reguły biznesowe, relacje, między innymi, które w innym przypadku są zamknięte w formie tekstowej, niedostępne dla automatycznego przetwarzania. Biorąc pod uwagę eksplozję danych tekstowych, którą obserwujemy obecnie, ważną umiejętnością dla analityków, takich jak statystycy i naukowcy zajmujący się danymi, jest umiejętność wydajnej pracy z tymi danymi i znajdowania spostrzeżeń, których szukają. W tej części postaramy się przewidzieć, czy klient dokona kolejnych zakupów, biorąc pod uwagę opinie przesłane do The Cake Factory. Ponieważ analiza tekstu to bardzo szeroki obszar badań, musimy zawęzić techniki, którym przyjrzymy się w tym rozdziale, do najważniejszych. Przyjmiemy podejście Pareto, skupiając się na 20% technik, które będą używane w 80% przypadków podczas wykonywania analizy tekstu.

 Niektóre z ważnych tematów omawianych są następujące:

* Macierze funkcji dokumentu jako podstawowa struktura danych

* Losowe lasy do modelowania predykcyjnego z danymi tekstowymi

* Termin dokumentacja częstotliwości odwrotnych częstotliwości do pomiaru ważności

* Modelowanie N-gramowe w celu przywrócenia porządku w analizie

* Rozkład wektorów osobliwych dla redukcji wymiarowości

* Podobieństwo cosinusowe w celu znalezienia podobnych wektorów cech

* Analiza nastrojów jako dodatkowa funkcja wektorowa

Interaktywna kula ziemska o wyrafinowanym wyglądzie

“Wspomóż rozwój naszego Bloga. Kliknij w Reklamę. Nic nie tracisz a zyskujesz  naszą wdzięczność … oraz lepsze, ciekawsze TEKSTY. Dziękujemy”

Aby zakończyć tą część, zbudujemy interaktywny globus o nowoczesnym wyglądzie, po którym będziesz mógł się poruszać i pokazywać znajomym. Tego typu wizualizacje zwykle nie są zbyt przydatne do analizy, ale są fajne!

Naszym celem jest pokazanie kuli ziemskiej, na której będą wyświetlane dane geograficzne pochodzące z wiadomości klientów, a także słupki, których wysokość reprezentuje PROFIT związane z każdą sprzedażą i kolory dla PROTEIN_SOURCE. Aby to osiągnąć, użyjemy pakietu threejs. Tak jak wcześniej, nasza funkcja graph_client_message_in_globe() otrzymuje dane client_messages i sales i konfiguruje je za pomocą funkcji setup_globe_data(). Następnie pobierze świat data za pomocą funkcji get_world_map_data() i dołącz go do ramki danych data za pomocą funkcji rbins.fill() z pakietu plyr. Ta funkcja przypomina funkcję R, rbind() ale nie będzie narzekać, jeśli kolumny nie będą zgodne. Zamiast tego wypełni puste wartości wskaźnikami brakujących danych. Na koniec zwracamy obiekt globusa z funkcją globejs(), która otrzymuje współrzędne w lat i long, wysokość słupka pod parametrem val, która pochodzi ze zmiennej PROFIT, color która pochodzi ze zmiennej COLOR utworzonej podczas konfiguracji danych (patrz poniższy przykład), a parametr atmosphere = TRUE pokazujący świecący efekt na całym świecie:

graph_client_messages_in_globe <- funtion(client_messages , sales) {

data <- setup_globe_data(client_messages, sales)

world_map <- get_world_map_data()

data <- rbind.fill(data, world_map_

return(globejs )

lat = data$LAT,

long = data$LNG,

val = data$PROFIT ^1.2,

color = data$COLOR,

pointsize = 1,

artmosphere = TRUE

))

}

Funkcja setuop_globe_data() wykonuje standardowe scalenie, które zrobiliśmy ze wszystkimi mapami i dodaje nową zmienną o nazwie COLOR, która zawiera kolory, które powinny być użyte dla każdej obserwacji. W przypadku pakietu ggplot2 to przypisanie koloru zostało zrobione za nas automatycznie, ale w pakiecie threejs musimy to zrobić sami. Będzie to po prostu inny kolor dla każdej wartości w zmiennej PROTEIN_SOURCE:

setup_globe_data <- function(lient_messages, sales) {

data <- merge (

clinet_messages,

sales,

„SALE_ID”,

all.x = TRUE,

all.y = FALSE

)

data$COLOR <- NA

data[data$PROTEIN_SOURCE ==”BEEF”, „COLOR”] <- „#aaff00”

data[data$PROTEIN_SOURCE ==”FISH, „COLOR”] <- „#00ffaa”

data[data$PROTEIN_SOURCE ==”CHICKEN”, „COLOR”] <- „#00aaff”

data[data$PROTEIN_SOURCE ==”VEGETARIA”, „COLOR”] <- „#0055ff”

return(data)

}

Funkcja get_world_mapdata() jest nieco skomplikowana. Jeśli nie rozumiesz, jak to działa, nie martw się zbytnio, ponieważ prawdopodobnie nie będziesz musiał tego robić samodzielnie. Nie możemy po prostu wykorzystać danych, których używaliśmy wcześniej do tworzenia map, które utworzyliśmy za pomocą funkcji map_data(), ponieważ wymagana struktura danych jest inna. W takim przypadku utworzymy plik tymczasowy o nazwie cache z funkcją tempfile(). Następnie odczytamy plik binarny pochodzący z adresu URL z funkcjami url() i readBi(). Plik jest plikiem TIFF, który otwieramy w formacie „raw”, aby zachować wszystkie dane w niezmienionej postaci i uniknąć jakiejkolwiek interpretacji danych w R. Parametr n to maksymalna liczba rekordów do odczytania z danych, która w tym przypadku wynosi 1 milion. Następnie wysyłamy te dane za pomocą funkcji writeBin(), aby zostały zapisane w pliku cache, który utworzyliśmy wcześniej. Ten mechanizm to sposób na pobranie niektórych danych tymczasowych, abyśmy mogli je wczytać do funkcji, która nie obsługuje odczytu z zasobów online. Gdy mamy gotowy plik tymczasowy, czytamy go funkcją readGDAL() z pakietu rgdal t, który odczyta go jako dane geograficzne. Konkretny format tych danych obejmuje długość i szerokość geograficzną oraz metrykę wysokości. Metryka wysokości służy do identyfikacji obszarów bez lądu (oceanów), które zawierają w tych danych wartość wyższą lub równą 255. Kontynuujemy usuwanie wszelkich wartości NA z danych i przypisywanie domyślnych wartości PROFIT  i COLOR. Zwróć uwagę, że tworzymy te wartości PROFIT i COLOR, aby ułatwić późniejsze scalanie danych. Używamy nazwy kolumny PROFIT dla metryki wysokości tylko dla wygody, ponieważ będziemy chcieli pokazać obszary geograficzne z niskimi słupkami i wiemy, że użyjemy PROFIT do wygenerowania wysokości dla każdego słupka:

get_world_map_data <- function () {

cache <- tempfile()

writeBin(readBin(url(

„http://illposed.net/nyr2015/MOD13A2_E_NDVI_2014-05025_rgb_360x180.TIFF”, open = „rb”),

what = „raw” ,  = 1e6), con – cache)

world_map <- readGDAL(cache)

world_map <- as.data.frame(cbind(coordinates(world_map),

world_map@data[,1]))

names(world_map) <- c(„LNG”, „LAT”, „PROFIT”)

world_map <- world_mp[world_map$PROFIT < 255,]

world_map <- na.exclude(world_map)

world_map$PROFIT <- 1

world_map$COLOR <- #0055ff”

retur(world_map)

}

Kiedy zainwestowaliśmy w tworzenie naszej funkcji wykresu, możemy tworzyć zaawansowane technicznie mapy, które pokazują lokalizację wiadomości otrzymywanych od naszych klientów, z paskami i kolorami wskazującymi powiązane PROFIT i PROTEIN_SOURCE odpowiednio dla każdej wiadomości. Zapraszam do poruszania się po świecie w przeglądarce internetowej:

graph_client_messages_in_globe(cliet_messages, sales)

To całkiem fajny efekt, prawda?

Poruszanie się po danych geograficznych za pomocą interaktywnych map

“Wspomóż rozwój naszego Bloga. Kliknij w Reklamę. Nic nie tracisz a zyskujesz  naszą wdzięczność … oraz lepsze, ciekawsze TEKSTY. Dziękujemy”

Po danych geograficznych możemy poruszać się za pomocą interaktywnych map, które wyjaśniono w kolejnych częściach.  Mapy, do których można nawigować i  które można powiększać  

W tej ostatniej sekcji stworzymy interaktywne mapy, po których możemy nawigować. To bardzo potężne narzędzie, które można osadzić w projektach języka R, znacznie zwiększając ich wartość i wpływ na odbiorców. Będziemy używać pakietu leaflet do tworzenia tej mapy. Naszym celem jest pokazanie mapy z lokalizacjami wiadomości, które otrzymujemy od naszych klientów z ikonami, które reprezentują typ oceny, jaką otrzymaliśmy za pomocą zmiennej STAR wiadomości i podpowiedzi, które pokazują PROFIT związane z odpowiednim zakupem każdej wiadomości. Nasza funkcja graph_client_messages_interactive() otrzymuje ramki danych client_messages i sales. Podobnie jak na poprzedniej mapie, wszystkie dane zostaną wyświetlone bez żadnych filtrów, więc to wszystko, czego potrzebujemy jako parametry. Pierwszą rzeczą, którą robimy, tak jak to zrobiliśmy wcześniej, jest scalanie danych, tak abyśmy zachowywali tylko obserwacje, które mają skojarzony komunikat. Następnie dodajemy nową zmienną do ramki danych data, która zawiera specyfikację ikony, która będzie używana przez leaflet. Aby to zrobić, używamy funkcji awesomeIcons() (jest częścią pakietu leaflet) i określamy funkcje używane do określenia ikony, koloru znacznika, i powiedzmy, że chcemy, aby nasze ikony były białe i pochodziły z biblioteki ikon ion (http://ioicons.com/). Inne dostępne biblioteki ikon to glyphicon (http://glyphicons.com/) i fa (fontawsome, http://fonrawsome.io/). Ikonę, której szukasz, możesz znaleźć w wymienionych witrynach internetowych. Na koniec zwracamy wykres ulotki, tworząc znaczniki  funkcją addAwesomeMarkers(), która otrzymuje obiekt ulotki utworzony z funkcją leaflet() owiniętą wokół naszego data, wzory na długości i szerokości geograficzne, wzór na ikony i wzór na etykiety. Opcjonalnie zawijamy wykres ulotki w addProviderTiles() , aby upewnić się, że w naszej przeglądarce internetowej otrzymamy kafelki (obrazy tła geograficznego). Potrzebujemy tego, ponieważ w chwili pisania tego tekstu istnieje błąd, który nie pokazuje danych geograficznych (tylko znaczniki) w określonych okolicznościach i chcemy uniknąć tego problemu, co możemy łatwo zrobić za pomocą wspomnianej techniki:

graph_client_messages_iteractive <- funtion(client_messages, sales) {

data <- merge(

client_messages,

sales,

„SALE_ID” ,

all.x = TRUE,

all.y = FALSE)

data$ICON <- awesomeIcons(

markerColor = get_icon_color(data),

icon = get_icon(data),

iconColor = ‘white’,

library = ‘io’

)

return(

addProviderTiles(addAwesomeMarkers (

leaflet(data),

~LNG, ~LAT,

ico = ~ICON,

labe; = ~paste(„Profit : „, PROFIT)

), providers$OpenStreetMap)

)

}

Teraz wyjaśnimy funkcje określające ikony i kolory znaczników. Funkcja get_ion_color() otrzyma naszą ramkę danych data i zwróci wektor z łańcuchem znaków, którym jest „green” lub ”red” , w zależności od tego, czy jest powiązany czy nie ze STARS ,gdzie jest większe lub równe 4, lub nie. Robimy to za pomocą funkcji sapply().

get_icon_color <- funtion(data) {

return(sapply(

as.numeric*(data$STARS),

function(stars) {

if (stars >= 4) {

return(„green”)

} else {

retur(„red”)

}

}

))

}

Funkcja get_icon jest bardzo podobna, ale zwróci nazwę żądanej ikony. Otrzymaliśmy te nazwy z witryny internetowej biblioteki ikon ion (wspomniana wcześniej):

get_icon_color <- funtion(data) {

return(sapply(

as.numeric*(data$STARS),

function(stars) {

if (stars >= 4) {

return(„ion-adroid-happy”)

} else {

return(„ion-android-sad”)

}

}

))

}

Teraz możemy łatwo tworzyć interaktywne mapy dla wiadomości naszych klientów przy użyciu następującego kodu. Otworzy przeglądarkę internetową i pokaże mapę, po której możesz się poruszać.

graph <- graph_lient_messages_interactive(client_messages, sales)

print(graph)

Początkowa pozycja mapy pokaże pełne dane geograficzne, jak pokazano na poniższym obrazku. Jak widać, znaczniki zawierają radosną lub smutną twarz, w zależności od oceny, jaką miała każda wiadomość. Ponadto kolor znacznika jest zielony lub czerwony, ponownie w zależności od oceny.

Powiększoną wersję interaktywnej mapy można zobaczyć na poniższym obrazku. W zależności od dostawcy, którego wybierzesz w funkcji addProviderTiles(), otrzymasz różne typy obrazów geograficznych

Przeglądanie danych geograficznych na statycznych mapach

“Wspomóż rozwój naszego Bloga. Kliknij w Reklamę. Nic nie tracisz a zyskujesz  naszą wdzięczność … oraz lepsze, ciekawsze TEKSTY. Dziękujemy”

Mapy mogą być bardzo przydatnymi narzędziami do zrozumienia danych geograficznych. W tej sekcji stworzymy mapę z pakietem ggplot2. Celem jest pokazanie lokalizacji wiadomości naszych klientów, PRICE związanych z ich zakupami i odpowiednich PROFIT_RATIO. Ten przykład pokaże nam, jak połączyć dane z ramek danych sales i cliet_messages.

Nasza funkcja graph_lient_messages_static() otrzymuje jako parametry  client_messages i sales ramek danych, a to wszystko, czego potrzebuje, ponieważ pokazujemy niefiltrowane (pełne) zestawy danych. Najpierw musimy połączyć nasze dwie ramki danych za pomocą wspólnego identyfikatora, którym jest SALE_ID. W tym celu używamy funkcjimerge() i określamy, że chcemy zachować wszystkie obserwacje w ramce danych x, która jest pierwsza (client_messages) i nie chcemy zachowywać obserwacji z  ramki danych y, czyli drugiej (sales), jeśli nie mają odpowiedniego identyfikatora w pierwszej ramce danych. Dzięki temu możemy zachować tylko te dane, z którymi są skojarzone wiadomości klientów. Następnie tworzymy dane geograficzne mapy z map_data() (jest w pakiecie ggplot2) i filtrujemy je, aby usunąć dowolny region oznaczony jako „ANTARCTICA”. Aby właściwie utworzyć wykres, użyjemy dwóch głównych warstw. Pierwszą z nich są dane geograficzne, które dodaje się funkcją geom_polygo(), wykorzystując dane world_map, określając współrzędne i grupy (grupy definiują krajów) i użyj ciemnych kolorów, aby kontrastować z naszymi kropkami. Druga warstwa to dane wiadomości, które są dodawane za pomocą funkcji geom_point(), używając scalonej ramki danych data, z odpowiednimi współrzędnymi i dodając kolory i rozmiary za pomocą PRICE  i PROFIT_RATIO odpowiednio. Ponieważ w tym przykładzie używamy zmiennej numerycznej do określenia koloru, otrzymamy gradient kolorów zamiast dyskretnych kolorów, jak w poprzednich przykładach. Na koniec określamy rzeczywistą paletę kolorów za pomocą funkcji scale_color_viridis() ustawiamy odpowiednie etykiety osi i sprawiamy, że współrzędne mają równe jednostki za pomocą  funkcji coord_fixed(). Jeśli nie użyjemy tej ostatniej funkcji, możemy uzyskać mapy, które są zdeformowane:

graph_liet_messages_static <- function(cliet_messages, sales) {

data <-merge(

client_message, sales,

„SALE_ID” , all.x = TRUE,

all.y = FALSE

)

world_map <- filter(map_data(„world), region != „Antarctica”)

return(

ggplot() +

geom_polygon(

data = world_map,

aes(long, lat, group = group),

color + „grey60”,

fill = „grey50”

)+

geom_point(

data = data,

aes(LNG, LAT, color = PRICE, size = PROFIT__RATIO)

)+

scale_color_viridis(option = „inferno”) +

ylab(„Latitude”) +

xab(„Logitude”) +

oord_fixed()

)

}

Teraz możemy tworzyć nasze mapy za pomocą następującego wywołania funkcji:

graph_client_messages_static(client_messages, sales)

W ten sposób otrzymasz następujący wykres:

Oczywiście, jeśli chcesz uogólnić tę funkcję, możesz sparametryzować niektóre zmienne używane do specyfikacji wykresu, tak jak to zrobiliśmy w poprzednich przykładach

Przeglądanie danych dynamicznych z szeregami czasowymi

“Wspomóż rozwój naszego Bloga. Kliknij w Reklamę. Nic nie tracisz a zyskujesz  naszą wdzięczność … oraz lepsze, ciekawsze TEKSTY. Dziękujemy”

Teraz skupimy się na innym bardzo popularnym typie wykresu: szeregach czasowych. Naszym celem jest zrozumienie, jak zachowują się nasze dane w ciągu ostatnich 􀁏 dni i, tak jak to zrobiliśmy wcześniej, chcemy dalej zdezagregować za pomocą kolorów, jak pokazuje poniższy wykres:

Jeśli przeczytałeś do tego momentu, powinieneś być w stanie zrozumieć większość z tego, co robi funkcja. Jedyną nową funkcją jest sale_dx_date() To nam pozwala określ formaty daty dla znaczników osi inne niż domyślne. W tym przypadku chcemy użyć podziału na dzień (tak jak to zrobiliśmy w niektórych przykładach wcześniej), ale chcemy mieć format na przykład etykiety  podobny do July, 30, 2017 r. W tym celu korzystamy z formatów dat wspomnianych w poprzedniej sekcji i wysyłamy żądaną strukturę ciągu do parametru date_label:

graph_last_n_days <- function(data, n, y = NULL, color = NULL) {

subset <- filter_n_days_back(data, )

days_range <- paste(„(last „, n . „ days) „ , sep = „ „

date_sequence <- seq(min(subset[,  „DATE”]),

max(subset{, „DATE”]), by = „day”

if (is.null(y) {

graph <= ggplot(subset, aes_strig(x = „DATE”, color = color)) +

ggtitle(paste(„Frequency”, days_range)) +

geom_point(stat = „count” , size = 3) +

geom_line(stat = „count” , size = 1)

} else {

aggregation <- get_aggregatio(y)

graph <- ggplot(subset, aes_string (

x = „DATE”,

 y = y,

color = color)) +

ggtitle(paste(y, days_range)) + geom_point(

fun.y = aggregation,

stat = „summary” , size = 3) +

geom_lie (

fun.y = aggregation,

stat = „summary”, size = 1)

}

graph <- graph +

ylab(y)+

scale_x_date (

breaks = date_sequece,

date_labels = :%B %d , %Y”

)

return(graph)

PROFIT lub PROFIT_RATIO z ostatnich 30 dni, możesz użyć następującego kodu. Nie pokazujemy tych obrazów, aby zaoszczędzić miejsce:

graph_last_n_days(sales, 30)

graph_last_n_days(sales, 30, „PROFIT”)

graph_last_n_days(sales, 30 , „PROFIT_RATIO”)

Aby spojrzeć na wykresy liniowe częstotliwości, PROFIT i PROFIT_RATIO, to odróżnia

PROTEI_SOURCE z kolorami możesz użyć następującego kodu:

graph_last_n_days(sales, 30, color = “PROTEIN_SOURCE”)

graph_last_n_days(sales, 30, „PROFIT”, “PROTEIN_SOURCE”)

graph_last_n_days(sales, 30 , „PROFIT_RATIO”, “PROTEIN_SOURCE”)

Funkcji graph_last_n_days można używać z innymi ramkami danych. Na przykład, na wykresie STARS ocen z ostatnich 30 dni pochodzących z client_messages, wystarczy przekształcić zmienną kategorialną STARS na wartość liczbową zmienna z funkcją as.numeric, aby nie otrzymywać błędów z powodu niezgodności typów, i wywołaj tę funkcję.

Jeśli nie określisz zmiennej do zdezagregowania za pomocą kolorów, domyślnie wyświetli się wykres z czarnym:

aux <- client_messages

aux$STARA <- as.numeri(aux$STARS)

graph_last_n_days(aux, 30, „STARS”)

Eksploracja za pomocą interaktywnych wykresów punktowych 3D

“Wspomóż rozwój naszego Bloga. Kliknij w Reklamę. Nic nie tracisz a zyskujesz  naszą wdzięczność … oraz lepsze, ciekawsze TEKSTY. Dziękujemy”

Podczas eksploracji danych czasami warto przyjrzeć się wykresowi punktowemu 3D. Jeśli jednak wykres punktowy jest ustalony (co oznacza, że ​​nie można go przesuwać), interpretacja może nie być łatwa. W takich przypadkach bardzo przydatne jest posiadanie interaktywnego wykresu (po którym można się poruszać), aby zobaczyć dane pod różnymi kątami. Te wykresy zwykle nie są uwzględniane w statycznych raportach, ponieważ są trudne do poprawnej interpretacji po naprawieniu, ale są bardzo przydatne do eksploracji danych. Na szczęście są one również bardzo łatwe do stworzenia za pomocą funkcji plot3d() z  pakietem rgl:

library(rgl)

plot3d(sales$PROTEIN, sales$CARBS, sales$FAT)

plot3d(sales$PROFIT_RATIO, sales$PRICE, sales$QUANTITY)

Po utworzeniu tych wykresów w komputerze pamiętaj, aby przesuwać je za pomocą myszy! Za pierwszym razem jest to niesamowite. W tym przypadku możesz zobaczyć dwa zjawiska, które występują w danych sales. Po pierwsze, procenty makroskładników odżywczych należy dodać do jednego, a ponieważ są ich trzy, to, co zobaczysz na wykresie po lewej stronie, jest kształtem trójkąta w taki sposób, że suma współrzędnych każdego punktu w nim jest równa jeden . Po drugie, wykres po prawej stronie przedstawia zależność między PRICE, QUANTITY i PROFIT_RATIO. Pokazuje, że w naszych danych sprzedażowych nie ma ilości ułamkowych (tak jak to zaprojektowaliśmy), że jest dużo zamówień z zerami PROFIT_RATIO, ponieważ nie są one zrealizowane ani opłacone, i że im wyższe jest PRICE, tym wyższe jest PROFIT_RATIO.

Nie ma nic więcej do wyjaśnienia na temat tych wykresów. Są proste w tworzeniu, mają prosty cel, który czasami może być bardzo przydatny, ale zwykle nie zobaczysz ich w pisemnych raportach.

Opracowanie własnego typu wykresu – wykresów radarowych

“Wspomóż rozwój naszego Bloga. Kliknij w Reklamę. Nic nie tracisz a zyskujesz  naszą wdzięczność … oraz lepsze, ciekawsze TEKSTY. Dziękujemy”

Ta sekcja przeniesie nasze funkcje wykresów na wyższy poziom, ponieważ opracowujemy własny niestandardowy typ wykresu. Pakiet ggplot2 nie ma domyślnie możliwości tworzenia wykresów radarowych, więc opracujemy go sami w tej sekcji. Istnieją pakiety, które rozszerzają ggplot2 o możliwości wykresu radarowego (na przykład ggradar), ale pokażemy, jak stworzyć go samodzielnie od podstaw. Po przeczytaniu tej sekcji będziesz przygotowany do samodzielnego tworzenia złożonych wykresów.

Wykresy radarowe są nanoszone na kołowym obszarze roboczym i mogą pokazywać jednocześnie wiele wartości zmiennych. Tworzą kształt przypominający radar i są przydatne, jeśli chcesz porównać różne wartości zmiennych między różnymi obiektami. Czasami są one używane do wizualnego zrozumienia jak podobne lub różne są byty. Jeśli nie jesteś zaznajomiony z tego typu wykresami, na poniższej ilustracji pokazano jeden. W naszym przykładzie, zamiast mierzyć prędkość, trwałość, komfort, moc i przestrzeń, jak w tym przykładzie, zmierzymy trzy różne makroskładniki odżywcze dla pięciu największych klientów The Food Factory.

Funkcja grpah_radar() otrzymuje jako parametry ramkę danych data i zmienną, za pomocą której chcemy wyświetlać radary (w naszym przypadku CLIENT_ID). Po pierwsze, przekształca dane, których potrzebujemy, z formatu szerokiego na długi za pomocą funkcji gather(). Następnie tworzy etykiety, które będą używane na górze każdego wykresu radarowego, które pokazują zysk generowany przez każdy CLIENT_ID. Na koniec zwraca obiekt wykresu, który jest tworzony przez określenie makroskładników i wartości procentowych, dodanie grup warstw wielokątów, kolorów i wypełnień za pomocą CLIENT_ID oraz dostosowanie alpha (przezroczystość) i rozmiar linii, aby dobrze wyglądały.

Funkcja facet_wrap() służy do powtarzania tego samego wykresu dla każdego wystąpienia zmieej by w danych (w naszym przypadku CLIENT_ID). Ponieważ wymaga formuły, a my chcemy uogólniamy jego użycie, używamy kombinacji funkcji as.formula() i paste(). My także przekazujemy parametr nrow=1, aby mieć pewność, że otrzymamy pojedynczy wiersz wykresów. Usuwamy dowolne informacje legendy z funkcją guides(), wysyłając ciąg „none” do odpowiedniej legendy, zastosuj naszą funkcję coord_radar() i usuń etykiety osi:

grpah_radar <-  function(datat, by) {

data <- tidyr :: gather(

datat, MARO, PERVCENTAGE, PROTEIN: FAT, factor_key  TRUE)

datat$CLIENT_ID <- paste(

data$CLIENT_ID, „ ($”, data$PROFIT, „)” , sep = „ „

)

Return(

ggplot(data, aes (MACRO, PERCENTAGE)) +

geom_polygon(

aes_string(group = by , color = by, fill = by),

alpha = 0.4,

size = 2

) +

faet+wrap(as.formula(paste(„~”, by)) , nrow = 1) +

guides(color = „none”, fill = „none”) +

coord_radar() +

xlab(„”)+

ylab(„”)

)

}

Funkcja coord_radar() nie jest funkcją wbudowaną w pakiecie ggplot i musimy ją sami zaprogramować. Wersja, z którą będziemy tutaj pracować, jest nieco zmodyfikowaną wersją coord_radar() znalezionego w Internecie, przypisanego najpierw Hadleyowi Wickhamowi. Wykorzystuje funkcję ggproto() do dziedziczenia i modyfikacji warstwy współrzędnych biegunowych w ggplot2, która otrzymuje parametry theta (kąt), r (promień), start (punkt początkowy), direction (czy używać jednostek dodatnich, czy ujemnych) i hack, który zwraca funkcję wymaganą przez parametr is_liear, tak aby jego wartość zawsze była TRUE. Gdybyśmy nie wysłali tego ostatniego hacka, otrzymalibyśmy okrągłe kształty, tak jak robimy to ze współrzędnymi biegunowymi podczas próby wykreślenia linii prostej. Poprzedni kod po prostu wybiera odpowiednią oś dla kąta, aby uzyskać kształt radaru:

coord_radar() <- function(theta = „x”, start = 0, diection =1 ) {

if (theta ==”x”) {

r <- „y”

} else {

r <- „x”

}

return (ggproto(

„CordRadar”,

CoordPolar,

theta = theta,

r=r,

start = start,

direction = sign(direction),

is_linear = function(coord) { return (TRUE) }

))

}

Funkcja ggproto() jest używana jako wewnętrzny system obiektów w pakiecie ggplot2 i została opracowana, aby uniknąć konieczności zmiany zbyt dużej części kodu podczas implementowania obiektów warstwowych. Nie zaleca się używania go, chyba że jest to absolutnie konieczne. Teraz, gdy mamy gotową funkcję wykresu, musimy się upewnić, że nasze dane są gotowe i poprawnie sformatowany. Aby to zrobić, tworzymy funkcję  filter_datat() to, która filtruje dane i tworzy oczekiwaną strukturę. Funkcja otrzymuje jako parametry data, którego użyjemy, liczbę dni wstecz od bieżącej daty jako n_days, liczbę najlepszych wykonawców, które pokażemy jako n_top, oraz zmienną będziemy agregować przez aggregate_by.

Najpierw filtrujemy dane n dni wstecz, a następnie zachowujemy obserwacje tylko dla n_top wykonawców zgodnie ze zmienną aggregate_by .Gdy to robimy, odpowiednio aktualizujemy data. Następnie agregujemy dane dwukrotnie, raz o PRoFIT, a drugi raz o makroskładniki odżywcze (PROTEIN, CARBS i FAT) i odzyskujemy nazwę CLIENT_ID do ramki danych. W ten sposób powstają dwie ramki danych, aggr_profit i aggr_macros, z których każda agreguje odpowiednie zmienne dla każdej unikalnej CLIET_ID . Zauważ, że dzielimy ten proces na dwie niezależne części, ponieważ chcemy połączyć PROTEIN, ARBS i FAT z mean, aby uzyskać średnią preferencję dla każdego CLIENT_ID, ale jednocześnie chcemy zagregować PROFIT  z sum, aby uzyskać całkowity zysk (a nie średni zysk) dla każdego CLIENT_ID. Na koniec łączymy dane z funkcją merge(), używając naszej zmiennej aggregate_by aby być indeksem, za pomocą którego łączymy dane, usuwamy kolumny reszt z ramki danych i zamów przez PROFIT:

filter_data <- function(data, n_days, _top, aggregate_by, static = TRUE) {

data <- filter_n_days_back(datat, n_days)

data <- filter_n_top(data, n_top, aggregate_by)

if (static) {

aggr_profit <_ aggregate (

data[, c(„PROFIT”, „PROFIT_RATIO”)],

list(data[, aggregate_by]),

sum

)

aggr_profit$CLIENT_ID <- aggr_profit$GROUP.1

aggr_macros <- aggregate(

data[, c(„PROTEI”, „CARBS”, „FAT”)].

list(data[, aggregate_by]),

mean

)

aggr_macrso$CLIENT_ID <- aggr_macros$Group.1

data<- merge(aggr_profit, aggr>maros, by = aggregate_by)

drop_columns <- c(„Group.1.x”, „Group.1.y”, „PROFIT_RATIO”)

data <- datat[, !(names(data) %i% drop_olumns0}

data <- data[order(-datat%PROFIT), ]

}

return(data)

}

Jeśli uważnie czytasz kod, być może zauważyłeś szczegół, o którym nie wspomnieliśmy, użycie zmiennej PROFIT_RATIO w agregacji, nawet jeśli nie używamy jej później w funkcji . Przyczyną włączenia PROFIT_RATIO do obliczeń aggregate() jest efekt uboczny, jaki wywołuje. Podczas określania dwóch lub więcej zmiennych w danych dla funkcji aggregate(), wynik wraca z rzeczywistymi nazwami kolumn ramki danych w wynikowej ramce danych aggr_profit. Jeśli określimy tylko PROFIT samodzielnie, wynik będzie miał kolumnę o nazwie x zamiast PROFIT, jak widzieliśmy i używaliśmy w poprzednim kodzie w. Jest to łatwy sposób na uniknięcie zmiany nazw zmiennych. Moim zdaniem funkcja aggregate() powinna zawsze zwracać oryginalne nazwy ramek danych, ale tak nie jest, więc musimy to obejść. Pamiętaj o tej użyteczności podczas programowania dla innych. Aby zobaczyć, jak faktycznie filtrujemy daty, zajrzyj do funkcji filter_n_days)back(). Jak widać, jako parametr otrzymujemy data, który chcemy przefiltrować, oraz liczbę dni, które chcemy zachować wstecz jako n. Jeśli n jest NULL, co oznacza, że ​​użytkownik nie chciał filtrować danych wstecz, to po prostu zwracamy to samo data, które otrzymaliśmy. Jeśli otrzymasz liczbę w ciągu n, otrzymamy aktualną datę i odejmiemy od niej 􀁏 dni za pomocą Sys_Date()-n To proste odejmowanie odbywa się automatycznie z dniami jako jednostkami dzięki technice zwanej przeciążaniem operatora. Na koniec po prostu zachowujemy te daty, które są co najmniej datą n_days_back (kolejne użycie techniki przeciążania operatorów, która pozwala nam porównywać daty). Funkcja filter_n_top() to ta, którą utworzyliśmy wcześniej dla kodu wykresów pudełkowych:

filter_n_days_bak <- function(data,) {

if (is.null(n)) {

return(datat)

}

n_days_baks <- SYs.Date() –

return(data[data[, „DATE”] .= n_days_back, ])

}

Nasza funkcja filter_data() jest sama w sobie bardzo przydatna. Na przykład możemy łatwo pokazać średnie makroskładniki odżywcze dla 5 najlepszych klientów w ciągu ostatnich 30 dni, wykonując:

filter_data(sales, 30, 5, „CLIENT_ID”)

#> CLIENT_ID PROFIT PROTEIN CARBS FAT

#> 2 BAWHQ69720 74,298 0,3855850 0,3050690 0,3093460

#> 3 CFWSY56410 73,378 0,4732115 0,3460788 0,1807097

#> 4 CQNQB52245 61,468 0,1544217 0,3274938 0,5180846

#> 1 AHTSR81362 58,252 0,3301151 0,3326516 0,3372332

#> 5 VJAQG30905 53,104 0,2056474 0,5909554 0,2033972

Po zainwestowaniu w stworzenie odpowiedniej funkcji wykresu jesteśmy teraz w stanie łatwo tworzyć własne wykresy radarowe. Na przykład możemy łatwo utworzyć odpowiedni wykres radarowy dla danych, które właśnie pokazaliśmy wcześniej, za pomocą:

graph_radar(filter_data(sales, 30, 5, „CLIENT_ID”), „CLIENT_ID”)

Poniższy obraz przedstawia poprzednie polecenie: