read.csv() zamienia plik CSV w ramkę danych
Wczytanie CSV w R to jedno wywołanie funkcji wbudowanej w język, bez żadnego pakietu:
sales <- read.csv("sales.csv")
read.csv() czyta plik, używa pierwszej linii jako nazw kolumn, zgaduje typ każdej kolumny i zwraca ramkę danych. Przy porządnie przygotowanym pliku to wszystko.
Możesz zobaczyć jej działanie bez żadnego pliku, bo read.csv() przyjmuje też surowy tekst CSV przez argument text. To ten sam parser, tylko zamiast nazwy pliku dostaje napis:
str() to pierwsza rzecz, którą warto uruchomić na wszystkim, co importujesz: pokazuje każdą kolumnę z odgadniętym typem. Tutaj name przyszła jako tekst, score jako liczba całkowita, a passed jako wartość logiczna, wszystko odgadnięte na podstawie wartości. Do szybkiego podglądu head(students) pokazuje pierwsze wiersze, a nrow(students) je liczy. Jeśli kolumna, która miała być liczbowa, pojawia się jako chr, coś w niej nie jest liczbą: zabłąkany komentarz, "N/A", separator tysięcy. To moment, żeby to naprawić, a nie trzy wykresy później.
Argumenty, które mają znaczenie
read.csv() ma dziesiątki parametrów; użyjesz około pięciu.
header: czy pierwsza linia zawiera nazwy kolumn. Domyślnie TRUE. Jeśli plik zaczyna się od razu od danych, przekaż header = FALSE, a R nazwie kolumny V1, V2, ...
sep: separator pól, domyślnie ",". W dużej części Europy pliki CSV zapisuje się ze średnikami jako separatorami, bo przecinek jest tam separatorem dziesiętnym. R ma gotowy wariant właśnie do tego: read.csv2() używa sep = ";" i dec = ",":
Wzrost wychodzi jako prawdziwe liczby: read.csv2 wiedziała, że 1,63 znaczy jeden i sześćdziesiąt trzy setne. Zwykła read.csv dałaby na tym pliku jedną pokiereszowaną kolumnę, bo nic nie dzieli poprawnie po przecinku, który jest przecinkiem dziesiętnym.
na.strings: które napisy oznaczają brak danych. Domyślnie tylko "NA" staje się wartością brakującą. Prawdziwe eksporty zapisują brakujące dane jako puste komórki, "missing", "-", "NULL", i jeśli ich nie zadeklarujesz, trafiają jako tekst i zamieniają całą kolumnę w tekstową:
Z właściwym na.strings puste pola stają się prawdziwymi NA, a score pozostaje liczbowa. Bez tego "missing" to po prostu słowo, a kolumna jest tekstowa.
skip: liczba linii do pominięcia przed początkiem danych. Eksporty uwielbiają umieszczać linię czy dwie tytułu nad właściwą tabelą; skip = 2 je przeskakuje.
colClasses: wymusza typy kolumn zamiast pozwalać R zgadywać. Klasyczną ofiarą jest wszystko z zerami na początku (kody pocztowe, numery telefonów, identyfikatory produktów), co mechanizm zgadywania R czyta jako liczby, niszcząc zera:
00501 zamieniło się w 501. Dane były poprawne w pliku i błędne w R, bez żadnego ostrzeżenia. colClasses = c("integer", "character") mówi parserowi po kolei, czym jest każda kolumna, i zera przetrwają.
Jeden argument, którego już nie potrzebujesz: stringsAsFactors. Przez większość historii R read.csv() zamieniała każdą kolumnę tekstową w czynnik, chyba że zaznaczono inaczej, co wywołało ogromnie dużo zamieszania. Od R 4.0 domyślna wartość to FALSE: tekst pozostaje tekstem. W starszych tutorialach wciąż zobaczysz stringsAsFactors = FALSE; w aktualnym R to nieszkodliwe, ale zbędne.
Ścieżki plików: powód numer 1, dla którego read.csv zawodzi
Błąd, na który każdy uczący się R trafia w pierwszym tygodniu:
Error in file(file, "rt") : cannot open the connection
In addition: Warning message:
cannot open file 'sales.csv': No such file or directory
Plik istnieje, widzisz go w menedżerze plików. Ale R nie szuka go tam. Sama nazwa pliku, taka jak "sales.csv", jest rozwiązywana względem katalogu roboczego R, a to zwykle nie jest folder z twoim plikiem. Dwie linie pozwalają to zdiagnozować:
getwd() # where R is actually looking
file.exists("sales.csv") # FALSE means the path is wrong, full stop
Jeśli file.exists() zwraca FALSE, żadne ponowne uruchamianie nie pomoże: popraw ścieżkę. Podaj pełną ścieżkę (read.csv("C:/Users/ada/data/sales.csv"); ukośniki działają też w Windows i są bezpieczniejsze niż ukośniki odwrotne) albo przenieś katalog roboczy R do folderu z danymi przez setwd(). Czym jest katalog roboczy, jak zarządzają nim projekty i dlaczego setwd() w skryptach jest źle widziane, opisuje artykuł o katalogu roboczym.
Niech file.exists() stanie się odruchem. W sekundę zamienia „tajemniczy błąd importu” w „literówkę w ścieżce”.
Wczytywanie CSV prosto z adresu URL
read.csv() przyjmuje URL wszędzie tam, gdzie przyjmuje nazwę pliku, i sama pobiera plik:
url <- "https://raw.githubusercontent.com/mwaskom/seaborn-data/master/penguins.csv"
penguins <- read.csv(url)
str(penguins)
To wygodne przy tutorialach i publicznych zbiorach danych: bez kroku pobierania i bez problemów ze ścieżkami. Ceną jest to, że twój skrypt zależy teraz od sieci i od tego, czy ten URL wciąż działa. W przypadku wszystkiego, co będziesz często uruchamiać, pobierz plik raz i czytaj lokalną kopię.
readr::read_csv: szybsza i bardziej rozmowna alternatywa
Tidyverse ma własny czytnik CSV w pakiecie readr: read_csv() (z podkreśleniem, nie kropką). Warto go znać, bo używa go większość nowoczesnego kodu R, jaki przeczytasz:
install.packages("readr") # once
library(readr) # every session
flights <- read_csv("flights.csv")
Praktyczne różnice względem read.csv():
- Szybkość: zauważalnie szybsza przy plikach z setkami tysięcy wierszy.
- Zwraca tibble: unowocześnioną ramkę danych, która wypisuje zwięzły podgląd zamiast zalewać konsolę.
- Informuje o swoich domysłach: po wczytaniu wypisuje wykryty typ każdej kolumny, więc kolumna odczytana jako tekst, choć miały tam być liczby, jest widoczna od razu, a nie jako niespodzianka później.
- Nigdy nie psuje nazw kolumn:
read.csv()przerabia nagłówek taki jakfirst namenafirst.name;read_csv()zostawia go bez zmian.
Przy małym pliku obie funkcje są w porządku. Sięgnij po read_csv(), gdy pliki robią się duże albo gdy reszta skryptu i tak korzysta z tidyverse. Wszystko, co napisano wyżej o ścieżkach, separatorach (istnieje też read_csv2()) i napisach oznaczających braki (na =), obowiązuje nadal, z nieco innymi nazwami argumentów.
Gdy skończysz analizę, drogę w drugą stronę, czyli eksport wyników do pliku, opisuje artykuł o write.csv.
Najważniejsze informacje
df <- read.csv("file.csv")wczytuje CSV do ramki danych; od razu sprawdź ją przezstr()ihead().read.csv(text = "...")parsuje napis CSV bezpośrednio, co świetnie sprawdza się przy eksperymentach i małych przykładach.- Argumenty, które naprawdę się przydają:
header,sep(alboread.csv2dla średników),na.strings,skip,colClasses. - „Cannot open file” oznacza, że katalog roboczy nie jest tam, gdzie myślisz:
getwd()ifile.exists()rozstrzygają to od razu. readr::read_csv()to szybsza wersja z tidyverse: tibble, raportowane typy kolumn, nietknięte nazwy.
Dalej: pliki, które wcale nie są zwykłym tekstem, czyli wczytywanie arkuszy Excela przez pakiet readxl.
Najczęściej zadawane pytania
Jak wczytać plik CSV w R?
Przez read.csv("file.csv"): funkcja jest wbudowana, nie potrzeba żadnego pakietu. Zwraca ramkę danych z jedną kolumną na każdą kolumnę CSV, a pierwszą linię traktuje jako nazwy kolumn. Przypisz wynik do zmiennej: df <- read.csv("sales.csv"), a potem sprawdź go przez str(df) i head(df).
Dlaczego read.csv zgłasza 'cannot open file: No such file or directory'?
R szuka pliku względem swojego katalogu roboczego, który najpewniej nie jest folderem z twoim plikiem. Uruchom getwd(), żeby zobaczyć, gdzie R szuka, i file.exists("file.csv"), żeby potwierdzić, że pliku tam nie ma. Napraw to pełną ścieżką albo ustawiając katalog roboczy na folder z plikiem.
Czym różni się read.csv od read_csv w R?
read.csv() to bazowy R: jest zawsze dostępna i zwraca zwykłą ramkę danych. read_csv() pochodzi z pakietu readr: jest szybsza przy dużych plikach, zwraca tibble, nigdy nie zmienia nazw kolumn i wypisuje odgadnięte typy kolumn, więc od razu wyłapiesz błędne parsowanie. Przy małych plikach obie są w porządku; przy dużych plikach albo w potokach tidyverse używaj read_csv().
Jak wczytać CSV rozdzielany średnikami w R?
Użyj read.csv2("file.csv"): to read.csv ustawiona pod konwencję europejską, ze średnikiem jako separatorem i przecinkiem jako separatorem dziesiętnym. Możesz też przekazać sep = ";" (i w razie potrzeby dec = ",") do zwykłej read.csv().