Dane instalacyjne pakietu R

Teraz, gdy wiemy, jak korzystać z kNN, przejdźmy do logiki tworzenia rekomendacji. Jednym ze sposobów, w jaki możemy zacząć przedstawiać rekomendacje, jest znalezienie produktów podobnych do tych, które już lubią nasi użytkownicy, a następnie zastosowanie kNN, które nazwiemy podejściem opartym na przedmiotach. Innym podejściem jest znalezienie elementów popularnych wśród użytkowników, którzy są podobni do użytkownika, dla którego staramy się stworzyć rekomendacje, a następnie zastosować kNN, który nazwiemy podejściem opartym na użytkownikach. Oba podejścia są rozsądne, ale jedno jest prawie zawsze lepsze niż drugie w praktyce. Jeśli masz o wiele więcej użytkowników niż przedmiotów (podobnie jak Netflix ma znacznie więcej użytkowników niż filmów), zaoszczędzisz na obliczeniach i kosztach przechowywania, stosując podejście oparte na przedmiotach, ponieważ wystarczy obliczyć podobieństwa między wszystkimi parami przedmiotów. Jeśli masz o wiele więcej elementów niż użytkowników (co często zdarza się, gdy dopiero zaczynasz zbierać dane), prawdopodobnie spróbuj wypróbować podejście oparte na użytkownikach. W tej części zajmiemy się podejściem opartym na przedmiotach. Zanim jednak omówimy bardziej szczegółowo algorytmy tworzenia rekomendacji, spójrzmy na dane, z którymi będziemy pracować. Zestaw danych, którego użyjemy, to dane, które były dostępne dla uczestników konkursu na rekomendację pakietu R na Kaggle. W tym konkursie udostępniliśmy uczestnikom pełny rekord instalacji pakietu dla około 50 programistów R. Jest to dość mały zestaw danych, ale wystarczyło, aby zacząć uczyć się o popularności różnych pakietów i ich stopniu podobieństwa. Zwycięskie zgłoszenia do konkursu wykorzystywały kNN jako część algorytmu rekomendacji, choć ogólnie był to tylko jeden część wielu dla zwycięskich algorytmów. Innym ważnym algorytmem, który został włączony do większości zwycięskich rozwiązań, jest faktoryzacja macierzy. Nie będziemy szczegółowo opisywać algorytmu, ale każdy, kto buduje system rekomendacji na poziomie produkcyjnym, powinien rozważyć połączenie rekomendacji zarówno z kNN, jak i modeli faktoryzacji macierzowej. W rzeczywistości najlepsze systemy często łączą kNN, faktoryzację macierzy i inne klasyfikatory razem w super-model. Sztuczki łączenia wielu klasyfikatorów są zwykle nazywane metodami zespołowymi. W konkursie R uczestnicy mieli przewidzieć, czy użytkownik zainstaluje pakiet, dla którego wstrzymaliśmy dane instalacyjne, wykorzystując fakt, że wiesz, jakie inne pakiety R zainstalował użytkownik. Podczas prognozowania nowego pakietu można spojrzeć na pakiety najbardziej do niego podobne i sprawdzić, czy zostały zainstalowane. Innymi słowy, było naturalne, że w zawodach zastosowano podejście kNN oparte na przedmiotach. Załadujmy więc zestaw danych i sprawdźmy go trochę. Następnie stworzymy miarę podobieństwa między pakietami. Surowe dane do konkursu nie nadają się idealnie do tego celu, dlatego przygotowaliśmy prostszy zestaw danych, w którym każdy wiersz opisuje parę elementów użytkownika, a trzecia kolumna określa, czy ten użytkownik ma zainstalowany pakiet, czy nie.

installations <- read.csv(‘data/installations.csv’)

head(installations)

# Package User Installed

#1 abind 1 1

#2 AcceptanceSampling 1 0

#3 ACCLMA 1 0

#4 accuracy 1 1

#5 acepack 1 0

#6 aCGH.Spline 1 0

Jak widać, użytkownik 1 w konkursie zainstalował pakiet abind, ale nie pakiet AcceptanceSampling. Ta nieprzetworzona informacja da nam miarę podobieństwa między pakietami po przekształceniu ich w inną formę. Zamierzamy przekształcić dane z „długiej formy” w „szeroką formę” danych, w których każdy wiersz odpowiada użytkownikowi, a każda kolumna odpowiada pakietowi. Możemy to zrobić za pomocą funkcji rzutowania z pakietu przekształcania:

library(‘reshape’)

user.package.matrix <- cast(installations, User ~ Package, value = ‘Installed’)

user.package.matrix[, 1]

# [1] 1 3 4 5 6 7 8 9 11 13 14 15 16 19 21 23 25 26 27 28 29 30 31 33 34

#[26] 35 36 37 40 41 42 43 44 45 46 47 48 49 50 51 54 55 56 57 58 59 60 61 62 63

#[51] 64 65

user.package.matrix[, 2]

# [1] 1 1 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 0 0 1 1 1 1 1 1 1 0 1 0 1 0 1 1 1 1 1 1

#[39] 1 1 1 1 1 1 1 1 0 1 1 1 1 1

row.names(user.package.matrix) <- user.package.matrix[, 1]

user.package.matrix <- user.package.matrix[, -1]

Po pierwsze, użyliśmy obsady do stworzenia naszej matrycy pakietów użytkowników. Po sprawdzeniu pierwszej kolumny zdajemy sobie sprawę, że po prostu przechowuje ona identyfikatory użytkowników, więc usuwamy ją po zapisaniu tych informacji w wierszach. Nazwy naszej matrycy. Teraz mamy odpowiednią macierz pakietów użytkowników, która sprawia, że ​​obliczanie miar podobieństwa jest banalne. Dla uproszczenia wykorzystamy korelację między kolumnami jako miarę podobieństwa. Aby to obliczyć, możemy po prostu wywołać funkcję cor z R:

similarities <- cor(user.package.matrix)

nrow(similarities)

#[1] 2487

ncol(similarities)

#[1] 2487

similarities[1, 1]

#[1] 1

similarities[1, 2]

#[1] -0.04822428

Teraz mamy podobieństwo między wszystkimi parami pakietów. Jak widać, pakiet 1 jest całkowicie podobny do pakietu 1 i nieco odmienny od pakietu 2. Ale kNN nie używa podobieństw; wykorzystuje odległości. Musimy więc przełożyć podobieństwa na odległości. Nasze podejście polega na użyciu jakiejś sprytnej algebry, aby podobieństwo 1 stało się odległością 0, a podobieństwo -1 stało się odległością nieskończoną. Kod, który tu napisaliśmy, robi to. Jeśli nie jest intuicyjnie jasne, dlaczego działa, spróbuj poświęcić trochę czasu na przemyślenie, w jaki sposób algebra przesuwa punkty.

distances <- -log((similarities / 2) + 0.5)

Przy takim przebiegu obliczeniowym mamy naszą miarę odległości i możemy rozpocząć implementację kNN. Użyjemy k = 25 na przykład do celów, ale chcesz wypróbować wiele wartości k w produkcji, aby zobaczyć, która z nich działa najlepiej. Aby przedstawić nasze rekomendacje, oszacujemy prawdopodobieństwo zainstalowania pakietu, po prostu zliczając liczbę zainstalowanych jego sąsiadów. Następnie posortujemy paczki według tej liczby i zasugerujemy paczki z najwyższym wynikiem. Więc przepiszmy naszą funkcję k.nearest.neighbors z wcześniejszej wersji:

k.nearest.neighbors <- function(i, distances, k = 25)

{

return(order(distances[i, ])[2:(k + 1)])

}

Korzystając z najbliższych sąsiadów, przewidzieliśmy prawdopodobieństwo instalacji, po prostu zliczając liczbę zainstalowanych sąsiadów:

installation.probability <- function(user, package, user.package.matrix, distances,

k = 25)

{

neighbors <- k.nearest.neighbors(package, distances, k = k)

return(mean(sapply(neighbors, function (neighbor) {user.package.matrix[user,

neighbor]})))

}

installation.probability(1, 1, user.package.matrix, distances)

#[1] 0.76

Widzimy tutaj, że dla użytkownika 1 pakiet 1 ma prawdopodobieństwo zainstalowania 0,76. Chcielibyśmy znaleźć pakiety, które najprawdopodobniej zostaną zainstalowane, i polecić je. Robimy to, zapętlając wszystkie pakiety, znajdując ich prawdopodobieństwa instalacji i wyświetlając najbardziej prawdopodobne:

most.probable.packages <- function(user, user.package.matrix, distances, k = 25)

{

return(order(sapply(1:ncol(user.package.matrix),

function (package)

{

installation.probability(user,

package,

user.package.matrix,

distances,

k = k)

}),

decreasing = TRUE))

}

user <- 1

listing <- most.probable.packages(user, user.package.matrix, distances)

colnames(user.package.matrix)[listing[1:10]]

#[1] “adegenet” “AIGIS” “ConvergenceConcepts”

#[4] “corcounts” “DBI” “DSpat”

#[7] “ecodist” “eiPack” “envelope”

#[10]”fBasics”

Jedną z zalet tego podejścia jest to, że możemy łatwo uzasadnić nasze prognozy dla użytkowników końcowych. Możemy powiedzieć, że poleciliśmy pakiet P użytkownikowi, ponieważ on już zainstalował pakiety X, Y i Z. Ta przezroczystość może być prawdziwą zaletą w

niektóre aplikacje. Teraz, gdy stworzyliśmy system rekomendacji wykorzystujący tylko miary podobieństwa, czas przejść do budowy silnika, w którym wykorzystujemy informacje społecznościowe w formie struktur sieciowych do formułowania rekomendacji

(I) : Wektory

W przypadku wektorów zwykle właściwe jest stosowanie pojedynczych nawiasów kwadratowych. Można również użyć nawiasów kwadratowych, ale mogą one uzyskiwać dostęp tylko do jednego elementu wektora na raz. W nawiasach kwadratowych może znajdować się wyrażenie logiczne lub zestaw wskaźników. Na przykład:

a [3: 7] lub a [a> 3]

Pierwsze wyrażenie skutkuje od trzeciego do siódmego elementu a. Drugie wyrażenie powoduje, że elementy a są większe niż trzy. Jeśli indeksom zostanie nadany znak ujemny, nie zostaną one uwzględnione. Na przykład

a [-2: -6]

zwróci obiekt z usuniętymi elementami od dwóch do sześciu. Obiekt można podzielić na jeden zestaw nawiasów kwadratowych i ponownie na inny zestaw nawiasów kwadratowych. Na przykład:

a [1:10] [b> 3],

gdzie długość a jest większa lub równa dziesięć, a b ma długość dziesięć. Wyrażenie zwróci te elementy pierwszych dziesięciu elementów a, dla których odpowiadający element b jest większy niż trzy. Podzbiór można kontynuować, dodając więcej zestawów nawiasów kwadratowych. Każdy zestaw będzie działał na podstawie wszystkich poprzednich podzbiorów

kNN: Systemy rekomendacji

Algorytm k-Najbliższych Sąsiadów

Wcześniej widzieliśmy, jak moglibyśmy zastosować proste techniki korelacyjne, aby stworzyć miarę podobieństwa między członkami Kongresu na podstawie ich wyników głosowania. Tu porozmawiamy o tym, jak korzystać z tych samych wskaźników podobieństwa, aby polecać produkty użytkownikom witryny. Algorytm, którego użyjemy, nazywa się k-najbliższych sąsiadów. Jest to prawdopodobnie najbardziej intuicyjny ze wszystkich algorytmów uczenia maszynowego, które prezentujemy. Rzeczywiście, najprostszą formą najbliższych sąsiadów jest algorytm, który większość ludzi wymyśliłaby spontanicznie, gdyby poproszono ich o rekomendacje na podstawie danych podobieństwa: poleciliby utwór, który jest najbliższy utworom, które użytkownik już lubi, ale których jeszcze nie ma na tej liście. Ta intuicja jest zasadniczo algorytmem  najbliższego sąsiada. Algorytm pełnego k-najbliższego sąsiada stanowi uogólnienie tej intuicji, w której przed wydaniem zalecenia korzystasz z więcej niż jednego punktu danych. Algorytm pełnego k najbliższych sąsiadów działa bardzo podobnie, jak niektórzy z nas proszą o rekomendacje od naszych przyjaciół. Najpierw zaczynamy od ludzi, których gust dzielimy, a potem prosimy ich, aby coś nam polecili. Jeśli wielu z nich poleca to samo, wywnioskujemy, że nam się spodoba. Jak możemy wziąć tę intuicję i przekształcić ją w coś algorytmicznego? Zanim zaczniemy opracowywać rekomendacje na podstawie rzeczywistych danych, zacznijmy od czegoś prostszego: podzielenie punktów na dwie kategorie. Jeśli pamiętasz, jak po raz pierwszy zmotywowaliśmy problem klasyfikacji spamu

Jak wyjaśniliśmy, możesz użyć regresji logistycznej za pomocą funkcji glm, aby podzielić te punkty za pomocą pojedynczej linii, którą nazwaliśmy granicą decyzji. W tym samym czasie, gdy wyjaśniliśmy, jak stosować regresję logistyczną, powiedzieliśmy również, że istnieją problemy których nie można rozwiązać za pomocą prostej liniowej granicy decyzji.

Jak możesz spróbować zbudować klasyfikator, który pasowałby do bardziej skomplikowanej granicy decyzyjnej, takiej jak ta pokazana na powyższym rysunku? Możesz spróbować wymyślić metodę nieliniową; sztuczka jądra, którą omówimy później, jest przykładem tego podejścia.

Innym podejściem byłoby wykorzystanie punktów najbliższych punktowi, który próbujesz sklasyfikować, aby zgadnąć. Możesz na przykład narysować okrąg wokół punktu, na który patrzysz, a następnie zdecydować o klasyfikacji na podstawie punktów w tym okręgu. 

Ten algorytm jest całkiem użyteczny, ale ma jedną zauważalną wadę: musimy wybrać promień okręgu, którego użyjemy do zdefiniowania „lokalnych” punktów. Jeśli wszystkie twoje punkty danych mają sąsiadów w przybliżeniu w tej samej odległości, nie będzie problemu. Ale jeśli niektóre punkty mają wielu bliskich sąsiadów, podczas gdy inne prawie ich nie mają, w końcu wybierzesz okrąg, który jest tak duży, że wykracza daleko poza granice decyzji dla niektórych punktów. Co możemy zrobić, aby obejść ten problem? Oczywistym rozwiązaniem jest uniknięcie użycia koła do zdefiniowania sąsiadów punktu i zamiast tego spojrzenie na k-najbliższych punktów. Punkty te nazywane są najbliższymi sąsiadami. Gdy już je mamy, możemy spojrzeć na ich klasyfikacje i użyć reguły większości, aby zdecydować o klasie dla naszego nowego punktu. Zbudujmy kod, aby właśnie to zrobić.

Najpierw przeczytamy w naszym zestawie danych:

df <- read.csv(‘data/example_data.csv’)

head(df)

# X Y Label

#1 2.373546 5.398106 0

#2 3.183643 4.387974 0

#3 2.164371 5.341120 0

#4 4.595281 3.870637 0

#5 3.329508 6.433024 0

#6 2.179532 6.980400 0

Następnie musimy obliczyć odległość między każdym punktem w naszym zbiorze danych. Będziemy przechowywać te informacje w macierzy odległości, która jest prostą macierzą 2D, w której odległość między punktem i a punktem j znajduje się przy wprowadzeniu tablicy odległości. Matryca [i, j]. Poniższy kod tworzy tę macierz odległości przy użyciu wzoru odległości euklidesowej:

distance.matrix <- function(df)

{

distance <- matrix(rep(NA, nrow(df) ^ 2), nrow = nrow(df))

for (i in 1:nrow(df))

{

for (j in 1:nrow(df))

{

distance[i, j] <- sqrt((df[i, ‘X’] – df[j, ‘X’]) ^ 2 + (df[i, ‘Y’] – df[j, ‘Y’])

^ 2)

}

}

return(distance)

}

Kiedy mamy już macierz odległości, potrzebujemy funkcji, która zwróci k najbliższych sąsiadów dla punktu. Jest to naprawdę łatwe do zaimplementowania w R, ponieważ możesz po prostu spojrzeć na i-ty rząd macierzy odległości, aby dowiedzieć się, jak daleko są wszystkie inne punkty od twojego punktu wejściowego. Po posortowaniu tego wiersza masz uporządkowaną listę sąsiadów i ich odległość od punktu wejściowego.

Po prostu wybierz pierwsze k wpisów po zignorowaniu punktu wejściowego (który zawsze powinien być pierwszym punktem w macierzy odległości), a będziesz mieć k najbliższych sąsiadów swojego punktu wejściowego.

k.nearest.neighbors <- function(i, distance, k = 5)

{

return(order(distance[i, ])[2:(k + 1)])

}

Gdy to zrobisz, zbudujemy funkcję knn, która pobiera ramkę danych i wartość k, a następnie generuje prognozy dla każdego punktu w ramce danych. Nasza funkcja nie jest bardzo ogólna, ponieważ zakładamy, że etykiety klas znajdują się w kolumnie o nazwie Etykieta, ale jest to tylko szybkie ćwiczenie, aby zobaczyć, jak działa algorytm. Istnieją już implementacje k-najbliższych sąsiadów w R, które możesz wykorzystać do praktycznej pracy, a my omówimy je za chwilę

knn <- function(df, k = 5)

{

distance <- distance.matrix(df)

predictions <- rep(NA, nrow(df))

for (i in 1:nrow(df))

{

indices <- k.nearest.neighbors(i, distance, k = k)

predictions[i] <- ifelse(mean(df[indices, ‘Label’]) > 0.5, 1, 0)

}

return(predictions)

}

Jak widać, wykorzystaliśmy zasady głosowania większością do naszych prognoz, przyjmując średnią etykietę, a następnie próg na poziomie 0,5. Wywołanie tej funkcji zwraca wektor prognoz, dlatego dołączamy je do naszej ramki danych, a następnie oceniamy naszą wydajność:

df <- transform(df, kNNPredictions = knn(df))

sum(with(df, Label != kNNPredictions))

#[1] 7

nrow(df)

#[1] 100

Niepoprawnie przewidzieliśmy etykiety dla 7 punktów na 100, więc mamy 93% czasu. To niezła wydajność jak na tak prosty algorytm. Teraz, gdy wyjaśniliśmy, jak działa algorytm k-najbliższych sąsiadów (kNN), zastosujemy kNN do niektórych rzeczywistych danych o użyciu pakietów R. Ale zanim to zrobimy, pokażemy Ci, jak używać implementacji kNN w czarnej skrzynce do własnych projektów:

rm (‘knn’) # Jeśli nadal masz naszą implementację w pamięci.

library(‘class’)

df <- read.csv(‘data/example_data.csv’)

n <- nrow(df)

set.seed(1)

indices <- sort(sample(1:n, n * (1 / 2)))

training.x <- df[indices, 1:2]

test.x <- df[-indices, 1:2]

training.y <- df[indices, 3]

test.y <- df[-indices, 3]

predicted.y <- knn(training.x, test.x, training.y, k = 5)

sum(predicted.y != test.y)

#[1] 7

length(test.y)

#[1] 50

Tutaj przetestowaliśmy funkcję knn z pakietu klas przy użyciu weryfikacji krzyżowej. O dziwo, tutaj również błędnie popełniamy 7 etykiet, ale zestaw testowy zawiera tylko 50 przykładów, więc osiągamy jedynie 86% dokładności. To wciąż jest całkiem niezłe. Pokażmy tylko, jak działałby model logistyczny, aby dać ci punkt porównania:

logit.model <- glm(Label ~ X + Y, data = df[indices, ])

predictions <- as.numeric(predict(logit.model, newdata = df[-indices, ]) > 0)

sum(predictions != test.y)

#[1] 16

Jak widać, najlepszy klasyfikator logistyczny błędnie przewiduje 16 punktów danych, co daje mu dokładność 68%. Kiedy twój problem jest daleki od liniowości, kNN będzie działać od razu znacznie lepiej niż inne metody.

(I) : Operatory relacyjne

Operatory relacyjne są używane w testach logicznych. Sześć operatorów relacyjnych to == dla równości,! = Dla nierówności, <dla mniej niż, <= dla mniejszej lub równej,> dla większej niż i> = dla większej niż lub równej. Lista operatorów logicznych znajduje się poniżej

== : równa się : a == 9

!= : nie równy : a! = 9

> : większe niż : a> 9

> = : większy lub równy : a> = 9

< : mniej niż :  a < 9

<= : mniejszy lub równy : a <= 9

Zauważ, że operator relacyjny równy to ==, a nie =. Częstym błędem jest wpisanie = dla == w wyrażeniu logicznym. R zwróci błąd dla =. Podobnie jak w przypadku operatorów arytmetycznych, wyrażenia logiczne można grupować za pomocą nawiasów. Na przykład,

((a > 0 & b > 0) i (a < 5 & b < 5))

jest wyrażeniem logicznym i można mu przypisać nazwę.

Stronę pomocy CRAN dla operatorów relacyjnych można znaleźć, wpisując ??„ relational operators” w wierszu polecenia R.

Operatory subskrypcji

Wiele obiektów w R ma więcej niż jeden element. Indeksowanie służy do uzyskiwania dostępu do określonych elementów obiektu. Wektory, macierze, tablice, listy i gniazda mogą być indeksowane. Do indeksowania używane są pojedyncze nawiasy kwadratowe ([]), podwójne nawiasy kwadratowe ([[]]), znaki dolara ($) i symbole (@). Żadne nie są używane gdzie indziej.

Eksploracja grupowania senatora MDS przez Kongres

Tak jak poprzednio, pierwszym krokiem jest użycie matrycy senator po głosowaniu do stworzenia macierzy odległości senator po senatorze, na której wykonamy MDS. Użyjemy funkcji lapply do wykonania kroków konwersji dla każdego Kongresu osobno. Zaczynamy od mnożenia macierzy i zapisywania wyników w zmiennej rollcall.dist. Następnie wykonujemy MDS za pomocą funkcji cmdscale za pomocą innego wywołania do okrążenia zagięcie. Należy zwrócić uwagę na dwie rzeczy związane z działaniem MDS. Po pierwsze, domyślnie cmdscale oblicza MDS dla dwóch wymiarów, więc jesteśmy zbędni, ustawiając k = 2. Przydatne jest jednak wyraźne wyrażanie się podczas wykonywania tej operacji podczas udostępniania kodu, dlatego dodajemy go tutaj jako najlepszą praktykę. Po drugie, zauważ, że mnożymy wszystkie punkty przez –1. Odbywa się to wyłącznie w celu wizualizacji, odwrócenie pozycjonowania osi x wszystkich punktów, i jak zobaczymy, umieszcza Demokratów po lewej stronie i republikanów po prawej. W kontekście amerykańskim jest to przydatna wskazówka wizualna, ponieważ zazwyczaj myślimy o Demokratach jako ideologicznie lewicy, a republikanach o prawicy. Jak zapewne się domyślacie, zauważyliśmy tylko, że Demokraci znajdą się po prawej stronie, a republikanie po lewej stronie punktów osi X dla MDS po wizualizacji. Częścią dobrego wykonywania analizy danych jest elastyczność i krytyczne myślenie o tym, jak możesz poprawić swoją metodę lub prezentację wyników po zakończeniu im. Chociaż więc prezentujemy to tutaj liniowo, należy pamiętać, że w praktyce decyzja o odwróceniu osi x w wizualizacji zapadła dopiero po pierwszym przejściu ćwiczenia.

rollcall.dist <- lapply (rollcall.simple, function (m) dist (m% *% t (m)))

rollcall.mds <- lapply (rollcall.dist,

function (d) as.data.frame ((cmdscale (d, k = 2)) * -1))

Następnie musimy dodać odpowiednie dane identyfikacyjne do ramek danych punktów współrzędnych w rollcall.mds, abyśmy mogli je wizualizować w kontekście przynależności do partii. W następnym bloku kodu zrobimy to za pomocą prostej pętli for na liście rollcall.mds. Najpierw ustawiamy nazwy kolumn punktów współrzędnych na x i y. Następnie uzyskujemy dostęp do oryginalnych ramek danych wywołania w rollcall.data i wyodrębniamy kolumnę nazw senatorów. Przypomnijmy, że musimy najpierw usunąć wiceprezydenta. Ponadto niektóre nazwiska senatorów obejmują imiona i nazwiska, ale w większości tylko ostatnie. Aby zachować spójność, usuwamy imiona, dzieląc wektor znaków nazwy przecinkiem i przechowujemy ten wektor w zmiennej congress.names. Na koniec używamy funkcji transformacji, aby dodać przynależność do partii jako czynnik i dodać numer Kongresu.

congresses <- 101:111

for(i in 1:length(rollcall.mds)) {

names(rollcall.mds[[i]]) <- c(“x”, “y”)

congress <- subset(rollcall.data[[i]], state < 99)

congress.names <- sapply(as.character(congress$name),

function(n) strsplit(n, “[, ]”)[[1]][1])

rollcall.mds[[i]] <- transform(rollcall.mds[[i]], name=congress.names,

party=as.factor(congress$party), congress=congresses[i])

}

head(rollcall.mds[[1]])

x y name party congress

2 -11.44068 293.0001 SHELBY 100 101

3 283.82580 132.4369 HEFLIN 100 101

4 885.85564 430.3451 STEVENS 200 101

5 1714.21327 185.5262 MURKOWSKI 200 101

6 -843.58421 220.1038 DECONCINI 100 101

7 1594.50998 225.8166 MCCAIN 200 101

Sprawdzając nagłówek pierwszego elementu w rollcall.mds po dodaniu danych kontekstowych, możemy zobaczyć ramkę danych, której użyjemy do wizualizacji. W pliku kodu R zawartym w tej sekcji mamy długi zestaw poleceń do zapętlania tej listy ramek danych w celu tworzenia indywidualnych wizualizacji dla wszystkich kongresów. Dla zwięzłości zamieszczamy tutaj jednak tylko część tego kodu. Podany kod wykreśli dane dla 110. Senatu, ale można go łatwo zmodyfikować w celu wykreślenia każdego innego Kongresu.

cong.110 <- rollcall.mds[[9]]

base.110 <- ggplot(cong.110, aes(x=x, y=y))+scale_size(to=c(2,2), legend=FALSE)+

scale_alpha(legend=FALSE)+theme_bw()+

opts(axis.ticks=theme_blank(), axis.text.x=theme_blank(),

axis.text.y=theme_blank(),

title=”Roll Call Vote MDS Clustering for 110th U.S. Senate”,

panel.grid.major=theme_blank())+

xlab(“”)+ylab(“”)+scale_shape(name=”Party”, breaks=c(“100″,”200″,”328”),

labels=c(“Dem.”, “Rep.”, “Ind.”), solid=FALSE)+

scale_color_manual(name=”Party”, values=c(“100″=”black”,”200″=”dimgray”,

“328”=”grey”),

breaks=c(“100″,”200″,”328”), labels=c(“Dem.”, “Rep.”, “Ind.”))

print(base.110+geom_point(aes(shape=party, alpha=0.75, size=2)))

print(base.110+geom_text(aes(color=party, alpha=0.75, label=cong.110$name, size=2)))

Wiele z tego, co robimy z ggplot2, powinno być już znane. Jednak w tym przypadku korzystamy z jednej niewielkiej zmiany w sposobie budowania grafiki.

Typową procedurą jest utworzenie obiektu ggplot, a następnie dodanie warstwy geom lub stat, ale w tym przypadku tworzymy obiekt podstawowy o nazwie case.110, który zawiera wszystkie szczegóły dotyczące formatowania tych wykresów. Obejmuje to warstwy rozmiaru, alfa, kształtu, koloru i opts. Robimy to, ponieważ chcemy zrobić dwa wykresy: po pierwsze wykres samych punktów, w których kształt odpowiada przynależności do partii; a po drugie, fabuła, w której nazwiska senatorów są używane jako punkty, a kolor tekstu odpowiada przynależności do partii. Najpierw dodając wszystkie te warstwy formatujące do base.110, możemy po prostu dodać do bazy warstwę sgeom_point lub geom_text, aby uzyskać żądany wykres. Rysunek pokazuje wyniki tych wykresów.

Zaczynamy od odpowiedzi na nasze początkowe pytanie: czy senatorowie z różnych partii mieszają się, gdy są zebrani według rekordów głosowania imiennego? Na rysunku  odpowiedź jest jednoznaczna „nie”. Wydaje się, że istnieje dość duża różnica między demokratami a republikanami. Dane potwierdzają również, że senatorzy często uważani za najbardziej ekstremalnych, są w rzeczywistości wartościami odstającymi. Po lewej stronie widzimy Senatora Sandersa, niezależnego Vermonta, a po prawej senatorów Coburna i DeMinta. Podobnie senatorzy Collins i Snowe są ściśle skupieni w centrum 111. Kongresu. Jak zapewne pamiętacie, to ci umiarkowani republikańscy senatorowie stali się centralnymi postaciami w wielu ostatnich wielkich bitwach legislacyjnych w Senacie USA. Innym interesującym wynikiem tej analizy jest pozycjonowanie senatorów Obamy i McCaina w 110. Senacie. Obama wydaje się wyróżniony w lewej górnej ćwiartce fabuły, podczas gdy McCain jest skupiony z senatorami Wicker i Thomasem, bliżej centrum. Chociaż może to być kuszące, aby interpretować to jako oznaczające, że dwaj senatorowie mieli bardzo komplementarne zapisy z głosowania, biorąc pod uwagę charakter kodowania danych, bardziej prawdopodobne jest, że w wyniku kampanii brakuje dwóch takich samych głosów. Oznacza to, że kiedy głosowali nad tym samym projektem ustawy, mogli mieć stosunkowo różne nawyki głosowania, chociaż nie bardzo różne zapisy głosowania, ale kiedy brakowało głosów, często dotyczyło tego samego aktu prawnego. Oczywiście rodzi się pytanie: jak interpretujemy pozycję Wiklina i Thomasa? Dla naszej ostatecznej wizualizacji zbadamy wykresy MDS dla wszystkich kongresów w czasie chronologicznym. To powinno dać nam pewne wskazówki na temat ogólnego mieszania senatorów przez partię w czasie, a to da nam bardziej zasadnicze spojrzenie na stwierdzenie, że Senat jest bardziej spolaryzowany niż kiedykolwiek wcześniej. W poprzednim bloku kodu generujemy pojedynczy wykres ze wszystkich danych, zwijając rollcall.mds w pojedynczą ramkę danych za pomocą do.call i rbind. Następnie tworzymy dokładnie ten sam wykres, który stworzyliśmy w poprzednim kroku, z tym wyjątkiem, że dodajemy facet_wrap, aby wyświetlić wykresy MDS w chronologicznej siatce według Kongresu. Rysunek 9-5 przedstawia wyniki tej wizualizacji.

all.mds <- do.call(rbind, rollcall.mds)

all.plot <- ggplot(all.mds, aes(x=x, y=y))+

geom_point(aes(shape=party, alpha=0.75, size=2))+

scale_size(to=c(2,2), legend=FALSE)+

scale_alpha(legend=FALSE)+theme_bw()+

opts(axis.ticks=theme_blank(), axis.text.x=theme_blank(),

axis.text.y=theme_blank(),

title=”Roll Call Vote MDS Clustering for U.S. Senate

(101st – 111th Congress)”,

panel.grid.major=theme_blank())+

xlab(“”)+ylab(“”)+

scale_shape(name=”Party”, breaks=c(“100″,”200″,”328”),

labels=c(“Dem.”, “Rep.”, “Ind.”),

solid=FALSE)+facet_wrap(~ congress)

all.plot

Używając głosowania imiennego jako miernika różnicy między senatorami, z tych wyników wynika, że ​​senat USA jest tak samo stronniczy, jak nigdy dotąd. Ogólnie rzecz biorąc, widzimy tylko duże grupy trójkątów i kół skupionych razem, z niewielką liczbą wyjątków na każdym Kongresie. Można powiedzieć, że 101. i 102. kongresy były mniej spolaryzowane, ponieważ klastry wydają się być bliżej. Ale to jest artefakt skali osi. Przypomnijmy, że procedura MDS stara się po prostu zminimalizować funkcję kosztów opartą na obliczonej macierzy odległości wśród wszystkich obserwacji. To, że skale dla 101. i 102. kongresu są mniejsze niż w przypadku wielu innych fabuł, nie oznacza, że ​​kongresy te są mniej spolaryzowane. Różnice te mogą wynikać z wielu powodów, takich jak liczba obserwacji. Ponieważ jednak wizualizowaliśmy je na jednym wykresie, skale muszą być jednolite na wszystkich panelach, co może powodować ,że niektóre wydają się ściśnięte, a inne rozciągnięte. Ważną rzeczą wynikającą z tego spisku jest to, że bardzo mało jest mieszania się stron, gdy grupujesz je za pomocą głosowania imiennego. Chociaż wewnątrz partii mogą występować niewielkie różnice, jak widać po rozwarstwieniu punktów koła lub trójkąta, różnice między stronami są bardzo małe. W prawie wszystkich przypadkach widzimy Demokratów skupionych z Demokratami i Republikanów z Republikanami. Oczywiście istnieje wiele innych informacji poza przynależnością do partii, które można by dodać do tego wątku. Możemy na przykład zastanawiać się, czy senatorowie z tego samego regionu geograficznego gromadą razem. Albo możemy się zastanawiać, czy członkostwo w komitecie prowadzi do grupowania. To są wszystkie interesujące pytania i zachęcamy do lektury

(I) : Operatory i funkcje macierzy

R udostępnia operatory i funkcje do manipulowania macierzami

Operator / Funkcja         :         Działanie                    :              Przykład

% *%                      mnożenie macierzy                      a% *% b

%o% lub outer()           produkt zewnętrzny dwóch wektorów, macierze lub  tablice                                 a% *% b, outer (a, b)

t()                  transpozycja macierzy                                                 t(a)

crossprod() lub tcrossprod ()     produkt krzyżowy macierzy lub  dwie macierze                                                                crossprod(a) lub crossprod(a, b) lub  crossprod(a) lub tcrossprod(a, b)

diag()          przekątna matrycy lub macierz diagonalna         diag(a),a jest macierzą lub diag(a),a jest wektorem

solve()      wrotność macierzy lub rozwiązanie dla Xa =   b                                             solve(a), solve(X,b)

Operatorem mnożenia macierzy jest% *%. R zwróci błąd, jeśli dwie macierze nie będą zgodne. Dla dwóch tablic (tablice obejmują wektory i macierze),% o% lub outer (), daje zewnętrzny produkt tablic.

Aby transponować macierz, użyj funkcji t (), na przykład t (a). Aby uzyskać iloczyn krzyżowy jednej macierzy z drugą (lub macierzą oryginalną), użyj funkcji crossprod () lub funkcji tcrossprod (). Jeśli aib są matrycami zgodnymi, to

crossprod (a) = t (a)% *% a,

tcrossprod (a) = a% *% t (a),

crossprod (a, b) = t (a)% *% b,

tcrossprod (a, b) = a% *% t (b).

Aby znaleźć odwrotność niesingularnej macierzy kwadratowej, użyj funkcji solver (), na przykład solass (a). Funkcja rozwiązywanie () może również rozwiązać równanie liniowe

Xa = b,

dla a, gdzie X jest niejednorodną macierzą kwadratową, a b ma taką samą liczbę wierszy jak X. Składnia jest rozwiązana (X, b). Aby utworzyć macierz diagonalną lub uzyskać diagonalną macierz, użyj funkcji diag (). Jeśli a jest wektorem, diag (a) zwróci macierz diagonalną o przekątnej równej a.

Na przykład:

> a = 1:2

> a

[1] 1 2

> diag(a)

[,1] [,2]

[1,] 1 0

[2,] 0 2

Jeśli a jest macierzą, diag (a) zwróci ukośne elementy macierzy, nawet jeśli macierz nie jest kwadratowa. Na przykład:

> a = matrix(1:6,2,3)

> a

[,1] [,2] [,3]

[1,] 1 3 5

[2,] 2 4 6

> diag(a)

[1] 1 4

Aby uzyskać więcej informacji, stronę pomocy CRAN dotyczącą mnożenia macierzy można znaleźć, wprowadzając ??„ matrix multiplication” po znaku zachęty R. W przypadku pięciu funkcji wpisanie? Nazwa, gdzie nazwa jest nazwą funkcji, powoduje wyświetlenie strony pomocy dla funkcji.

Analiza danych z apelu amerykańskiego senatora (kongresy 101–111)

Jak wspomniano, zebraliśmy wszystkie dane do głosowania imiennego Senatu na kongresach 101. do 111. i umieściliśmy je w katalogu danych. Jak zrobiliśmy w całym tym tekście, rozpoczniemy to studium przypadku, ładując dane i sprawdzając je. W tym procesie wykorzystamy dwie biblioteki R: po pierwsze, bibliotekę zagraniczną, które omówimy za chwilę; a po drugie, ggplot2, którego użyjemy do wizualizacji wyników algorytmu MDS. Pliki znajdują się w data / roll_call /, więc używamy funkcji list.files do generowania wektora znakowego o nazwie data.files ze wszystkimi nazwami plików danych.

library(foreign)

library(ggplot2)cac

data.dir <- “data/roll_call/”

data.files <- list.files(data.dir)

Kiedy sprawdzamy zmienną data.files, widzimy, że rozszerzenie plików danych różni się od plików tekstowych, których używaliśmy do naszych studiów przypadków w poprzednich częściach. Rozszerzenie .dta odpowiada plikowi danych Stata. Stata to komercyjny program do obliczeń statystycznych, który okazuje się być bardzo popularny wśród naukowców, szczególnie naukowców. Ponieważ Poole i Rosenthal postanowili rozpowszechnić dane w tym formacie, więc będziemy potrzebować sposobu załadowania tych danych do R.

data.files

[1] “sen101kh.dta” “sen102kh.dta”

[3] “sen103kh.dta” “sen104kh.dta”

[5] “sen105kh.dta” “sen106kh.dta”

[7] “sen107kh.dta” “sen108kh_7.dta”

[9] “sen109kh.dta” “sen110kh_2008.dta”

[11] “sen111kh.dta”

Wprowadź obcy pakiet, który jest przeznaczony do odczytu dużej liczby egzotycznych plików danych do ramek danych R, w tym S, SAS, SPSS, Systat, dBase i wielu innych. Do naszych celów wykorzystamy funkcję read.dta, która jest przeznaczona do odczytu plików Stata. Na potrzeby tej analizy chcemy przeanalizować dane dla 10 kongresów, od 101 do 111. Wszystkie te dane przechowamy w jednym obiekcie, którym można manipulować jednocześnie. Jak zobaczymy, te zestawy danych są stosunkowo małe, więc w tym przypadku nie martwimy się o pamięć. Aby połączyć nasze zestawy danych, użyjemy funkcji lapply w połączeniu z read.dta.

rollcall.data <- lapply(data.files,

function(f) read.dta(paste(data.dir, f, sep=””), convert.factors=FALSE))

Mamy teraz wszystkie 10 ramek danych głosowań imiennych w zmiennej rollcall.data. Kiedy sprawdzamy wymiar pierwszej ramki danych, 101. kongresu, widzimy, że ma ona 103 wiersze i 647 kolumn. Po dalszym sprawdzeniu nagłówka tej ramki danych możemy zobaczyć, co znajduje się w tych wierszach i kolumnach. Podczas sprawdzania głowy danych należy zwrócić uwagę na dwie ważne rzeczy. Po pierwsze, każdy wiersz odpowiada wyborcy w Senacie USA. Po drugie, pierwsze dziewięć kolumn ramki danych zawiera informacje identyfikacyjne dla tych wyborców, a pozostałe kolumny to rzeczywiste głosy. Zanim przejdziemy dalej, musimy zrozumieć te informacje identyfikacyjne.

dim(rollcall.data[[1]])

[1] 103 647

head(rollcall.data[[1]])

cong id state dist lstate party eh1 eh2 name V1 V2 V3 … V638

1 101 99908 99 0 USA 200 0 0 BUSH 1 1 1 … 1

2 101 14659 41 0 ALABAMA 100 0 1 SHELBY, RIC 1 1 1 … 6

3 101 14705 41 0 ALABAMA 100 0 1 HEFLIN, HOW 1 1 1 … 6

4 101 12109 81 0 ALASKA 200 0 1 STEVENS, TH 1 1 1 … 1

5 101 14907 81 0 ALASKA 200 0 1 MURKOWSKI, 1 1 1 … 6

6 101 14502 61 0 ARIZONA 100 0 1 DECONCINI, 1 1 1 … 6

Niektóre kolumny są dość oczywiste, takie jak lstate i name, ale co z eh1 i eh2? Na szczęście Poole i Rosenthal udostępniają książkę kodów dla wszystkich danych apelowych. Książka kodów dla 101. kongresu znajduje się na stronie http://www.voteview.com/senate101. Ten słownik kodów jest szczególnie pomocny ponieważ wyjaśnia nie tylko, co zawiera każda z pierwszych dziewięciu kolumn, ale także sposób kodowania każdego z głosów, na co będziemy musieli wkrótce zwrócić uwagę.

  1. Numer kongresu
  2. Numer identyfikacyjny ICPSR: 5-cyfrowy kod przypisany przez ICPSR, poprawiony przez Howarda Rosenthala i mnie.
  3. Kod stanu: 2-cyfrowy kod stanu ICPSR.
  4. Numer dystryktu kongresowego (0, jeśli Senat)
  5. Nazwa stanu
  6. Kod imprezy: 100 = Dem., 200 = Repub. (Patrz PARTY3.DAT)
  7. Obłożenie: Kod zajętości ICPSR – 0 = tylko mieszkaniec; 1 = 1. mieszkaniec; 2 = 2. mieszkaniec; itp.
  8. Ostatni sposób objęcia urzędu: Kodeks zdobycia urzędu ICPSR – 1 = wybory powszechne;

2 = wybory specjalne; 3 = wybrany przez ustawodawcę stanowego; 5 = wyznaczony

  1. Imię i nazwisko

10 – do liczby apeli + 10: dane apeli –

0 = nie jest członkiem, 1 = Tak, 2 = Sparowane Tak, 3 = Ogłoszono Tak,

4 = nie ogłoszono, 5 = powiązano, 6 = nie,

7 = Obecne (niektóre kongresy, również nieużywane niektóre kongresy),

8 = Obecne (niektóre Kongresy, również nie korzystały z niektórych Kongresów),

9 = Nie głosować

Do naszych celów jesteśmy zainteresowani jedynie nazwiskami wyborców, ich przynależnością do partii i ich faktycznymi głosami. Z tego powodu naszym pierwszym krokiem jest uzyskanie danych głosowania imiennego w formie, z której możemy stworzyć rozsądną miarę odległości od głosów. Jak widać w przykładzie 9-1, głosowanie imienne w Senacie nie jest po prostu tak lub nie; istnieją ogłoszone i sparowane formy głosów Yea i Nay, a także Obecne głosy, to znaczy głosy, w których senator wstrzymał się od głosowania nad konkretnym projektem ustawy, ale był obecny w czasie głosowania. Są też chwile, kiedy senatorzy po prostu nie byli obecni, aby oddać głos, ani nawet nie zostali wybrani do Senatu. Biorąc pod uwagę różnorodność możliwych głosów, w jaki sposób bierzemy te dane i przekształcamy je w coś, co możemy łatwo wykorzystać do pomiaru odległości między senatorami? Jednym z podejść jest uproszczenie kodowania danych poprzez agregację podobnych typów głosów. Na przykład głosowanie w parach jest procedurą, w ramach której członkowie Kongresu wiedzą, że nie będą obecni podczas danego głosowania imiennego, a ich głos może zostać „sparowany” z innym członkiem, który głosuje przeciwnie. To, wraz z ogłoszonymi głosowaniami, jest środkiem parlamentarnym dla Senatu lub Izby w celu ustalenia kworum do przeprowadzenia głosowania. Dla naszych celów jesteśmy jednak mniej zainteresowani mechanizmem, w którym głosowanie się odbyło, a raczej zamierzonym wynikiem głosowania, tj. Za lub przeciw. Jako taki, jedną metodą agregacji byłoby grupowanie wszystkich typów Yea i Nay razem. Zgodnie z tą samą logiką możemy zgrupować wszystkie typy, które nie oddają głosu.

rollcall.simplified <- function(df) {

no.pres <- subset(df, state < 99)

for(i in 10:ncol(no.pres)) {

no.pres[,i] <- ifelse(no.pres[,i] > 6, 0, no.pres[,i])

no.pres[,i] <- ifelse(no.pres[,i] > 0 & no.pres[,i] < 4, 1, no.pres[,i])

no.pres[,i] <- ifelse(no.pres[,i] > 1, -1, no.pres[,i])

}

return(as.matrix(no.pres[,10:ncol(no.pres)]))

}

rollcall.simple <- lapply(rollcall.data, rollcall.simplified)

Rysunek

ilustruje procedurę, którą zastosujemy w celu uproszczenia kodowania z Poole i Rosenthal, która zostanie wykorzystana w naszej analizie. Podobnie jak w symulowanym przykładzie w poprzedniej sekcji, zakodujemy wszystkie Yeas jako +1, wszystkie Nays jako –1, a wszystkie obserwacje bez głosu jako 0. To pozwala na bardzo proste zastosowanie kodowania danych do metryki odległości. Teraz musimy przekonwertować dane na nasze nowe kodowanie. Musimy także wyodrębnić tylko głosy z ramki danych, abyśmy mogli wykonać niezbędną manipulację macierzą. Aby to zrobić, definiujemy funkcję rollcall.simplified, która przyjmuje ramkę danych wywołania roll jako swój jedyny argument i zwraca matrycę senator według głosów z naszym uproszczonym kodowaniem. Zauważysz, że pierwszy krok w tej funkcji usuwa wszystkie obserwacje, w których kolumna stanu jest równa 99. Kod stanu 99 odpowiada wiceprezydentowi Stanów Zjednoczonych, a ponieważ wiceprezydent bardzo rzadko głosuje, usuwamy go. Następnie używamy polecenia ifelse, aby wykonać wektoryzowane porównanie numeryczne dla wszystkich kolumn w pozostałej macierzy. Pamiętaj, że kolejność, w jakiej dokonujemy tego porównania, ma znaczenie. Zaczynamy od ustawienia wszystkich nonvotes (wszystko powyżej 6) na zero. Możemy wtedy szukać głosów zakodowanych powyżej 0 i mniej niż 4, Yeas, i przekonwertować je na 1. W końcu wszystko większe niż 4 to NIE, więc kodujemy je jako –1. Mamy teraz dane apelowe w tej samej formie, w jakiej zaczęliśmy dla naszych danych symulowanych z poprzedniej sekcji, i możemy kontynuować te dane dokładnie tak samo, jak w przypadku danych symulowanych recenzji konsumenckich. W następnej i ostatniej sekcji wygenerujemy MDS tych danych i zbadamy je wizualnie.

(I) : Operatory arytmetyczne

Operatory arytmetyczne mogą mieć operandy numeryczne lub operandy, które można przekonwertować na liczby. Na przykład dla obiektów logicznych PRAWDA jest koercyjna na 1, a FAŁSZ – 0. W przypadku niektórych typów obiektów określone operatory mają inne znaczenie, ale te typy obiektów nie zostaną omówione w tym rozdziale. Wyrażenia arytmetyczne są oceniane elementarnie. Jeśli liczba elementów nie jest taka sama między obiektami w wyrażeniu, mniejszy obiekt przechodzi cyklicznie przez większy do końca większego. Liczba elementów w większym obiekcie nie musi być wielokrotnością mniejszego obiektu w celu przełączania. Wyrażenia są oceniane od lewej do prawej, zgodnie z regułami pierwszeństwa. Operatory arytmetyczne są standardem * dla mnożenia, / dla dzielenia, + dla dodawania i – dla odejmowania. Symbolem potęgowania jest ^. Operator %% daje

moduł pierwszego argumentu w odniesieniu do drugiego argumentu. Operator% /% dokonuje podziału na liczby całkowite. Wyrażenia można grupować za pomocą nawiasów, na przykład (a + b) / c.

Operator             :              Działanie            :              Przykład

*                                            mnożenie                           a * b

/                                             dzielenie                             a / b

+                                             dodawanie                        a + b

–                                             odejmowanie                   a-b

^                                            potęgowanie                    a ^ b

%%                                        modulo                                               a %% b

% /%                                     dzielenie całkowite        a% /% b

Aby uzyskać więcej informacji, strony pomocy CRAN dla operatorów arytmetycznych można znaleźć, wpisując ??“arithmetic operators” w wierszu polecenia R.

Jak klaster senatorów USA?

Obecny 111-ty Kongres, , jest najbardziej ideologicznie spolaryzowany we współczesnej historii. W Izbie i Senacie najbardziej konserwatywny demokrata jest bardziej liberalny niż najbardziej liberalny republikanin. Jeśli zdefiniuje się „centrum” kongresu jako nakładanie się dwie strony, centrum zniknęło. –— William A. Galston, The Brookings Institute (2010)

Często słyszymy uwagi, takie jak ta Williama A. Galstona, Senior Fellow w Governance Studies w Brookings Institute, twierdząc, że polaryzacja w Kongresie USA jest najwyższa w historii. Łatwo zrozumieć, dlaczego. Takie portrety są często wykonywane w popularnej prasie i głównych mediach w Stanach Zjednoczonych często pracują nad wzmocnieniem tych różnic. Jeśli myślimy o ustawowym bagnie jako produkcie ubocznym tej polaryzacji, wówczas możemy spojrzeć na wyniki legislacyjne jako przybliżoną miarę polaryzacji. Na 110. Kongresie wprowadzono prawie 14 000 aktów prawnych, ale tylko 449 ustaw, czyli 3,3%, faktycznie stało się prawem . W rzeczywistości z 449 rachunków 144 zmieniło po prostu nazwę budynku federalnego. Ale czy Kongres USA jest teraz bardziej spolaryzowany niż kiedykolwiek wcześniej? Chociaż my możemy wierzyć, że to prawda – i mamy niepotwierdzone dowody, takie jak cytat profesora Galstona – wolelibyśmy bardziej zasadowy sposób odpowiedzi na to pytanie. Tutaj naszym podejściem będzie wykorzystanie MDS do wizualizacji grup senatorów w poprzek linii partii, aby sprawdzić, czy istnieje mieszanie między członkami obu partii. Jednak zanim to zrobimy, potrzebujemy miernika do pomiaru odległości między senatorami. Na szczęście Kongres USA jest jednym z najbardziej otwartych organów legislacyjnych na świecie. Możemy wykorzystać publiczną dokumentację prawodawców do stworzenia rozsądnej miary odległości. Tutaj wykorzystamy zapisy z głosowania ustawodawcy. Podobnie jak w przykładzie w poprzedniej sekcji, możemy wykorzystać zapisy głosowania imiennego jako sposób pomiaru zatwierdzenia lub odrzucenia proponowanego projektu przez ustawodawców. Tak jak klienci w poprzednich przykładach głosowali kciukiem do góry lub kciukiem w dół, tak ustawodawcy głosują za rachunkami Yeas (zatwierdzają) lub Nays (odrzucają). Dla osób niezaznajomionych z procesem legislacyjnym w USA głosowanie imienne jest jedną z najbardziej podstawowych procedur parlamentarnych w każdej izbie Kongresu USA. Jak sama nazwa wskazuje, jest to proces, w którym członkowie Izby Reprezentantów i Senatu głosują za każdą propozycją przedstawioną na głos. Każdy dom ma inny mechanizm, według którego można zainicjować głosowanie imienne, ale wyniki są w zasadzie równoważne. Głosowanie imienne jest zapisem działań każdego ustawodawcy dotyczących danego wniosku. Jak wspomniano wcześniej, zazwyczaj przyjmuje to postać Yea lub Nay, ale później przekonamy się, że wyniki są nieco bardziej skomplikowane. Te dane apelacyjne są doskonałym źródłem do pomiaru podobieństw i różnic między ustawodawcami i są nieocenionym źródłem dla naukowców zajmujących się badaniem Kongresu USA. Dane są tak cenne, że dwóch politologów stworzyło jednolity zasób do ich pobierania. Keith Poole (University of Georgia) i Howard Rosenthal (New York University) prowadzą witrynę http://www.voteview.com/, która jest repozytorium wszystkich danych z amerykańskich listów apelowych od pierwszego Kongresu do najnowszego .Istnieje również wiele innych zestawów danych dostępnych na tej stronie, ale dla naszych celów przeanalizujemy dane głosowania imiennego z Senatu USA dla 101. do 111. Kongresów. W poniższych sekcjach omówimy kod użyty do wykonania MDS na danych tego wezwania. Po obliczeniu skalowania wizualizujemy wyniki, aby odpowiedzieć na pytanie: czy senatorowie z różnych partii mieszają się, gdy są zebrani według rekordów głosowania imiennego?

(I) : Operatory

Operatory operują na obiektach. Operatory mogą być logiczne, arytmetyczne, macierzowe, relacyjne lub indeksowalne, lub mogą mieć specjalne znaczenie. Każdy z typów operatorów jest opisany tutaj. W przypadku operatorów elementowych odnosi się do wykonywania operacji na każdym elemencie obiektu lub sparowanych elementów dla dwóch obiektów. Jeśli dwa obiekty nie mają takich samych wymiarów, operator przełączy mniejszy obiekt na większy. Cykl przebiega przez każdy wymiar. Na przykład w przypadku macierzy pierwszym wymiarem są rzędy, a drugim wymiarem są kolumny, więc cykl odbywa się w dół wierszy, zaczynając od pierwszej kolumny. Litery NA służą do wskazania, że ​​w elemencie brakuje danych. Większość operatorów ma zasady postępowania z brakującymi danymi i może zwrócić NA, jeśli brakuje danych. CRAN udostępnia stronę pomocy zawierającą informacje na temat pierwszeństwa operacji.

Operatory logiczne i funkcje

Operatory logiczne zwracają wartości TRUE, FALSE lub NA, gdzie NA oznacza brakującą wartość. Operatory logiczne to nie operator, dwa lub operatory, dwa i operatory, funkcja wyłączna lub funkcja (która jest funkcją, która działa jak operator) oraz dowolna funkcja (która jest funkcją działającą na obiekcie logicznym). W przypadku operatorów logicznych, jeśli dwa obiekty nie mają takich samych wymiarów, liczba elementów w większym obiekcie musi być wielokrotnością liczby elementów w mniejszym obiekcie, aby nastąpiło przełączenie.

Operator :          Działanie            :              Opis

!              :              not                        :              operator negacji – np. !a

|             :              or                           :              elementarny or operator – np. a | b

||           :              or                           :              operator or, po prostu ocenia pierwsze elementy w obiekcie –a || b

&            :              and                        :              elementarny and operatorem – np. a & b

&&         :              and                        :              operator and , po prostu ocenia pierwsze  elementy w obiekcie – np. a &&b

xor ()     :              exclusive or       :              funkcja exclusive or – np. xor (a, b)

any()     :              test logiczny      :              sprawdza, czy TRUE występuje w obiekcie logicznym – np. any(a)

Operatory logiczne działają na obiektach logicznych, numerycznych lub surowych. Gdy obiekt numeryczny jest zmuszony do logicznego, wszystkie niezerowe wartości są ustawione na PRAWDA, a wartości zerowe są ustawione na FAŁSZ. W przypadku wektorów surowych operatory są stosowane bitowo.

Operator negacji zmienia PRAWDA na FAŁSZ, a FAŁSZ na PRAWDA w obiekcie logicznym. Operator | porównuje oba obiekty elementarnie i dla każdej pary elementów zwraca PRAWDA, jeśli PRAWDA jest obecna, a FALSE w przeciwnym razie. Operator || porównuje pierwszy element pierwszego obiektu z pierwszym elementem drugiego obiektu i zwraca PRAWDA, jeśli PRAWDA jest obecna, lub FALSE w przeciwnym razie.

Operator & porównuje dwa obiekty elementarnie i dla każdej pary elementów zwraca PRAWDA, jeśli oba elementy są PRAWDZIWE, a FALSE w przeciwnym razie. Operator && porównuje pierwszy element pierwszego obiektu z pierwszym elementem drugiego obiektu i zwraca PRAWDA, jeśli oba elementy są PRAWDA, w przeciwnym razie FAŁSZ.

Funkcja xor () porównuje obiekty elementarnie i zwraca PRAWDA, jeśli sparowane elementy są różne, oraz FALSE, jeśli sparowane elementy są takie same. W przypadku wektora logicznego lub wektora, który można przekonwertować na logiczny, funkcja any () zwróci wartość PRAWDA, jeśli którykolwiek z elementów jest PRAWDA, w przeciwnym razie FAŁSZ. Aby uzyskać więcej informacji o operatorach logicznych, strony pomocy CRAN dla operatorów logicznych można znaleźć, wprowadzając ??logical operators  po znaku zachęty R. Dostęp do strony pomocy dla any() można uzyskać, wprowadzając ?any w wierszu polecenia R.