Czym naprawdę jest czynnik
Czynnik (factor) to odpowiedź R na dane kategoryczne, czyli wartości pochodzące ze stałego menu możliwości: grupy badawcze, odpowiedzi w ankiecie, rozmiary koszulek. Po wypisaniu wygląda jak wektor tekstowy, ale nim nie jest. Wewnętrznie czynnik to wektor kodów całkowitych i tabela etykiet nazywanych poziomami (levels):
Wydruk pokazuje etykiety, a potem wiersz Levels: z menu. as.integer() odsłania mechanizm: kody wracają jako 3 1 3 2, bo każda wartość to w rzeczywistości indeks w tabeli poziomów, a poziomy domyślnie sortują się alfabetycznie (large, medium, small), a nie w kolejności, w jakiej przyszły dane. Zatem small ma kod 3, a large kod 1, co jest sprzeczne z intuicją każdego. Zapamiętaj tę alfabetyczną wartość domyślną; stoi za dwiema pułapkami opisanymi niżej.
Po co ta dwuwarstwowa konstrukcja zamiast zwykłych napisów? Bo wymaga jej statystyka. Model nie pomnoży "small" przez współczynnik, ale może zakodować trzy znane poziomy w kolumnach zer i jedynek. Funkcje takie jak lm(), glm(), table() i mechanizm stojący za ANOVA opierają się na czynnikach, żeby wiedzieć, że zmienna jest kategoryczna, jaki jest pełny zbiór kategorii (łącznie z tymi, których brakuje w danych) i która kategoria jest bazowa. Zwykłe wektory tekstowe nie niosą żadnej z tych informacji.
Tworzenie czynników: levels, labels i table()
Domyślnie factor() bierze znalezione unikalne wartości i sortuje je alfabetycznie w poziomy. Często chcesz kontrolować zarówno zbiór, jak i kolejność; przekaż levels =:
Teraz poziomy idą w naturalnej kolejności rozmiarów, a table() (jednolinijkowe zliczanie częstości, którego będziesz ciągle używać z czynnikami) podaje liczebności też w tej kolejności. nlevels() liczy kategorie.
levels = daje jeszcze dwie rzeczy. Wartości w danych, których nie ma na liście poziomów, stają się NA (dobrze: literówki wychodzą na jaw, zamiast stawać się osobną kategorią). A poziomy bez żadnego wystąpienia nadal istnieją, więc podsumowanie odpowiedzi w ankiecie pokazuje "zdecydowanie się nie zgadzam: 0", zamiast udawać, że takiej opcji nigdy nie było.
labels = zmienia nazwy poziomów w chwili tworzenia, co przydaje się, gdy surowe dane używają kodów:
A as.factor(x) to szybka konwersja istniejącego wektora, gdy ustawienia domyślne są w porządku.
Czynniki uporządkowane dla danych porządkowych
Zwykłe czynniki traktują kategorie jako nieuporządkowane: "red" nie jest mniejsze od "blue". Niektóre skale kategoryczne mają jednak prawdziwy porządek: low/medium/high, nie zgadzam się/neutralnie/zgadzam się. Zadeklarujesz to przez ordered = TRUE:
Wydruk pokazuje teraz Levels: low < medium < high, a operatory porównania działają: możesz zapytać, czy jedna ocena przewyższa drugą, albo przefiltrować wszystko od "medium" w górę. Na nieuporządkowanym czynniku oba działania dałyby błędy (a ściślej ostrzeżenia i NA). Czynniki uporządkowane zmieniają też sposób kodowania zmiennej w modelach (kontrasty wielomianowe zamiast zmiennych zero-jedynkowych), czego zwykle chcesz dla predyktorów porządkowych.
Używaj ordered = TRUE tylko wtedy, gdy porządek jest prawdziwy. Kodowanie zwykłych grup jako uporządkowanych zmienia wyniki modelu w sposób łatwy do błędnego odczytania.
Poziom odniesienia i relevel()
Pierwszy poziom czynnika jest wyjątkowy: funkcje modeli traktują go jako kategorię odniesienia, czyli poziom bazowy, względem którego mierzy się współczynnik każdego innego poziomu. Ponieważ domyślna kolejność poziomów jest alfabetyczna, poziom bazowy wybiera alfabet, chyba że zainterweniujesz. A to, że "control" przegrywa alfabetycznie z "aspirin", nie jest decyzją naukową.
relevel() awansuje poziom na pierwsze miejsce:
Przed: control jest pierwszy tylko dzięki alfabetycznemu szczęściu. Po relevel(..., ref = "control") jest pierwszy celowo. W regresji liniowej z tym predyktorem współczynnik treatment odpowiada teraz na pytanie "czym leczenie różni się od kontroli?", czyli na pytanie, które naprawdę zadajesz. Gdy kategoryczne współczynniki modelu wyglądają myląco, najpierw sprawdź poziom odniesienia.
(Żeby zmienić całą kolejność, a nie tylko pierwsze miejsce, przekaż ponownie pełny wektor levels = do factor().)
Klasyczna pułapka: konwersja czynnika na liczby
Czasem liczby przychodzą jako czynniki, zwykle w kolumnie CSV, która zawierała jedną zabłąkaną wartość nieliczbową. Konwersja z powrotem wygląda oczywiście, a kończy się pamiętną katastrofą:
as.numeric(f) zwraca 2 1 3. Nie 20, 10, 30, tylko kody poziomów. Poziomy sortują się alfabetycznie do "10", "20", "30", więc "20" to poziom 2 i konwertuje się do... 2. Bez błędu, bez ostrzeżenia, wiarygodnie wyglądające małe liczby całkowite po cichu zastępują twoje dane. Przez ten błąd wycofywano już publikacje naukowe.
Poprawna droga prowadzi przez tekst: as.numeric(as.character(f)) najpierw odzyskuje etykiety jako tekst, a potem parsuje tekst jako liczby, dając 20 10 30. Wryj sobie ten idiom w pamięć: konwersja czynnika na liczby zawsze idzie przez as.character().
droplevels() i historia stringsAsFactors
Wybranie podzbioru czynnika zachowuje pełny zbiór poziomów, nawet dla kategorii, które już się nie pojawiają:
Po odfiltrowaniu large funkcja table() wciąż go pokazuje, z liczebnością 0. Czasem to dokładnie to, czego chcesz (pusta kategoria ma być widoczna). Gdy nie jest (grupy z zerową liczebnością zaśmiecają wykresy i mogą zepsuć analizy warstwowe), droplevels() usuwa poziomy bez obserwacji.
Uwaga historyczna, która przyda się przy czytaniu starszego kodu albo odpowiedzi na Stack Overflow: przed R 4.0 (2020) data.frame() i read.csv() automatycznie zamieniały każdą kolumnę tekstową w czynnik, bo domyślnie obowiązywało stringsAsFactors = TRUE. Dekada tutoriali jest pełna obejść dla czynników, o które nikt nie prosił. Od R 4.0 wartość domyślna to FALSE: napisy zostają napisami, a czynniki tworzysz świadomie tam, gdzie zmienna w ramce danych jest naprawdę kategoryczna. To właściwy nawyk: jawne czynniki, celowo, z wybranymi przez siebie poziomami.
Co warto zapamiętać
- Czynnik = kody całkowite + etykiety poziomów; to on mówi funkcjom statystycznym, że zmienna jest kategoryczna.
- Zbiór i kolejność kategorii kontrolujesz przez
levels =, nazwy zmieniasz przezlabels =, liczysz przeztable(). ordered = TRUEwłącza porównania dla naprawdę porządkowych skal.- Pierwszy poziom to poziom bazowy modelu; ustawiaj go świadomie przez
relevel(f, ref = ...). - Nigdy nie wywołuj
as.numeric(f)bezpośrednio; zawszeas.numeric(as.character(f)). droplevels()usuwa nieużywane poziomy po wybraniu podzbioru; od R 4.0 napisy zostają napisami, chyba że samodzielnie utworzysz czynniki.
Dalej: ramki danych, w których czynniki, liczby i tekst mieszkają razem jako kolumny jednej tabeli.
Najczęściej zadawane pytania
Czym jest czynnik (factor) w R?
Czynnik to typ R dla danych kategorycznych, czyli wartości pochodzących ze stałego zbioru możliwości nazywanych poziomami. Wewnętrznie to wektor kodów całkowitych i tabela etykiet poziomów, dzięki czemu funkcje statystyczne traktują kategorie poprawnie (zliczają je, kodują zmiennymi zero-jedynkowymi w modelach), zamiast traktować je jak dowolny tekst.
Jak zamienić czynnik na liczby w R?
Przejdź przez tekst: as.numeric(as.character(f)). Bezpośrednie wywołanie as.numeric(f) zwraca wewnętrzne kody poziomów (1, 2, 3, ...), a nie wartości pokazywane przez etykiety, więc czynnik wyświetlający "20" może wrócić jako 2. To jeden z najczęstszych cichych błędów w R.
Co robi relevel() w R?
Przesuwa wybrany poziom na pierwszą pozycję: relevel(group, ref = "control"). Pierwszy poziom to kategoria odniesienia (bazowa), z którą funkcje modeli, takie jak lm() i glm(), porównują każdy inny poziom, więc świadomy wybór sprawia, że współczynniki regresji znaczą to, co zamierzasz.
Dlaczego mój czynnik wciąż pokazuje usunięte poziomy?
Wybranie podzbioru czynnika zachowuje pełny zbiór poziomów, nawet gdy niektóre już nie występują, więc table() pokazuje kategorie z zerową liczebnością, a modele wciąż rezerwują na nie miejsce. Uruchom droplevels() na podzbiorze, żeby usunąć nieużywane poziomy.