Импорт данных

До этого момента мы либо создавали какой-то набор данных, либо использовали какие-то встроенные датасеты. В реальной жизни все намного сложнее. Данные нужно откуда-то брать. Прежде чем говорить об источниках данных, давайте дадим определение. Импорт данных – это загрузка в среду R различных данных для последующей работы с ними. Важно понимать откуда мы берём данные. Обычно источником импорта выступают:

  1. Обычные файлы (.csv, .txt).
  2. Excel (.xlsx, .xls)
  3. Базы данных (SQL).
  4. Интернет.
  5. Статистические пакеты (SPSS, SAS, STATA)

Директория

Директория – это место (папка), где находится ваш “проект”. То есть там лежит скрипт, данные, картинки и прочее. Когда вы хотите загрузить данные с файлика, вам нужно прописать путь к нему, но если он находится в вашей директории, то можно просто напиать его название.

После загрузки всех необходимых пакетов, нужно узнать в какой директории вы находитесь. Это можно сделать несколькими способами:

  1. Текущая директория написана в консоли.

  1. C помощью функцию getwd().

Зачастую, у каждого проекта своя директория, поэтому приходится часто их менять. Есть несколько способов это сделать:

  1. Использовать функция setwd("~/Desktop/R"), где в кавычках можно прописать путь к директории.
  2. На панели R нажать кнопку Session и в выпадающем списке выбрать Set Working Directory. После чего вы можете выбрать нужную папку.
  3. В нижнем правом окошке есть вся файловая система компьютера, где так же удобно можно установить нужную директорию. Нажав кнопку More, можно перейти в текущую директорию или установить новую.

Я рекомендую именно второй способ, потому что он быстрее , и вам не нужно знать путь. Чтобы проверить, что вы находитесь в нужной директории можно использовать функцию dir(). Она показывает все объекты которые находятся в директории.

Импорт файлов с расширениями csv, txt и другими

Функция read.csv()

Формат .csv самый распространенный формат хранения данных в мире для анализа данных. Его можно получить, например, сохранив excel файл в формате csv(разделитель - запятая). Перед тем как подгружать файл, нужно открыть файл в текстовом редакторе и посмотреть его структуру. Нужно обратить внимание на:

  1. Наличие шапки (то есть имеются ли названия столбцов).
  2. Тип разделителя (чем отделены друг от друга переменные).

Если вы часто работаете в разных директориях, советую прописать путь к файлу в отдельную переменную path. Для этого можно использовать функцию file.path(‘~’, ‘data’, ‘data.csv’), но все таки лучше копировать путь из свойств файла. Также важно отметить про то, что Windows ставит слэш в обратную сторону.

Давайте разберем функцию read.csv(). Можно вызвать справку и узнать об этой функции побольше.

?read.csv

Можно увидеть, что у этой функции достаточно много аргументов. Давайте посмотрим только на те, которые нам нужны.

read.csv(path, header = TRUE, sep = ",", stringAsFactors = TRUE, dec = '.')

Аргументы (дефолтное значение):

  • path – путь к файлу
  • header (TRUE) – есть ли в файле наименования столбцов
  • sep (',') – разделитель между переменными
  • stringAsFactors (TRUE) – сделать ли столбец строковых переменных в факторный
  • dec ('.') – разделитель для числовых переменных (точка или запятая)

У нас есть файлик friends.csv. Попробуем подгрузить его.

Попытка №1

А давайте просто укажем файл и забьем на все эти параметры.

data <- read.csv('data/friends.csv')
data
##         Jack.19.M.10.May.2000.7 X6
## 1  Emma;21;F;22 February 1998;8  9
## 2 Henry;18;M;3 September 2001;8  0
## 3      Aria;20;F;26 June 1999;9  3
str(data)
## 'data.frame':    3 obs. of  2 variables:
##  $ Jack.19.M.10.May.2000.7: chr  "Emma;21;F;22 February 1998;8" "Henry;18;M;3 September 2001;8" "Aria;20;F;26 June 1999;9"
##  $ X6                     : int  9 0 3

R неправильно прочитал файл. Он думает, что у нас есть всего два столбца. Почему так вышло? Если открыть файл в текстовом редакторе, то можно увидеть, что разделителем между переменными является ";".

Попытка №2

Теперь мы поняли свою ошибку. Давайте её исправим

data <- read.csv('data/friends.csv', sep = ';')
data
##    Jack X19 M     X10.May.2000 X7.6
## 1  Emma  21 F 22 February 1998  8,9
## 2 Henry  18 M 3 September 2001  8,0
## 3  Aria  20 F     26 June 1999  9,3
str(data)
## 'data.frame':    3 obs. of  5 variables:
##  $ Jack        : chr  "Emma" "Henry" "Aria"
##  $ X19         : int  21 18 20
##  $ M           : chr  "F" "M" "F"
##  $ X10.May.2000: chr  "22 February 1998" "3 September 2001" "26 June 1999"
##  $ X7.6        : chr  "8,9" "8,0" "9,3"

Ой! У нас всего 3 наблюдения, хотя было 4. Это произошло, так как первая строчка стала названием столбцом. Почему так вышло? Давайте исправим это.

Попытка №3
data <- read.csv('data/friends.csv', sep = ';', header = FALSE)
data
##      V1 V2 V3               V4  V5
## 1  Jack 19  M      10 May 2000 7,6
## 2  Emma 21  F 22 February 1998 8,9
## 3 Henry 18  M 3 September 2001 8,0
## 4  Aria 20  F     26 June 1999 9,3
str(data)
## 'data.frame':    4 obs. of  5 variables:
##  $ V1: chr  "Jack" "Emma" "Henry" "Aria"
##  $ V2: int  19 21 18 20
##  $ V3: chr  "M" "F" "M" "F"
##  $ V4: chr  "10 May 2000" "22 February 1998" "3 September 2001" "26 June 1999"
##  $ V5: chr  "7,6" "8,9" "8,0" "9,3"

Если взглянуть на данные, то кажется, что всё прекрасно. Но это не так!

  1. Попробуйте вытащить любое число и провести с ним какую-нибудь операцию.
  2. Данные без названия столбцов – это не данные.
  3. Хотелось бы, чтобы все переменные считывались как строковые, а не факторные.
Попытка №4

Попробуем сделать всё так, как нужно!

data <- read.csv('data/friends.csv', sep = ';', header = FALSE, 
                 dec = ',', stringsAsFactors = FALSE, 
                 col.names = c('Name', 'Age', 'Gender', 'Birthday', 'Homework grade'))
data
##    Name Age Gender         Birthday Homework.grade
## 1  Jack  19      M      10 May 2000            7.6
## 2  Emma  21      F 22 February 1998            8.9
## 3 Henry  18      M 3 September 2001            8.0
## 4  Aria  20      F     26 June 1999            9.3
str(data)
## 'data.frame':    4 obs. of  5 variables:
##  $ Name          : chr  "Jack" "Emma" "Henry" "Aria"
##  $ Age           : int  19 21 18 20
##  $ Gender        : chr  "M" "F" "M" "F"
##  $ Birthday      : chr  "10 May 2000" "22 February 1998" "3 September 2001" "26 June 1999"
##  $ Homework.grade: num  7.6 8.9 8 9.3

Все выглядит почти идеально. Изменим тип переменной Gender на факторный, а также переменную Birthday на дату.

# install.packages('lubridate')
library(lubridate)
data$Birthday <- dmy(data$Birthday)
data$Gender <- factor(data$Gender)
str(data)
## 'data.frame':    4 obs. of  5 variables:
##  $ Name          : chr  "Jack" "Emma" "Henry" "Aria"
##  $ Age           : int  19 21 18 20
##  $ Gender        : Factor w/ 2 levels "F","M": 2 1 2 1
##  $ Birthday      : Date, format: "2000-05-10" "1998-02-22" ...
##  $ Homework.grade: num  7.6 8.9 8 9.3

Если вы хотите использовать разделитель ;, то можно использовать функцию read.csv2, которая использует этот разделитель по умолчанию, а также dec = ",".

Иногда бывают данные, где столбец это год. Например, у вас есть временной ряд за 1960 - 1976 года. Писать название каждого столбца утомительно. Можно воспользоваться функцией paste0.

paste0("year_", 1960:1976)
##  [1] "year_1960" "year_1961" "year_1962" "year_1963" "year_1964" "year_1965"
##  [7] "year_1966" "year_1967" "year_1968" "year_1969" "year_1970" "year_1971"
## [13] "year_1972" "year_1973" "year_1974" "year_1975" "year_1976"

Помним, что обычный data frame не терпит пробелов в названиях переменных. Можно ставить нижнее подчеркивание (_).

Функция read.delim() и read.table()

Нужно сказать сначала то, что функции read.delim и read.csv это дочерние функции от функции read.table. Как мы уже убедились read.csv создан для файлов с расширением csv. А вот read.delim создан для файлов с расширением .txt. Если у вас есть какое-то другое расширение, то вы можете использовать read.table с нужными вам параметрами.

Функция read.delim()

/t – знак табуляции (один из видов разделителей). В read.delim он используется по умолчанию.

data <- read.delim('data/friends.txt', dec = ',', header = FALSE, 
                   stringsAsFactors = FALSE, 
                   col.names = c('Name', 'Age', 'Gender', 'Birthday', 'Homework grade'))
data
##    Name Age Gender         Birthday Homework.grade
## 1  Jack  19      M      10 May 2000            7.6
## 2  Emma  21      F 22 February 1998            8.9
## 3 Henry  18      M 3 September 2001            8.0
## 4  Aria  20      F     26 June 1999            9.3
str(data)
## 'data.frame':    4 obs. of  5 variables:
##  $ Name          : chr  "Jack" "Emma" "Henry" "Aria"
##  $ Age           : int  19 21 18 20
##  $ Gender        : chr  "M" "F" "M" "F"
##  $ Birthday      : chr  "10 May 2000" "22 February 1998" "3 September 2001" "26 June 1999"
##  $ Homework.grade: num  7.6 8.9 8 9.3

Аналогично есть функция read.delim2.

Функция read.table()

Если открыть файл friends2.txt можно увидеть, что разделитель это слэш (/). С помощью read.table мы можем задать нужный нам разделитель.

data <- read.table('data/friends2.txt', sep = '/', dec = ',', 
                   header = FALSE, stringsAsFactors = FALSE, 
                   col.names = c('Name', 'Age', 'Gender', 'Birthday', 'Homework grade'))
data
##    Name Age Gender         Birthday Homework.grade
## 1  Jack  19      M      10 May 2000            7.6
## 2  Emma  21      F 22 February 1998            8.9
## 3 Henry  18      M 3 September 2001            8.0
## 4  Aria  20      F     26 June 1999            9.3
str(data)
## 'data.frame':    4 obs. of  5 variables:
##  $ Name          : chr  "Jack" "Emma" "Henry" "Aria"
##  $ Age           : int  19 21 18 20
##  $ Gender        : chr  "M" "F" "M" "F"
##  $ Birthday      : chr  "10 May 2000" "22 February 1998" "3 September 2001" "26 June 1999"
##  $ Homework.grade: num  7.6 8.9 8 9.3

Пакет readr

Установка и чтение пакетов

Давайте для начала установим и прочитаем пакет, а также пакет dplyr.

#install.packages('readr')
# install.packages("dplyr")
library(readr)
library(dplyr)

Плюсы пакета и основые функции

Зачем нам вообще этот пакет, ведь мы умеем читать файлы с расширением .csv, .txt и их разновидностями?.

Плюсы:

  1. Самое главное: сами понимают как устроен файл. Не нужно вводить все эти аргументы.
  2. Работают быстрее (примерно в 10 раз).
  3. Создают tibble-frame, а не data frame.
  4. Более оптимален. С ним будет меньше проблем.
  5. Имеет интерактивную полосу, чтобы понимать, сколько нам еще ждать. Это становится актуально, когда файл весит много.

Здесь важно использовать определенную функцию для определенного разделителя. Мы рассмотрим функции read_csv() и read_csv2().

Давайте попробуем подгрузить файл, который подгружали ранее.

data <- read_csv2('data/friends.csv', 
                  col_names = c('Name', 'Age', 'Gender', 'Birthday', 'Homework grade'))
glimpse(data)
## Rows: 4
## Columns: 5
## $ Name             <chr> "Jack", "Emma", "Henry", "Aria"
## $ Age              <dbl> 19, 21, 18, 20
## $ Gender           <chr> "M", "F", "M", "F"
## $ Birthday         <chr> "10 May 2000", "22 February 1998", "3 September 2001…
## $ `Homework grade` <dbl> 7.6, 8.9, 8.0, 9.3

Все получилось! Видим, что оценка за ДЗ подгрузилась как число. Аргумент col_names может принимать значение FALSE, если у нас нет названий переменных.

Изучим 2 новых аргумента:

  • comment – знак комментария в файле
  • skip – количество строк, которые нужно пропустить
data <- read_csv2('data/friends2.csv', comment = '#', 
                  col_names = c('Name', 'Age', 'Gender', 'Birthday', 'Homework grade'))

Или можно просто пропустить 1 строку.

data <- read_csv2('data/friends2.csv', skip = 1,
                  col_names = c('Name', 'Age', 'Gender', 'Birthday', 'Homework grade'))

Функции этого пакета определяют тип переменных в столбце следующим образом: они берут первые 1000 наблюдений и используют к нему функцию guess_parser(), которая определяет к какому типу относится переменная. А функция parse_guess() преобразовывает вектор к нужному типу.

guess_parser(c("True", "False"))
## [1] "logical"
parse_guess(c("True", "False"))
## [1]  TRUE FALSE
guess_parser(c("1.2", "2.12"))
## [1] "double"
parse_guess(c("1.2", "2.12"))
## [1] 1.20 2.12

Скорость работы

Давайте проверим сокрость этого пакета. С помощью функции Sys.time() будем измерять время загрузки файла. Будем использовать файл nir.csv. В нем имеются данные о российских корпоративных облигациях. Весит этот файл 50 мегабайт. Это средний размер файла, но уже здесь мы почувствуем разницу.

Посчитаем время использования функции read.csv():

start <- Sys.time()
data <- read.csv('data/nir.csv')
finish <- Sys.time()

print(finish-start)
## Time difference of 20.90118 secs

Видим приблизительно 20.9 секунды. Представьте, что вы меняете и запускаете код постоянно. Хотелось бы, чтобы загрузка занимала меньше времени.

Теперь посчитаем время использования аналогичной функции read_csv() из пакета readr:

start <- Sys.time()
data <- read_csv2('data/nir.csv')
finish <- Sys.time()

print(finish-start)
## Time difference of 7.804004 secs

Время уменьшилось до 7.8 секунд!

Проблемы больших файлов

В больших файлах иногда бывают проблемы. Например, первые 1000 значений NA. А с 1001 идут вещественные числа. Столбцу дадут тип logical. Можно увеличить количество значений с помощью аргумента guess_max.

Можно увидеть, что появились предупреждения. Это связано с проблемой описанной выше. Эту проблему можно исправить с помощью парметра col_types. С помощью него можно явно задать какого формата наша переменная.

data <- read_csv2('data/nir.csv', col_types = cols(
                                YLD_YTM_MID = col_double() ,
                                YLD_CNV_MID = col_double()
                  ))

Иногда проблемных мест бывает очень много. Поэтому бывает полезно прочитать все переменные как строковые.

data <- read_csv2('data/nir.csv', col_types = cols(.default = col_character()))

Пропущенные значения

Почти в любых наборах данных, которые приходится импортировать бывают пропущенные значения. По умолчанию функция read_csv() считает пропущенными значениями "" и “NA”. Это можно исправить с помощью аругмента na. Представьте, что в наборе данных пропущенные значения помечаются как “UNKNOWN”, “NA” и "". Тогда можно преобразовать их следующим образом.

data <- read_csv2('data/friends_na.csv', na = c("", "NA", "UNKNOWN"), col_names = F)

Подгрузка файлов из интернета

Можно подгружать файлы из интернета по url.

data <- read_csv2('https://raw.githubusercontent.com/ahmedushka7/R/master/docs/scripts/hse_data_analysis/sem_7/data/friends.csv', col_names = F)
data
## # A tibble: 4 x 5
##   X1       X2 X3    X4                  X5
##   <chr> <dbl> <chr> <chr>            <dbl>
## 1 Jack     19 M     10 May 2000        7.6
## 2 Emma     21 F     22 February 1998   8.9
## 3 Henry    18 M     3 September 2001   8  
## 4 Aria     20 F     26 June 1999       9.3

Экспорт данных

Данные нужно уметь не только импортировать, но и экспортировать. Для этого можно использовать функцию write_csv(). У нее имеется два важных аргумента:

  • x – датасет (data frame), который у вас есть в памяти
  • path – путь и название файла (если оставить только название файла, то файл сохранится в текущей директории)

Давайте сохраним набор mtcars.

write_csv(mtcars, 'data/mtcars.csv')

Если вы планируете работать с вашим .csv файлом далее в excel, то рекомендуется использовать функцию write_excel_csv(), чтобы избежать проблем с кодировкой. Она работает аналогично функции write_csv.

Также существует функция write_csv2(), которая сохраняет файл с разделителем ";".

В этих функциях можно также передать аргумент na, в котором можно указать как должны выглядеть пропущенные значения в сохраняемом файле.

Кодировка

Пакет readr по умолчанию работает с кодировкой UTF-8. Если вы работаете со старым файлом, у которого другая кодировка, то вы можете использовать функцию guess_encoding(), которая может помочь узнать кодировку.

guess_encoding("data/mtcars.csv")
## # A tibble: 1 x 2
##   encoding confidence
##   <chr>         <dbl>
## 1 ASCII             1

После того как вы узнали кодировку, вы можете передать ее в аргумент locale.

data <- read_csv("data/mtcars.csv", locale = locale(encoding = 'ASCII'))