Cel programowania obiektowego

Głównym celem programowania obiektowego jest efektywne zarządzanie złożonością. Jest to sposób organizowania kodu i danych w taki sposób, aby można było tworzyć dobrze rozgraniczone abstrakcje z kontrolowanymi zależnościami, aby rozwinąć złożony system w kontrolowany sposób. Te abstrakcje nazywane są obiektami i oferują zachowanie w odpowiedzi na wiadomości. Zachowanie, które oferują innym obiektom, jest katalogowane w interfejsie, który jest zaimplementowany w metodach publicznych tego obiektu. Obiekty żądają zachowania od innych obiektów, a kiedy to robią, mówi się, że są od nich zależne. Komunikaty przesyłane między wszystkimi tymi obiektami i związane z nimi zachowanie sprawiają, że system obiektowy jest użyteczny. Zanim przejdziemy dalej, wyjaśnijmy więcej na temat tych pojęć. Obiekt jest bytem w abstrakcyjnej formie. Na przykład liczby całkowite, samochody, psy, budynki, karty kredytowe i kryptowaluty mogą być obiektami w systemie obiektowym. Obiekt jest dobrze zdefiniowaną ideą czegoś i wiemy, że różne rodzaje obiektów mają różne rodzaje zachowań, które się z nimi wiążą, a niektóre z tych zachowań wymagają pewnych danych, które zwykle są przechowywane w obiekcie. Na przykład idea liczby całkowitej nie jest powiązana z żadną określoną liczbą, tak jak idea samochodu nie jest powiązana z żadnym konkretnym modelem ani marką. Osoby zaznajomione ze statystyką mogą pomyśleć o zmiennej losowej jako o obiekcie, a realizację tej zmiennej losowej jako o instancji. Programowanie zorientowane obiektowo to sposób myślenia o programach jako o interakcjach między obiektami, a nie o krokach przez algorytm. Nadal można rozumieć system obiektowy jako duży algorytm z wieloma wywołującymi się sobą funkcjami, ale dla wystarczająco dużych systemów nie będzie to owocny ani przyjemny proces. W przypadku systemów zorientowanych obiektowo lepiej jest po prostu spróbować zrozumieć część systemu samodzielnie i jasno określić, w jaki sposób powinien się on komunikować z innymi częściami. Próba pełnego zrozumienia złożonego systemu zorientowanego obiektowo może okazać się nie lada wyzwaniem.

Krótkie wprowadzenie do programowania obiektowego

Jako statystycy i naukowcy zajmujący się danymi staramy się tworzyć systemy, które dostarczają cennych informacji. Aby to osiągnąć, zwykle używamy dwóch narzędzi – matematyki i komputerów. Zwykle, gdy ludzie z matematycznym doświadczeniem są wprowadzani do programowania, są wprowadzani poprzez podejście funkcjonalne, co oznacza, że ​​myślą w kategoriach algorytmów z wejściami i wyjściami, które są implementowane jako funkcje. Ten sposób pracy jest intuicyjny, jeśli wywodzisz się z matematyki i nie masz do czynienia z abstrakcjami wysokiego poziomu, i to jest sposób, w jaki pracowaliśmy do tej pory w całej książce. Ta sekcja pokaże inny sposób programowania zwany programowaniem obiektowym. Programowanie obiektowe i model obiektowy to potężne i jednoczące idee w wielu dziedzinach, które można znaleźć w większości popularnych języków programowania, przy czym R nie jest wyjątkiem. Z mojego doświadczenia wynika, że ​​ludzie, którzy nie mieli świadomego doświadczenia z programowaniem obiektowym, zwykle uważają, że jest to zagmatwane i nie rozumieją jego potencjału. Uważają, że jest to bardziej kłopotliwe niż ułatwienie i myślą, że przeszkadza im to podczas pisania kodu. W tym rozdziale postaramy się wydestylować paradygmat obiektowy w sposób zrozumiały dla osób, które czują się komfortowo z podejściem funkcjonalnym (niekoniecznie z programowaniem funkcjonalnym), a także pokażemy, jak wdrożyć mały obiektowy system, który stale pobiera dane na żywo z rynków kryptowalut i portfeli. Zanim zaczniemy wdrażać taki system, musimy wprowadzić koncepcje, które będą używane w dalszej części przykładu, w tym w dwóch kolejnych rozdziałach. W kolejnych akapitach znajdziesz bardzo ogólne opisy pojęć stojących za modelem obiektowym, który jest zaimplementowany w programowaniu obiektowym, a także wyjaśnienia, które, miejmy nadzieję, przekonają Cię, że ten sposób programowania może być bardzo skuteczny w przypadku niektórych problemów.

Przykład kryptowalut

Kryptowaluta to cyfrowa waluta zaprojektowana do pracy jako środek wymiany. Kryptowaluty wykorzystują kryptografię do zabezpieczania i weryfikacji transakcji, a także do kontrolowania tworzenia nowych jednostek. Mówiąc najprościej, kryptowaluty to wpisy w publicznej i rozproszonej bazie danych, które można zmienić tylko na podstawie konsensusu algorytmicznego, i eliminują one potrzebę korzystania z zaufanych stron trzecich do obsługi transakcji i emisji waluty. Koncepcja bardzo przypomina sieci peer-to-peer do udostępniania plików, z algorytmiczną polityką pieniężną na czele. Jeśli chcesz dowiedzieć się więcej o kryptowalutach, zdecydowanie powinieneś obejrzeć filmy z udziałem Andreasa Antonopoulosa. Potrafi bardzo łatwo zrozumieć bardzo złożone koncepcje. Kryptowaluty są obecnie intensywnie rozwijane, aby oferować wiele innowacyjnych funkcji które będą miały destrukcyjny wpływ w nadchodzących latach, ale na razie są one głównie wykorzystywane do kupowania towarów i inwestowania. Każda transakcja składa się z ilości przekazanych monet oraz kluczy publicznych nadawcy i odbiorcy, zwanych również adresami portfela. Użyjemy tych kluczy publicznych w przykładzie dla tego rozdziału, aby śledzić, ile monet posiadamy, a także użyjemy API CoinMarketCap do śledzenia cen kryptowalut. Ponieważ będzie to złożony system, użyjemy programowania obiektowego, aby go modularyzować i zbudować część po części. Pod koniec przykładu będziemy mieli system, który można włączyć, aby rozpocząć śledzenie naszych aktywów kryptowalutowych, a także ich cen oraz zapisać dane w czasie rzeczywistym na dysku w celu późniejszej analizy. Później wykorzystamy te dane, w formie symulowanej, do opracowania różnych implementacji prostej średniej ruchomej (SMA), aby pokazać, jak można ulepszyć kod R, aby stał się szybszy i bardziej czytelny. Na koniec zobaczymy, jak stworzyć nowoczesną aplikację internetową, aby pokazać opracowane SMA, a także zebrane dane.

Zorientowany obiektowo system do śledzenia kryptowalut

Przedstawimy nowy sposób programowania, którego nie używaliśmy wcześniej. Nazywa się to programowaniem obiektowym i będzie używane w naszym trzecim i ostatnim przykładzie. Programowanie zorientowane obiektowo jest bardzo popularne wśród programistów i służy głównie do modelowania i implementacji złożonych relacji abstrakcji w taki sposób, aby ewolucja systemu nie była zagrożona. Tworząc systemy obiektowe i ogólnie, gdy programujemy, powinniśmy dążyć do prostoty, ale nie przychodzi to naturalnie. Mając do czynienia ze złożoną domeną, łatwiej jest stworzyć złożony niż prosty kod. Programiści muszą dołożyć wszelkich starań, aby stworzyć prosty kod, ponieważ prostota zależy głównie od programisty, a nie od języka. W tym rozdziale pokażemy, jak efektywnie pracować z kodem zorientowanym obiektowo, przedstawiając idee i koncepcje, które go wspierają, a później zilustrujemy, jak go zaimplementować przy użyciu trzech najczęściej używanych modeli obiektowych języka R. R ma różne modele obiektowe lub systemy zorientowane obiektowo, więc na początku może być nieco onieśmielające. Celem nie jest uczynienie cię ekspertem w programowaniu obiektowym lub w każdym z modeli obiektowych języka R, ale pomoc w zrozumieniu, jak zaimplementować podstawowe elementy składowe programów obiektowych z różnymi modelami obiektowymi języka R. Niektóre z ważnych tematów omówionych  to:

* Podstawowe koncepcje programowania obiektowego

* Projektowanie i architektura systemów obiektowych

* Parametryczny polimorfizm R poprzez funkcje ogólne

* Różne modele obiektów dostępne dla R.

* Funkcjonalność mieszania z różnych modeli obiektów R.

Wymagane pakiety w tym rozdziale

Zostaną wykorzystane metody, i pakiety R6 w celu załadowania funkcjonalności modeli obiektowych S4 i R6. Powinieneś wiedzieć, że interaktywne sesje języka R ładują domyślnie metody, ale sesje nieinteraktywne nie, więc w takich przypadkach musisz jawnie załadować je. Pakiety jsonlite i lubridate zostały wprowadzone w celu uproszczenia niektórych typowych zadań, takich jak pobieranie danych z interfejsów API JSON i przekształcanie dat.

R6 : Model obiektowy R6

S4 : metody model obiektowy S4

lubridate: łatwo zmieniaj daty

jsonlite: pobieranie danych z interfejsów API JSON

Tworzenie naszej prezentacji z R Markdown

W tej sekcji rozwiniemy plik R Markdown naszej prezentacji. Tworzymy pusty plik o nazwie presentation.R i umieszczamy następujące nagłówki. Cudzysłowy nie są wymagane, chyba że chcesz dołączyć dwukropek w tytule. Jak pokazano w poprzedniej sekcji, używając lewych apostrofów („ ‘), możemy wykonać kod R. W takim przypadku aktualną datę umieszczamy automatycznie na pierwszej stronie. Na koniec wybraliśmy ioslides_presentation jako format wyjściowy. Zapraszam do eksperymentowania z innymi wynikami pokazanymi wcześniej:

title : „The Food Factory”

author : „Weekly Update”

date :  „ r Sys.Date() ` „

output : ioslides_presentation

Poniższy kod konfiguruje domyślną konfigurację fragmentów kodu w naszej prezentacji. Unikamy pokazywania kodu w prezentacji za pomocą echo = FALSE i sprawiamy, że każdy obraz ma pełną szerokość, chyba że podano inaczej za pomocą out.width = ‘100%’:

“` {r setup, include = FALSE}

knitr ::opts_chunk$set(echo = FALSE, out.width = ‘100%’)

“`

Teraz musimy zebrać wszystkie zasoby, których potrzebujemy, aby nasza prezentacja działała. W szczególności musimy załadować funkcje, które opracowaliśmy wcześniej. Załaduj dane sales i client_messages i zastosuj tę samą transformację, którą widzieliśmy poprzednio, aby skonfigurować dane. Zwróć uwagę, że  odnosiliśmy się do danych sprzedaży jako all_time zamiast sales, a aby uniknąć zmiany naszego kodu, abyśmy mogli nadal łatwo odwoływać się do naszych plików programistycznych, po prostu kopiujemy sales do obiektu all_time. Zachowaj ostrożność, jeśli masz duże ograniczenia pamięci w systemie:

“`{r load-fuctions-and-data, include=FALSE}

source(„../functions.R”)

sales <- readRDS(„../../results/sales.rds”)

cliet_messages <- readRDS(„../../results/clinet_messages.rds)

sales <- add_profits(sales)

all_time <- sales

max_date <- max(all_time$DATE)

this_week <- filter_n_days_back(all_time, 7, max_date)

last_week <- filter__n_days_back(all_time, 7, max_date – 7)

quatity_all <- proportions_table(all_time, „QUANTITY”)

continent_all <- proportions_table(all_time, „CONTINENT”)

protein_all <- proportions_table(all_time, „PROTEIN_SOURCE”)

quatity_last<- proportions_table(last_week, „QUANTITY”)

continent_last <- proportions_table(last_week, „CONTINENT”)

protein_last <- proportions_table(last_week, „PROTEIN_SOURCE”)

quatity_this <- proportions_table(this_week, „QUANTITY”)

continent_this <- proportions_table(this_week, „CONTINENT”)

protein_this <- proportions_table(this_week, „PROTEIN_SOURCE”)

Teraz, gdy nasze zasoby zostały skonfigurowane, możemy pracować nad kodem, który faktycznie pokaże naszą analizę w prezentacji. Zaczynamy od slajdów, które wykorzystują funkcje opracowane wcześniej, aby pokazać zmiany za pomocą pasków i linii. Zwróć uwagę, że w każdym przypadku określamy różne wysokości dla wykresów słupkowych i liniowych. Zwróć też uwagę, że w przypadku wykresów liniowych używamy szerokości 50%. To dlatego, że chcemy, aby były wyświetlane pionowo na slajdzie. 50% szerokość przy wysokości 10 zapewnia taki rozkład. W rzeczywistości możesz chcieć wybrać lepsze tytuły dla każdego slajdu, ale w tym przykładzie pozostaną one oczywiste. Zauważ, że pracując w ten sposób, unikamy umieszczania jakiegokolwiek kodu logicznego na naszych slajdach, a po prostu czytając tytuły funkcji, wiemy dokładnie, co zostanie pokazane. Pozwala to na łatwe przenoszenie rzeczy bez rozbijania ich z powodu zależności między fragmentami kodu, ponieważ wyodrębniliśmy to w oddzielnych plikach. Jeśli wypełnisz pliki prezentacji logiką R, szybko przekonasz się, że jest to bardzo zagmatwane, gdy trzeba je zmienić. Lepiej jest mieć tę logikę w rzeczywistym pliku .R, tak jak robimy to z naszym plikiem function.R. Nie wspominając już o tym, że jest również znacznie bardziej wielokrotnego użytku w ten sposób:

## Changes in  quantity (1/2)

“` {r quantity-bars, fig.height = 2.5 }

difference_bars_absolute(quantity_last, quatity_this, „This week”, „Last week”)

difference_bars_absolute(quantity_all, quantity_thi, „This week”, „All-time”)

“`

## Changes in quantity (2/2)

“` {r quantity-lines, out.width = ‘50%’, fig.height = 10}

change_lines(quantity_last, quantity_this, „This week”, „Last week”, 0.2)

chage_lines(quantity_all, quantity_this, „This week”, „All-time”, 0.2)

“`

## Changes in continent (1/2)

“`{r cotinet-bars, fig.height = 2.5}

difference_bars_absolute(continet_last, continet_this, „This week”, „Last week”)

difference_bars_absolute(continent_all, continent_this, „This week”, „All-time”)

“`

## Changes in continet (2/2)

“` {r continet-lines, out.width = ‘50%’, fig.height = 10)

change_lines(continent_last, continent_this, „This week”, „Last week”, 0.3)

change_lines(continent_all, continent_this, „This week”, „All-time, 0.3)

“`

## Changes in protein source (1/2)

“`{r protein-source-bars, fig.height = 2.5}

difference_bars_absolute(protein_last, protein_this, „This week”, „Last week”)

difference_bars_absolute(protein_all, protein_this, „This week”, „All-time”)

“`

## Changes in continet (2/2)

“` {r protein-source-lines, out.width = ‘50%’, fig.height = 10)

change_lines(protein_last, protein_this, „This week”, „Last week”, 0.5)

change_lines(protein_all, protein_this, „This week”, „All-time, 0.5)

“`

Teraz dodamy wywołania funkcji do kodu, który opracowaliśmy w poprzednich rozdziałach. Jak widać, proces przebiega dokładnie tak samo, ponieważ w tym momencie wczytaliśmy już te zasoby we fragmencie kodu load-functions-and-data pokazanym wcześniej . Wszystko, co musimy zrobić, to wywołać funkcje, które tworzą dla nas wykresy. Jeśli nie pamiętasz, co robią te funkcje, sugerujemy cofnięcie się do odpowiednich rozdziałów i omówienie szczegółów ich tworzenia. Jak widać, ostatni slajd z tego fragmentu kodu wywołuje funkcję graph_client_messages_interactive() która tworzy interaktywną mapę. Wspaniałą rzeczą w tworzeniu prezentacji w ten sposób jest to, że możesz faktycznie bawić się mapą w prezentacji! Oczywiście zadziała to tylko wtedy, gdy używasz formatu wyjściowego, który wykorzystuje przeglądarkę internetową do wizualizacji (nie będzie działać na przykład z plikami PDF lub dokumentami Word), ale może to być fantastyczny sposób na dodanie potężnej zawartości do prezentacje, jeśli używasz przeglądarki internetowej do ich wizualizacji:

## Profit ratio vs contiet

“` {r sales-proft-rati-by-continent-and-protein-source }

graph_bars(sales, „CONTINENT”, „PROFIT_RATIO”, „PROTEIN_SOURCe”)

“`

## Cost vs proce

“` {r price-vs-cost}

graph_marginal_distributions(sales, „COST”, „PRICE”, „PROTEIN_SOURCE”, „CONTINENT”)

“`

## Price vs profit

“`{r price-vs-profit-ratio}

graph_marginal_distributions(sales, „PRICE”, „PROFIT_RATIO”, „PROTEIN_SOURCE”, „CONTINET”)

“`

## Historic pricing

“` {r date-vs-frequecy-profit-and-profit-ratio, fig.height = 1.8}

grpah_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”)

## Top 5 customers’ preferences

“` {r top-customers-preferences}

subset <- filter_data(sales, 30, 5, „CLIENT_ID”)

graph_radar(subset, „CLIENT_ID”)

“`

## Customer message geolocations

“` {r customers-dynamic-map}

graph_client_messages_interactive(client_messages, sales)

“`

Na koniec chcemy pokazać najnowsze tweety przy użyciu rzeczywistych danych z Twittera na żywo. Ponieważ firma Food Factory, do której nawiązaliśmy w tym przykładzie, jest fikcyjna, tak naprawdę nie możemy uzyskać dla niej danych, ale nadal będziemy przeszukiwać Twittera pod kątem frazy The Food Factory i wyświetlać 5 najlepszych wyników, które otrzymamy. W rzeczywistości możesz pobrać tweety, które wspominają o konkretnym koncie, które Cię interesuje, i wykazać się większą kreatywnością podczas wykonywania zapytań. W tym przykładzie będzie to proste. Pierwszą rzeczą, którą musimy zrobić, jest identyfikacja z API Twittera, abyśmy mogli odzyskać dane. Jeśli nie pamiętasz, jak to zrobić, zajrzyj do wspomnianego rozdziału. Ponieważ chcemy wykonać ten fragment kodu, ale nie chcemy go wyświetlać ani jego wyników, po prostu stosujemy opcję include = FALSE. Zwróć uwagę, że trzymamy tytuł slajdu na górze kodu uwierzytelniającego jako znak dla siebie, że ten kod należy do logiki tego slajdu:

## Latest message from Twitter

“` {r twitter-setup, include = FALSE}

consumer_key <- „b9SGfRpz4b1rnHFtN2HtiQ9xl”

consumer_secret <- „YMifSUmCJ4dlgB8RVxKRNxILQw7Y4IBwDwBRkdz2Va1vcQjOP0”

access_token <- „171370802-RI14RBpMDaSFdVf5q9xrSWQKxtae4Wi3y76Ka4Lz”

access_secret <- „dHfbMtmpeA2QdOH5cYPXO5b4hF8Nj6LjxELfOMSwHoUB8”

setup_twitter_oauth(consumer_key, consumer_secret, access_token, access_secret)

“`

Następnie wstawiamy kolejny fragment kodu, który w rzeczywistości generuje dane wyjściowe, które chcemy pokazać na slajdzie. Pobieramy dane z Twittera za pomocą get_twitter_data(), które stworzyliśmy w poprzednim rozdziale i przekazujemy je przez 􀁇􀁐􀁓􀁎􀁂􀁕􀁀􀁕􀁘􀁆􀁆 􀁕􀁔􀀊􀀋 funkcja, którą pokażemy dalej:

“`{r twitter-live-data, size == „footnotesize”, comment = „”}

format_tweets(get_twitter_data(„The Food Factory”, 5))

“`

Ta funkcja format_tweets() była konieczna do wydrukowania danych, które chcemy pokazać na slajdzie. Jeśli pamiętasz, dane, które otrzymujemy z funkcji get_twitter_data(), zawierają sporo metadanych wokół każdego tweeta, co jest bardzo przydatne podczas analizy, ale do tego slide, wolelibyśmy pokazać tylko nazwę użytkownika osoby, która napisała na Twitterze, sygnaturę czasową tweeta i rzeczywisty tweet. Musimy również skrócić długość tweeta, aby upewnić się, że będzie dobrze wyglądał w prezentacji. Mimo że jest to niewielka funkcja, kod może być nieco złożony, jeśli wcześniej nie widziałeś tych funkcji, więc zrobimy to krok po kroku. Funkcja format_tweets() otrzymuje pojedynczy argument, czyli dane, które otrzymaliśmy z funkcji get_twitter_data() i wiemy, że struktura danych zawiera interesujące nas zmienne creates, text i screenName. Ponieważ jest to kod wektorowy, nie trzeba użyć pętli for, aby wydrukować każdy tweet niezależnie. Możemy po prostu bezpośrednio użyć tablic wartości. Jeśli nie pamiętasz, do czego odnosi się kod wektorowy :

format_tweets <- function(data)  {

write(paste (

data$screenName , „ („ , datat$created, „) : \n”,

iconv(enc2utf8(substr(data$text, 1, 65)) , sub = „”),

„(…) \n”, sep = „”

), stdout () )

}

Pierwszą rzeczą, jaką możesz zauważyć, jest to, że nie używamy funkcji print(). Używamy funkcji write() przekazanej w wywołaniu funkcji stdout() Oznacza to, że napiszemy obiekt na standardowe wyjście. Możesz myśleć o tym jako o głupim wywołaniu funkcji print(), w którym R nie wykona za nas żadnego przetwarzania i po prostu pokaże dokładnie, co mu powiemy. To pozwala uniknąć drukowania numerowanych wierszy, które zwykle otrzymujemy podczas korzystania z funkcji drukowania. Pamiętasz te [1], [2]. … na początku wyjścia w poprzednim kodzie? Ta technika write(…, stdout() ) pozwala ich uniknąć. Zwykle tego nie chcesz, ale w tym konkretnym przypadku jest to przydatne ze względów estetycznych. Następnie używamy funkcji paste(), tak jak robiliśmy, aby złożyć wszystko, co chcemy wydrukować. W tym przypadku zaczynamy od nazw ekranów, po których następuje nawias zawierający znacznik czasu (zawarty w data$created), a następnie kombinacja wskazująca nowy wiersz. Kombinacja \n, gdy jest używana wewnątrz funkcji write(), mówi R, aby faktycznie wprowadził nowy wiersz w tym miejscu, tak jakbyś nacisnął klawisz powrotu (klawisz Enter na klawiaturze). Następnie przekazujemy rzeczywisty tweet (data$text) do funkcji substr(), dzięki czemu możemy uzyskać znaki od 1 do 65. Zrobiliśmy to ponownie ze względów estetycznych, ponieważ nie chcę, aby bardzo długie tweety zajmowały więcej niż jedną linię. Dane wyjściowe są wysyłane do funkcji enc2utf8(), która ustawia kodowanie łańcucha na UTF-8, a dane wyjściowe są przekazywane przez funkcję iconv()  z parametrem sub = „”, który usunie wszystkie niewymienialne znaki. Na koniec umieściliśmy ciąg znaków ”(…) \n”, aby pokazać, że tweet został prawdopodobnie obcięty, oraz kolejny symbol nowej linii. Podczas korzystania z funkcji iconv() zdarza się, że będzie ona próbowała konwertować znaki jeden po drugim, a gdy nie będzie mogła przekonwertować znaku, zastąpi go wysyłanym przez nas ciągiem znaków sub. Musimy to zrobić, ponieważ możemy otrzymać znaki z języków takich jak chiński lub arabski, których wyjście zawierałoby reprezentację Unicode, co nie miałoby sensu dla osób, które nie są zaznajomione z tego typu problemami z kodowaniem. Staramy się stworzyć przyjazną dla użytkownika prezentację.

Jeśli ponownie skompilujesz tę prezentację, wiadomości pobrane z Twittera będą się różnić od pokazanych tutaj, ponieważ zostaną pobrane w tym momencie

Teraz możesz skompilować swoją prezentację dowolną z metod wymienionych wcześniej, a jeśli wszystko pójdzie dobrze, powinieneś zobaczyć plik presentation.html w swoim katalogu. Jeśli otworzysz ten plik w przeglądarce internetowej, powinieneś zobaczyć slajdy podobne do pokazanych poniżej. Możesz także otworzyć prezentację na żywo bezpośrednio w repozytorium tej książki. Pamiętaj, aby bawić się interaktywną mapą!

Sesson info ——————————————————-

setting value

version R bersion 3.4.2 (2017 – 09 – 28

system x84_64, linux-gnu

ui X11

language (EN)

collate en_US.UTF-8

tz America/Mexico City

date 2017-10-30

Packages ———————————————————–

package * versin date source

assertthat 0.2.0  2017-04-11 CRAN (R 3.3.2)

base * 3.4.2. 2017-10-28 local

base64enc 0.1-3 2015-07-28 CRAN (R 3.3.2)

bindr 0.1 2016-11-13 CRAN (R 3.3.2)                             

[…truncated…]

Podsumowanie

Omówiliśmy zalety automatyzacji zadań oraz tworzenia treści. Pokazaliśmy, jak zintegrować potoki automatyzacji do tworzenia treści, jak pisać dokumenty R Markdown, które zapewniają dynamiczną zawartość, oraz jak używać tych dokumentów do tworzenia ładnie wyglądających i wydajnych dokumentów i prezentacji. Pokazaliśmy, jak zintegrować różne zasoby języka R, aby tworzyć treści, które mogą być aktualizowane automatycznie. Jeśli chcesz opracować dokumenty, które są bardziej techniczne lub obszerne, pakiet bookdow może być dla Ciebie dobrą opcją. Jego celem jest ułatwienie tworzenia długich dokumentów, takich jak książki, za pomocą R Markdown. Prawdę mówiąc, ta książka została napisana przy użyciu bookdown, a proces był naprawdę przyjemny. W następnym rozdziale rozpoczniemy nowy przykład koncentrujący się na ocenie transakcji kryptowalutowych. Zaczniemy od zbudowania zorientowanego obiektowo systemu, który symuluje platformę handlową i automatycznie ocenia wyniki traderów. Następnie pokażemy, jak sprawić, by nasze algorytmy działały szybciej, używając równoległości i delegacji, a na koniec w ostatnim rozdziale pokażemy, jak tworzyć strony internetowe zawierające interaktywne pulpity nawigacyjne, wszystko z poziomu R.

Opracowywanie wykresów i analiz w normalny sposób

Jak widzieliście w poprzednich sekcjach, możesz pracować bezpośrednio z naszym plikiem R Markdown do prezentacji (presentation.Rmd w naszym przypadku). Jednak możesz być bardziej produktywny, jeśli najpierw opracujesz zawartość prezentacji, tak jak normalnie pracujesz z R, wykorzystując wszelkie konfiguracje i narzędzia, do których jesteś przyzwyczajony. Po sfinalizowaniu kodu tłumaczysz tylko niezbędne części do pliku R Markdown. Nawet jeśli wydaje się to sprzeczne z intuicją, ponieważ wymagałoby więcej pracy, w rzeczywistości działa to szybciej, tylko dlatego, że jesteś przyzwyczajony do pracy z R bardziej niż z R Markdown i pomyślisz o stworzeniu modularnego kodu, który można podłączyć do Twoja prezentacja. Pozwala to na tworzenie kodu o wyższej jakości i wielokrotnego użytku. Dokładnie to zrobimy tutaj. Zaczniemy pracować z naszymi zwykłymi plikami mai.R i functios.R, aby opracować to, czego potrzebujemy. Następnie w dalszej części dokonamy migracji kodu do naszego pliku presentation.Rmd. Zauważ, że użycie funkcji source(), tak jak zrobiliśmy, ładuje do pamięci wszystkie funkcje, które mamy w pliku funkcji. Może to być to, czego naprawdę potrzebujesz, ale jeśli nie będziesz ostrożny, możesz w rezultacie nadpisać definicję funkcji. W tym konkretnym przypadku nie stanowi to problemu, więc zostawimy to tak, jak jest. Gdyby to był problem, zawsze moglibyśmy przenieść żądaną funkcję do jej własnego pliku i po prostu source tego pliku. Interesująca nas funkcja to:

filter_n_days_back <- function(data,n) {

if (is.null()) {

return(data)

}

n_days_back <- Sys.Date() – n

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

}

Załóżmy, że minęło dużo czasu od pierwszej symulacji danych. Jeśli wykonasz wywołanie funkcji, takie jak filter_n_days_back(data,7), nie masz gwarancji, że będziesz mieć dane z poprzedniego tygodnia i Ciebie Najprawdopodobniej otrzymasz pusty wynik, ponieważ n_days_back <- Sys.Date() – n zawiera dane z 7 dni wstecz od today , a nie ostatnia data zapisana w danych. To jest problem. Sposób radzenia sobie w takich sytuacjach może zakończyć długą debatę z rówieśnikami. Generalnie mamy dwie możliwości: przepisanie niezależnej funkcji lub naprawienie kodu, który już mamy. Właściwa odpowiedź będzie zależeć od twoich konkretnych okoliczności i kontekstu, a oba mają swoje zalety i

wady. Generalnie, pisząc nową funkcję, będziesz mieć pewność, że twój kod działa i że nie złamałeś przypadkowo kodu innej osoby, co zależało od poprzedniej wersji. Wadą jest to, że będziesz musiał utrzymywać więcej kodu bez uzyskiwania dużej funkcjonalności, a z czasem może to być ogromny ból. Pamiętasz zasadę DRY, o której wspomnieliśmy wcześniej? Nie powtarzaj się (SUCHE). Jeśli zdecydujesz się naprawić obecną wersję kodu, prawdopodobnie otrzymasz bardziej niezawodną bazę kodu, którą możesz ponownie wykorzystać w jeszcze większej liczbie przypadków, niż początkowo przewidywano, bez zbytniego zwiększania (czasami zmniejszania) kodu, który musisz utrzymywać. Istnieje jednak również możliwość, że złamiesz kod, który zależał od poprzedniej funkcjonalności, co może być bardzo trudne do naprawienia w przyszłości, gdy zdasz sobie sprawę, że to zrobiłeś. Istnieją dwie podstawowe zasady, które uchronią Cię przed silnymi bólami głowy w tego typu sytuacjach. Używaliśmy jednej z nich: tworzenia małego i modułowego kodu. Krótko mówiąc, mamy na myśli kod działający zgodnie z zasadą pojedynczej odpowiedzialności, Kiedy to robisz, dzieje się coś magicznego; zaczynasz podłączać kod do innego kodu i możesz łatwo modyfikować te wtyczki i tworzyć nowe, jeśli ich potrzebujesz, bez większych problemów. Innym fundamentem są testy jednostkowe dla twojego kodu. Mówiąc najprościej, testy jednostkowe to fragmenty kodu zaprojektowane do testowania, czy inny kod działa tak, jak powinien. Testy jednostkowe są poza zakresem tej książki, ale zdecydowanie powinieneś się tym zająć, jeśli jeszcze tego nie wiesz.

Wracając do kodu tego konkretnego przykładu, zdecydowaliśmy się naprawić kod, który już mamy. Aby mieć pewność, że przypadkowo nie złamiemy innego kodu zależnego od tej funkcji, stosujemy się do zasady Open-Closed, która mówi, że obiekty powinny być otwarte na rozszerzenia i zamknięte na modyfikacje. Zasadniczo rozszerzymy interfejs bez modyfikowania go w taki sposób, aby wynik był taki sam, gdy używamy tych samych poprzednich wejść, ale rozszerzona wersja pozwoli nam uzyskać nowe wyjścia, które chcemy. Brzmi bardziej uciążliwie niż w rzeczywistości. Jak widać, po prostu dodajemy nowy opcjonalny parametr o domyślnej wartości NULL. Następnie zamiast obliczać_days-back z bieżącą datą, sprawdzamy, czy została wysłana jakakolwiek wartość; jeśli tak, to używamy tego jako punktu wyjścia; jeśli nie, wracamy do starego zachowania:

filter_n_days_back <- function(data, n, from_date = NULL) {

if (is.null(n) ) {

return(data)

}

if (is.null(from_date)) {

from_date <- Sys.Date()

) else if (is.character(from_date)) {

from_date <- as.Date(from_date)

}

n_days_back  <-  from_date – n

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

}

Teraz, gdy mamy tę nową wersję funkcji, możemy użyć jej do uwzględnienia ostatniego tygodnia w danych, obliczając maksymalną datę, którą w niej zapisaliśmy, i używając tego jako naszego parametru 

from_date . Zwróć także uwagę, jak łatwo jest wziąć dane nie tylko z tego tygodnia, ale także z zeszłego tygodnia. Jednak aby to zadziałało, musimy upewnić się, że obiekt max_date jest obiektem Date w R, abyśmy mogli odjąć od niego 7, a to faktycznie oznacza 7 dni. Jeśli jest to ciąg znaków zamiast daty, wystąpiłby błąd. Na marginesie, pamiętaj, że gdybyśmy korzystali z danych, które są stale rejestrowane, ten i ostatni tydzień miałby sens, ale ponieważ używamy danych, które symulowaliśmy prawdopodobnie dawno temu, ten i ostatni tydzień będą się różnić w zależności od daty w rzeczywistych danych, których używamy. To nie jest problem, ponieważ używamy maksymalnej daty w danych, która zostanie odpowiednio dostosowana dla każdej sytuacji:

max_date <- max(all_time$DATE)

this_week <- filter_n_days_back(all_time, 7, max_date)

last_week <- filter_n_days_back(all_time, 7 , max_date -7)

Teraz, gdy mamy trzy potrzebne nam zbiory danych (all_time, last_week i  this_week), możemy rozpocząć tworzenie kodu, który wykorzysta je do tworzenia wykresów, których szukamy. Najpierw musimy uzyskać tabele proporcji dla każdej interesującej nas zmiennej i dla każdego zbioru danych. Tak jak zawsze chcemy opakować kod, który nie jest zbyt jasny na temat jego funkcjonalności, we własną funkcję, abyśmy mogli nadać jej nazwę i szybko wiedzieć, co ma robić. W w tym przypadku tworzymy funkcjęproportio_table(), która powinna być oczywista, i stosujemy to, jak wspomniano. Zauważ, że mnożymy przez 100 , ponieważ chcemy pokazać 10% z zamiast 0.2 na naszych wykresach:

propotions_table <- function(data, variable){

return(prop.table(table(data[, variable])))

}

quantity_all <- proportios_table(all_time, „QUANTITY”)

cotinent_all <- proportions_table(all_time, „CONTINENT”)

protein_all <- proportions_table(all_time, „PROTEIN_SOURCE”)

quantity_last <- proportios_table(last_week, „QUANTITY”)

cotinent_last <- proportions_table(last_week, „CONTINENT”)

protein_last- proportions_table(last_week, „PROTEIN_SOURCE”)

quantity_this <- proportios_table(this_week, „QUANTITY”)

cotinent_this <- proportions_table(this_week, „CONTINENT”)

protein_this <- proportions_table(this_week, „PROTEIN_SOURCE”)

W tym momencie każdy z tych obiektów powinien zawierać tabelę z procentami każdej kategorii w ramach zmiennej będącej przedmiotem zainteresowania. Te kończące się na _all zawierają procenty wszystkich zarejestrowanych danych. Podobnie te kończące się na _last i _this zawierają wartości procentowe odpowiednio dla ostatniego tygodnia i tego tygodnia. Liczba miejsc dziesiętnych zależy od aktualnych danych i konfiguracji. We wszystkich przypadkach liczby powinny sumować się do 100: 

quantity_all

#> 1 2 3 4 5 6 7 8 9

#> 13,22 27,78 26,09 18,29 9,19 3,77 1,29 0,30 0,07

quantity_last

#> 1 2 3 4 5 6 7 8

#> 12,1387 33,5260 28,3234 12,7160 5,7803 5,7803 1,1560 0,5780

quantity_this

#> 1 2 3 4 5 6 7 8

#> 12 36 25 14 7 4 1 1

Uważny czytelnik powinien był zauważyć, że quantity_all zawiera jeszcze jedną kategorię niż quantity_last i quantity_this. To dlatego, że w ciągu ostatnich dwóch tygodni w danych nie było sprzedaży dla dziewięciu artykułów. Oznacza to, że gdy spróbujemy porównać zmianę liczby w każdej z tych kategorii, będziemy mieli problem z powodu dodatkowej kategorii w quantity_all. Poradzimy sobie z tym, zachowując tylko kategorie, które są wspólne dla każdej używanej przez nas pary tabel. Funkcja equal_length_data() otrzymuje dwie z tych tabel jako data_1 i data_2, a następnie oblicza minimalną długość (ml) wśród nich i używa go do uzyskania elementów do tego punktu w obu data_1 i data_2. Ponieważ oba są w tym momencie tabelami, chcemy numerycznej tablicy jej wartości, a nie obiektu tabeli, dlatego stosujemy as.numeric(). Jeśli tego nie zrobimy, ggplot2 będzie narzekać, że nie wie, jak postępować z obiektami typu table. Nie tracimy nazw kategorii, stosując funkcję as.numeric do tabel, ponieważ bierzemy je oddzielnie w elemencie names zwracanej listy. Na koniec chcemy wiedzieć, czy jakiekolwiek kategorie zostały usunięte, i możemy to wiedzieć, sprawdzając, czy długość którejkolwiek z tabel danych zawiera mniej kategorii, niż wskazuje liczba ml. W takim przypadku delete będzie TRUE i zostanie wysłane, a będzie FALSE w przeciwnym razie:

equal_legth_data <- function(data_1, data_2) {

ml <- min(length(data_1), length(data_2))

return(list(

names = names(data_1[1:ml]),

data_1 = as.numeric(data_1[1:m;]),

data_2 = as.numeric(datat_2[1:ml]),

deleted = ml != length(data_1) || ml = != length(data_2)

)

}

Mamy teraz dostęp do danych o równej długości, z odpowiednimi nazwami kategorii i wartością logiczną wskazującą, czy jakiekolwiek kategorie zostały usunięte. Możemy użyć tego obiektu w następujący sposób:

parts <- equal_length_data(quantity_all, quantity_this)

parts$names

#> [1] “1” “2” “3” “4” “5” “6” “7” “8”

parts$data_1

#> [1] 0,1322 0,2778 0,2609 0,1829 0,0919 0,0377 0,0129 0,0030

pats$data_2

#> [1] 0,12 0,36 0,25 0,14 0,07 0,04 0,01 0,01

parts$deleted

#> [1] TRUE

Teraz skupimy się na przygotowaniu danych do naszych wykresów. Ponieważ będziemy używać pakietu ggplot2, wiemy, że musimy utworzyć ramkę danych. Ta ramka danych powinna zawierać nazwy kategorii w Category bezwzględne i procentowe różnice między pasującymi kategoriami z dwóch tabel odpowiednio Difference i Percent , Sign i Color w zależności od tego, czy bezwzględna różnica jest dodatnia czy ujemna, a dane przed i po odpowiednio Before i After. Zauważ, że kolejność, w jakiej obliczono parts, jest ważna dla bezwzględnych i procentowych różnic, które z kolei wpływają na kolor i znak. Musimy uważać na przesyłanie najnowszych danych jako data_2, aby otrzymać interpretację podobną do zeszłego tygodnia, w tym tygodniu mieliśmy X więcej. W przeciwnym razie interpretacja byłaby odwrócona:

prepare_data <- function(parts) {

data <- data.frame(„Category” = parts$names)

data$Difference <- parts$data_2 – parts$data_1

data$Percent <- (parts$data_2 – parts$data_1) / parts$data_1 * 100

data$Sign <- ifelse(data$Difference >= -, „Positive”, „Negative”)

data$Color <- ifelse(data$Difference, &gt; = 0, GREEN, RED)

data$Before <- parts$data_1

data$After <- parts$data_2

return(data)

}

Zdefiniujemy dwa kolory za pomocą notacji szesnastkowej, abyśmy mogli wywołać je po nazwie zamiast za każdym razem kopiować ciąg szesnastkowy. Później, jeśli chcemy zmienić kolory, możemy zmienić je w jednym miejscu zamiast zastępować je wszędzie tam, gdzie ich używaliśmy:

RED <- „#F44336”

GREEN <- „#4CAF50”

Funkcja difference_bars() powinna być jasna. Jak widać, obliczamy obiekty parts i data za pomocą funkcji przedstawionych wcześniej, a następnie używamy pakietu ggplot2 do opracowania wykresu. Zwróć uwagę, że dodajemy tylko podtytuł zawierający informację, że niektóre kategorie zostały usunięte, jeśli wartość logiczna delete z parts to TRUE:

differennce_bars <- function(data_1, data_2, before, after) {

parts <- equal_length_data(data_1, data_2)

data <- prepare_data(parts)

p <- ggplot(data, aes(Category, Difference, fill =  Sign))

p <- p + geom_bar(stat = „identity” , width = 0.5)

p <- p + scale_fill_manual(values =

c(„Positive” = GREEN, „Negative” = RED))

p <- p + theme(legend.position = „none”,

text = element_text(size = 14))

p <- p + scale_y_cotinuous(labels = scales ::percent)

p <- p + labs(title = paste(before, „vs” , after))

p <- p + labs(x = „” , y = „”)

if (parts$deleted) {

p <- p + labs(subtitle =

„(Extra categories have been deleted)”)

}

return(p)

}

Teraz możemy stworzyć kilka przydatnych wykresów, jak poniżej. Należy pamiętać, że wartości na osi y nie wskazują procentowego wzrostu, ale zmianę w punktach procentowych. Można to od razu zrozumieć, patrząc na kod, ale nie jest to jasne, patrząc na wykres. W rzeczywistości musielibyśmy zawrzeć pewne wyjaśnienie tego w prawdziwej prezentacji:

difference_bars(quantity_all, quantity_this, „This week”, „All-time”)

difference_bars(continent_all, continent_this, „This week”, „All-time”)

difference_bars(protein_all, protein_this, „This week”, „All-time”)

Wynikowe wykresy przedstawiono w następujący sposób:

Drugi typ wykresu, który chcemy opracować, jest nieco bardziej złożony. Utworzymy pionowe linie na 1 i 2 wzdłuż osi x, umieścimy etykiety tekstowe wskazujące, gdzie procent dla każdej kategorii znajduje się w zestawach danych before i after, a procent zmiany w środku. Najpierw tworzymy obiekt data tak jak poprzednio. Następnie tworzymy etykiety, których użyjemy dla każdej kategorii. Te po lewej to before_labels, te w środku to percent_labels, a te po prawej to after_labels. percent_y zawiera wartości dla osi y, na której będzie umieszczony percet_labels. Wartość osi x jest ustalona na 1,5, tak że znajduje się między dwiema pionowymi liniami. Aby obliczyć wartość perent_y, chcemy uzyskać minimum między wartościami przed i po dla każdej kategorii i dodać połowę różnicy między nimi. Zapewni to, że wartość będzie znajdować się w środku linii, która będzie łączyła obie wartości. Jesteśmy teraz gotowi do rozpoczęcia korzystania z pakietu ggplot2. Najpierw definiujemy dane w zwykły sposób i dodajemy segment łączący wartości before i  after dla każdej kategorii, zaczynając od krotki $(1,Befoere)  i kończąc na krotce $(2,After), gdzie każda krotka ma postać $(x,y). Użyjemy zmiennej Sign jako koloru wypełnienia słupków i unikniemy wyświetlania legendy, ponieważ sami pokażemy niektóre etykiety. Użyjemy funkcji scale_color_manual (), aby określić kolory, które powinny być używane dla każdej linii w zależności od tego, czy różnica bezwzględna była dodatnia czy ujemna. Następnie pojawiają się pionowe linie, które tworzy się funkcją geom_vline(). Jak wspomniano wcześniej, zostaną one umieszczone z wartościami 1 i 2 wzdłuż osi x. Zrobimy linię przerywaną, aby poprawić estetykę i użyć mniejszego rozmiaru niż linie segmentów, które stworzyliśmy wcześniej.

Następnie umieścimy etykiety za pomocą funkcjigeom_text(). Rozpoczynamy tworzenie etykiety dla każdej z linii pionowych, które są tworzone przy wartościach 0,7 i 2,3 osi x oraz nieco zwiększonym maksimum wartości before i after. Następnie umieszczamy etykiety kategorii po lewej stronie, w środku i po prawej stronie za pomocą funkcji geom_text_repel(). Ta funkcja nie jest zawarta w pakiecie ggplot2, a właściwie jest jej rozszerzeniem. Jest przeznaczony do odpychania (stąd nazwa) etykiet, które nakładają się na siebie. W tym celu funkcja odsuwa etykiety od pozycji punktu i rysuje linię wskazującą, która etykieta należy do każdego punktu.

W naszym przypadku usuwamy wspomnianą linię parametrem segment.color = NA i wskazujemy, że kierunek regulacji przebiega tylko wzdłuż osi y. W rzeczywistości bardzo trudno jest komuś wymyślić cały ten kod za pierwszym razem, a nasz przypadek nie był inny. Zaczęliśmy od kilku małych wątków i stale dodawaliśmy elementy, których szukaliśmy, poprzez powtarzane eksperymenty. W szczególności zdaliśmy sobie sprawę, że niektóre etykiety zachodzą na siebie, co nie wygląda dobrze, dlatego zdecydowaliśmy się użyć pakietu geom_text_repl(), którego wcześniej nie robiliśmy Wiem, ale łatwo znaleźć w Internecie, ponieważ wiele osób ma ten sam problem i na szczęście ktoś opracował jego rozwiązanie. Parametr x_adjustment jest wynikiem podobnych eksperymentów. Zdaliśmy sobie sprawę, że etykiety różnych wykresów nakładały się na pionowe linie w zależności od liczby znaków w nazwach kategorii. Aby to naprawić, zdecydowaliśmy się wprowadzić nowy parametr, który dostosowuje położenie wzdłuż osi x, z którym można eksperymentować, dopóki nie znajdziemy dla niego dobrego parametru. Wszystko po to, aby powiedzieć, że powinieneś skorzystać z szybkich cykli eksperymentów R, aby iteracyjnie wytworzyć to, czego szukasz. Na koniec usuwamy dowolny tekst z osi x i y oraz ograniczamy ich zakres wartości, ponieważ nie trzeba ich czytać na wykresie i zapewniać bardziej przejrzystą wizualizację. Zrozumienie, co dokładnie robi każda część kodu, może wymagać trochę eksperymentów, co jest całkowicie w porządku i zdecydowanie powinieneś to zrobić:

change_lines <- function(data_1, data_2, before, after, x_adjustment) {

parts <- equal_length_data(data_1, data_2)

percent_labels <- paste(round(data$Percent, 2), „%”, sep = „”)

befoe_labels < paste(

data$Category, „ ( „, round(data$Before, 2), „%)”, sep = „”)

after_labels <- paste(

data$Category, „ („ round(data$After, 2), „%)”, sep = „”)

percent_y <- (

apply(data[, c(„Before”, „After”)], 1, min) +

abs(data$Before – data$After) / 2

)

p <- ggplot(data)

p <- p + geom_segment (

aes(x = 1, xend = 2, y = Before, yend = After, col = Sign).

show.legend = FALSE,

size – 1.5)

p <- p + sale_color_manual (

values = c(„Positive” = GREEN, „Negative” = RED))

p <- p + geom_vline(xintercept = 1 lietype = „dashed”, size = 0.8)

p <- p + geom_vline(xintercept = 2 , lietype = „dashed” , size = 0.8)

p <- p + geom_text (

label = before,

x = 0.7

y = 1.1 * max(data$Befre data$After),

size = 7)

p <- p + geom_text (

label= after,

x = 2.3,

y = 1.1  * max(data$Before, data$After),

size= 7)

p <- p + geom_text_repel (

label = befoe_labels,

x = rep(1 – x_adjustment, nrow(data)),

y = data$Before, size = 5, direction = „y”,

segmet.color = NA)

p <- p + geom_text_repel (label = after_labels,

x = rep(2 + x_adjustment, nrow(data)),

y = data$After, size = 5,

direction = „y”,

segment.color = NA)

p <- p + geom_text_repel(label = percent_labels,

x = rep(1.5, nrow(data)),

y = perent_y, col – data$Color , size = 5,

direction = „y”

segment.color = NA)

p <- p + theme (

axis.ticks = elelment_blank(),

axis.text.x = element_blank(),

axis.text.y = elemet_blank()

)

p <- p + ylim(0, (1.1 * max(data$Before, data$After)))

p <- p + labs(x = „” , y = „”)

p <- p + xlim(0.5 , 2.5)

retur(p)

}

Teraz możemy przedstawić kilka bardzo przydatnych i ładnie wyglądających wykresów z następującym kodem:

change_lines(quantity_last, quantity_this, „This week”, „Last week”, 0.2)

change_lines(continent_last, continent_this, „This week”, „Last week”, 0.3)

change_lines(protein_last, protein_this, „This week”, „Last week”, 0.5)

Te wykresy można łatwo zinterpretować i nie wydają się być tak podatne na problem z jednostkami procentowymi osi x, o którym wspominaliśmy na poprzednich wykresach. Możesz łatwo sprawdzić, czy kategoria zwiększyła lub zmniejszyła swój procent między okresami oraz o ile procent. Pamiętaj, że wątki wszech czasów zawierają również ten tydzień podczas ich interpretacji. W rzeczywistości może to być poprawne lub nie w Twoim konkretnym przypadku użycia.

Wytwarzanie końcowego produktu za pomocą knitr

Gdy masz gotowy dokument lub jesteś gotowy, aby zobaczyć jego następną iterację, możesz skompilować w R Studio, jeśli go używasz, lub wykonując kod, który wyzwala kompilację. Pokażemy to drugie, ponieważ jest bardziej ogólne i może być używane przez osoby, które nie są koniecznie przy użyciu R Studio. Wystarczy wykonać następujące wiersze, zmieniając nazwę pliku „document.Rmd”na własną i wybierając odpowiednie wyjście:

library(rmarkdown)

output <- c(„html_document”, „pdf_document”)

render(„document.Rmd”, outputs)

Sugerujemy utworzenie pliku compile.R zawierającego te linie i wykonywanie go za każdym razem, gdy będziesz chciał rekompilować swój dokument. Dostępne są następujące wyjścia:

Wyjście ciągu

html_document :  dokument HTML

pdf_document:  Dokument PDF

word_document : Dokument Word

10slides_presentation :  Prezentacja HTML, typ 1

slidy_presentation: Prezentacja HTML, typ 2

beamer_presentation : Prezentacja Beamer (LaTex) PDF

W tym momencie powinieneś być w stanie tworzyć własne prezentacje. W kolejnych sekcjach zaczniemy budować prezentację, którą chcemy faktycznie opracować dla przykładu The Food Factory.

Buforowanie

Jak wspomnieliśmy wcześniej, knitr nie jest tak przydatny, jeśli piszesz bardzo długi dokument lub dokument zawierający złożone obliczenia. Możesz jednak uniknąć niektórych z tych problemów, używając pamięci podręcznych. Podstawową kwestią jest to, że jeśli masz długi dokument lub taki, który wymaga długich obliczeń, to za każdym razem, gdy chcesz odświeżyć dokument, musisz go ponownie skompilować, co oznacza, że ​​musisz ponownie wykonać wszystkie obliczenia. Może to nie stanowić problemu, jeśli dokument jest wydajny lub mały. Jednak siedzenie i czekanie na wykonanie każdego obliczenia za każdym razem może być nieefektywne. Buforowanie fragmentów to jeden ze sposobów uniknięcia tych długich obliczeń. Ustawiając opcję cache = TRUE chunk, knitr uruchamia porcję raz i zapisuje dane wyjściowe w katalogu roboczym. Kiedy ponownie tworzysz dokument, zamiast uruchamiać kod w tym konkretnym fragmencie, knitr przeładuje zapisane wyjście. Jeśli kod w porcji w ogóle się zmieni, knitr wykryje to i ponownie uruchomi kod, przechowując zaktualizowane wyniki. Istnieją pewne zastrzeżenia dotyczące buforowania. W szczególności zależności między porcjami nie są domyślnie sprawdzane. Jeśli wyniki buforowanej porcji zależą od poprzedniej porcji, która została zmodyfikowana, zmiany te niekoniecznie będą przenoszone na późniejsze porcje w pamięci podręcznej. Ponadto fragmenty ze znaczącymi skutkami ubocznymi, takie jak zapisywanie danych wyjściowych do plików lub jakakolwiek interakcja ze środowiskiem zewnętrznym, mogą nie być buforowane. Dopóki jesteś z nimi ostrożny, nie powinieneś mieć żadnych problemów.