Изучив основные объекты в R, мы можем перейти к объектам, ради которых многие и начинают изучать R, а именно, к базам данных. Но прежде необходимо научиться загружать файлы с данными, чтобы было с чем работать.
Повторение. Если мы не хотим прописывать слишком длинный путь к файлу, файл с данными можно сохранить сразу в рабочую папку (папку, из которой запускается R). Тогда при попытке открыть файл с заданным названием R будет искать его в этой папке. Узнать, какая папка является рабочей, можно с помощью функции getwd()
:
getwd() # wd - от working directory
## [1] "/home/oem/Рабочий стол/rprogramming-4/R-programming-4/lectures/lect3-27-09"
Рабочую папку можно изменить. Например, так:
setwd("C:/AllaT/Рабочий стол/")
Для начала загрузим в R “простые” текстовые файлы. “Простые” в том смысле, что для их загрузки не требуется установки специальных библиотек.
csv-файлы
Формат csv (comma separated values) - широко распространенный текстовый формат, который используется для представления табличных данных. В качестве разделителя, т.е. символа, который разделяет значения колонок, обычно используется запятая, как и следует из названия.
df <- read.csv("example1.csv")
View(df) # посмотреть на базу данных, V - заглавная
Но иногда в качестве разделителя могут быть использованы другие символы (точка с запятой, пробел, табуляция). Если мы загрузим файл с другим разделителем и никак это не укажем, что загрузится совсем не то, что мы ожидали:
df1 <- read.csv("example2.csv")
View(df1)
А если выставим нужный разделитель в качестве параметра, то все будет, как нужно:
df1 <- read.csv("example2.csv", sep = ";") # sep - от separator
View(df1)
Если в файле есть текст на кириллице, могут возникнуть проблемы при чтении файла или при его отображении. Решения могут быть разными (зависит от системы, ее параметров и самого файла). Вот некоторые из них.
Можно посмотреть, какая кодировка и какие языки определены системой по умолчанию:
Sys.getlocale()
## [1] "LC_CTYPE=ru_RU.UTF-8;LC_NUMERIC=C;LC_TIME=ru_RU.UTF-8;LC_COLLATE=ru_RU.UTF-8;LC_MONETARY=ru_RU.UTF-8;LC_MESSAGES=ru_RU.UTF-8;LC_PAPER=ru_RU.UTF-8;LC_NAME=C;LC_ADDRESS=C;LC_TELEPHONE=C;LC_MEASUREMENT=ru_RU.UTF-8;LC_IDENTIFICATION=C"
Можно добавить русский язык:
#Sys.setlocale("Russian")
А можно просто спеифицировать кодировку самого файла:
#df2 <- read.csv("example3.csv", encoding = "UTF-8")
#df2 <- read.csv("example4.csv", encoding = "WINDOWS-1251")
Будем считать, что с csv-файлами разобрались.
txt-файлы
При работе с txt-файлами необходимо указывать, каким образом столбцы отделены друг от друга (аргумент sep
, разделитель, как и в случае в csv-файлами), а также учитывать, что представляет собой первая строка: наблюдение или шапку таблицы (аргумент header
). Откроем файл, в котором столбы разделены табуляцией и сравним, как он будет выглядеть при выставлении разных значений параметра header
:
table1 <- read.table('example1.txt', sep='\t', header = TRUE)
View(table1) # header = T - первая строка читается как имя переменной
table2 <- read.table('example1.txt', sep='\t', header = FALSE)
View(table2) # header = F - первая строка читается как наблюдение
Теперь перейдем к другим форматам.
файлы Excel
Чтобы спокойно загружать xls-файлы и xlsx-файлы необходимо установить соответствующие библиотеки xls
(xlsx
).
Установим библиотеку xlsx
. С ее установкой могут возникнуть проблемы: R будет писать что-то про rjava. Это обычно бывает, если на компьютере не установлена Java или установлена такая ее версия, которая конфликтует с R (например, недостаточно новая). Тогда Java можно поставить, скачав отсюда. После этого проблема должна исчезнуть.
install.packages("xlsx")
Теперь обратимся к этой библиотеке - иначе открыть файл мы не сможем:
library(xlsx)
Наконец, откроем сам файл. Не забудьте указать номер листа после запятой (даже если он всего один), иначе не сработает.
ex_data <- read.xlsx("example1.xlsx", 1)
файлы STATA
Для загрузки файлов STATA (файлы с расширением .dta
) потребуется библиотека foreign
.
install.packages("foreign")
library(foreign)
Теперь загрузим dta-файл.
stata_data <- read.dta("example1.dta")
файлы SPSS
Для загрузки файлов SPSS (файлы с расширением .sav
) потребуется библиотека Hmisc
.
install.packages("Hmisc")
library(Hmisc)
Загрузим sav-файл.
#sav_data <- spss.get("example1.sav")
Выгружаются данные из R аналогичным образом, но только вместо read
в названиях функций используется write
. Например, сохраним базу df в csv-формате:
write.csv(df, "new_file.csv")
Загрузим более содержательную базу данных. Базу данных, которая использовалась в исследовании Druckman, Levendusky, McLain No Need to Watch: How the Effects of Partisan Media Can Spread via Inter-Personal Discussions (2017). Файл и codebook к базе данных можно найти здесь.
dat <- read.csv("druckman_levendusky_mclain.csv")
Какую информацию о базе данных мы можем получить?
Можем определить число наблюдений и число переменных в базе. Узнать это можно точно так же, как и размерность матрицы, ведь число строк - это число наблюдений, а число столбцов - это число переменных.
dim(dat)
## [1] 575 31
Можем узнать гораздо больше - структуру базы данных: число наблюдений и переменных, типы переменных и примеры значений, которые они принимают. Сделать это можно с помощью уже знакомой функции str()
:
str(dat)
## 'data.frame': 575 obs. of 31 variables:
## $ X : int 1 2 3 4 5 6 7 8 9 10 ...
## $ Group_Number : int 101 100 102 101 102 103 101 102 102 102 ...
## $ Type_of_Session: Factor w/ 5 levels "Delbieration + Choice",..: 5 5 5 5 5 5 5 5 5 5 ...
## $ Condition : Factor w/ 16 levels "1","10A","10B",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ Numb_Delib : int NA NA NA NA NA NA NA NA NA NA ...
## $ IndepDelib : int NA NA NA NA NA NA NA NA NA NA ...
## $ Pid : int 1 1 1 1 1 2 2 2 2 2 ...
## $ PolInterest : num 3 3 2 3 1 1 3 2 2 2 ...
## $ Educ : int 3 2 4 3 4 2 3 3 4 4 ...
## $ Income : int 2 2 4 3 4 2 2 4 4 4 ...
## $ Race : int 0 0 0 0 0 5 0 0 0 0 ...
## $ Age : int 1 0 1 1 1 0 1 1 1 1 ...
## $ Female : int 1 1 1 1 0 1 1 1 0 0 ...
## $ Veto : int 1 0 1 1 1 0 1 1 1 1 ...
## $ OilExport : int 1 0 0 1 1 1 1 1 1 1 ...
## $ Renewable : int 1 0 0 1 1 1 1 1 1 0 ...
## $ HouseMajority : int 1 0 0 1 1 1 1 1 1 1 ...
## $ LawCons : int 1 0 1 1 1 1 1 1 1 1 ...
## $ SecState : int 0 0 1 0 1 0 1 1 1 1 ...
## $ GulfBan : int 0 1 0 1 0 0 1 1 1 0 ...
## $ ConsParty : int 1 0 1 1 1 1 1 1 1 1 ...
## $ MEOil : int 1 0 1 1 0 0 1 1 0 0 ...
## $ VideoWatch1 : Factor w/ 7 levels "","A","B","C",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ VideoWatch2 : Factor w/ 7 levels "","A","B","C",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ VideoWatch3 : Factor w/ 7 levels "","A","B","C",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ SupportCoastal : int 5 5 5 6 3 5 6 5 4 6 ...
## $ SupportFederal : int 4 2 4 4 3 5 6 4 4 7 ...
## $ SupportKeystone: int 5 4 4 4 5 6 6 4 4 6 ...
## $ KnowOther : int NA NA NA NA NA NA NA NA NA NA ...
## $ TrustOther : int NA NA NA NA NA NA NA NA NA NA ...
## $ ProtectEnviro : int NA NA 2 4 1 4 1 3 4 3 ...
Также легко посмотреть на первые несколько значений:
head(dat)
## X Group_Number Type_of_Session Condition Numb_Delib IndepDelib Pid
## 1 1 101 No Deliberation 1 NA NA 1
## 2 2 100 No Deliberation 1 NA NA 1
## 3 3 102 No Deliberation 1 NA NA 1
## 4 4 101 No Deliberation 1 NA NA 1
## 5 5 102 No Deliberation 1 NA NA 1
## 6 6 103 No Deliberation 1 NA NA 2
## PolInterest Educ Income Race Age Female Veto OilExport Renewable
## 1 3 3 2 0 1 1 1 1 1
## 2 3 2 2 0 0 1 0 0 0
## 3 2 4 4 0 1 1 1 0 0
## 4 3 3 3 0 1 1 1 1 1
## 5 1 4 4 0 1 0 1 1 1
## 6 1 2 2 5 0 1 0 1 1
## HouseMajority LawCons SecState GulfBan ConsParty MEOil VideoWatch1
## 1 1 1 0 0 1 1
## 2 0 0 0 1 0 0
## 3 0 1 1 0 1 1
## 4 1 1 0 1 1 1
## 5 1 1 1 0 1 0
## 6 1 1 0 0 1 0
## VideoWatch2 VideoWatch3 SupportCoastal SupportFederal SupportKeystone
## 1 5 4 5
## 2 5 2 4
## 3 5 4 4
## 4 6 4 4
## 5 3 3 5
## 6 5 5 6
## KnowOther TrustOther ProtectEnviro
## 1 NA NA NA
## 2 NA NA NA
## 3 NA NA 2
## 4 NA NA 4
## 5 NA NA 1
## 6 NA NA 4
Или последние:
tail(dat)
## X Group_Number Type_of_Session Condition Numb_Delib
## 570 570 99 Deliberation + Forced Exposure 9B 6
## 571 571 14 Deliberation + Forced Exposure 9B 4
## 572 572 99 Deliberation + Forced Exposure 9B 6
## 573 573 90 Forced Exposure + Deliberation 9B 4
## 574 574 33 Deliberation + Forced Exposure 9B 4
## 575 575 34 Deliberation + Forced Exposure 9B 4
## IndepDelib Pid PolInterest Educ Income Race Age Female Veto OilExport
## 570 1 6 2 2 2 0 1 1 1 1
## 571 1 6 2 4 3 0 1 0 1 1
## 572 1 7 2 1 2 0 1 1 0 0
## 573 0 7 4 2 3 0 0 0 1 1
## 574 0 7 2 4 3 0 1 1 1 1
## 575 0 7 4 4 4 0 1 0 1 1
## Renewable HouseMajority LawCons SecState GulfBan ConsParty MEOil
## 570 0 1 1 1 0 1 0
## 571 1 1 1 1 1 0 1
## 572 0 0 1 0 0 1 0
## 573 1 1 1 1 1 1 1
## 574 0 0 1 0 0 1 0
## 575 1 1 1 1 0 1 1
## VideoWatch1 VideoWatch2 VideoWatch3 SupportCoastal SupportFederal
## 570 6 6
## 571 4 3
## 572 6 7
## 573 6 6
## 574 4 6
## 575 6 7
## SupportKeystone KnowOther TrustOther ProtectEnviro
## 570 3 4 1 1
## 571 4 3 4 6
## 572 7 2 5 2
## 573 6 4 4 4
## 574 7 4 4 4
## 575 6 2 2 4
Обсуждение вывода описательных статистик для переменных в базе данных оставим на потом, разберем этот вопрос более подробно, когда начнем разведывательный анализ данных. А пока поговорим о чуть более продвинутых (но несложных!) вещах.
Результаты, которые выдают нам функции str()
и dim()
, содержат только общую информацию о количестве наблюдений в базе данных и не дают никакой информации о пропущенных значениях. Как это исправить? Для начала можно выяснить, сколько в базе неполностью заполненных строк. Функция complete.cases()
выдает логический вектор, где TRUE означает полностью заполненную строку, а FALSE - содержащую пропуски (NAs).
head(complete.cases(dat)) # head - первые несколько значений
## [1] FALSE FALSE FALSE FALSE FALSE FALSE
Посчитаем, сколько полностью заполненных наблюдений:
sum(complete.cases(dat))
## [1] 381
Соответственно, остальные (из 575) - недозаполненные (содержащие NAs).
Посмотрим на незаполненные строки:
View(dat[!complete.cases(dat), ]) # ! отрицание
Для дальнейшей работы с пропущенными значениями нам понадобятся дополнительные библиотеки. Установим их. Можно устанавливать сразу несколько библиотек – оформить перечень необходимых библиотек в виде вектора, и тогда сразу после установки одной библиотеки начнется загрузка следующей.
install.packages(c("mice", "VIM"))
Обратимся к ним:
library(mice)
library(VIM)
Выведем графики, которые покажут, в каких переменных пропущенных значений больше всего и как выглядит база с пропущенными значениями (паттерны пропущенных значений).
На графике слева показано, с какой частотой встречаются пропущенные значения в той или иной переменной. На графике справа показано, в каких комбинациях эти пропущенные значения встречаются. Например, в нашем случае отсутствие ответов в TrustOther часто совпадает с отсутствием ответов в KnowOther (пропущенные значения отмечены красным цветом).
aggr(dat)
Следующий график отвечает за заполненность наблюдений (красным цветом отмечены пропущенные значения, остальное - заполненные значения, чем темнее цвет, тем больше значение). По вертикальной оси - номер строки в базе данных (id наблюдения).
matrixplot(dat)
Удаление пропущенных значений
При работе с базами данных необходимо удалить пропущенные значения (или правильно заполнить - кто умеет), потому что иначе мы не сможем полноценно работать с базой (многие функции не работают при наличии NAs, а у некоторых необходимо указывать дополнительный аргумент - учитывать NA или нет).
dat <- na.omit(dat)
Если мы хотим обратиться к конкретной переменной и рассматривать ее как вектор элементов, нужно использовать символ $
.
dat$Educ # образование
## [1] 4 3 3 3 3 2 3 2 3 4 2 3 4 3 3 2 2 2 3 3 3 3 2 1 4 4 4 3 3 1 4 4 3 4 4
## [36] 4 2 4 2 4 2 4 3 4 2 4 2 4 3 4 2 2 1 3 3 4 2 3 3 3 3 3 3 3 3 4 4 4 4 3
## [71] 3 3 3 3 3 4 2 3 2 3 2 2 1 3 3 4 4 4 3 4 4 3 4 2 2 1 2 2 4 2 4 4 3 3 4
## [106] 2 3 3 4 3 3 4 2 4 3 3 4 3 1 3 2 3 2 1 4 4 4 3 2 2 2 2 3 4 4 2 4 4 2 1
## [141] 4 4 1 2 2 2 2 1 2 2 3 4 3 4 3 4 3 2 3 4 3 2 2 3 2 4 2 4 1 3 2 3 3 2 4
## [176] 3 2 3 2 3 1 3 3 3 2 4 2 3 2 2 1 2 2 4 4 3 4 3 3 4 4 4 2 2 3 2 4 4 4 3
## [211] 4 3 3 2 3 2 1 1 2 3 2 2 4 4 2 4 2 2 2 3 3 2 1 2 3 3 1 3 3 2 4 2 4 3 3
## [246] 4 3 1 3 2 4 4 3 3 3 4 3 1 3 2 2 3 3 2 1 4 2 4 4 3 3 2 2 2 2 2 2 2 3 3
## [281] 4 2 2 1 4 3 4 3 4 1 3 4 1 3 3 3 4 3 2 2 2 3 2 1 4 4 2 1 2 3 4 1 4 2 3
## [316] 3 4 3 4 2 2 4 3 2 4 1 1 2 1 4 2 3 4 2 2 3 3 2 2 1 3 3 3 2 2 3 2 4 4 3
## [351] 2 3 4 2 3 3 4 4 3 4 4 2 2 2 3 4 3 2 2 1 3 4 2 3 3 2 4 1 2 4 4
Attach и detach
Мы можем “закрепить” базу данных с помощью команды attach, чтобы обращаться к переменным более простым способом:
attach(dat) # заодно покажет, какие переменные есть
head(Educ) # имя переменной как есть, без $
## [1] 4 3 3 3 3 2
Educ
## [1] 4 3 3 3 3 2 3 2 3 4 2 3 4 3 3 2 2 2 3 3 3 3 2 1 4 4 4 3 3 1 4 4 3 4 4
## [36] 4 2 4 2 4 2 4 3 4 2 4 2 4 3 4 2 2 1 3 3 4 2 3 3 3 3 3 3 3 3 4 4 4 4 3
## [71] 3 3 3 3 3 4 2 3 2 3 2 2 1 3 3 4 4 4 3 4 4 3 4 2 2 1 2 2 4 2 4 4 3 3 4
## [106] 2 3 3 4 3 3 4 2 4 3 3 4 3 1 3 2 3 2 1 4 4 4 3 2 2 2 2 3 4 4 2 4 4 2 1
## [141] 4 4 1 2 2 2 2 1 2 2 3 4 3 4 3 4 3 2 3 4 3 2 2 3 2 4 2 4 1 3 2 3 3 2 4
## [176] 3 2 3 2 3 1 3 3 3 2 4 2 3 2 2 1 2 2 4 4 3 4 3 3 4 4 4 2 2 3 2 4 4 4 3
## [211] 4 3 3 2 3 2 1 1 2 3 2 2 4 4 2 4 2 2 2 3 3 2 1 2 3 3 1 3 3 2 4 2 4 3 3
## [246] 4 3 1 3 2 4 4 3 3 3 4 3 1 3 2 2 3 3 2 1 4 2 4 4 3 3 2 2 2 2 2 2 2 3 3
## [281] 4 2 2 1 4 3 4 3 4 1 3 4 1 3 3 3 4 3 2 2 2 3 2 1 4 4 2 1 2 3 4 1 4 2 3
## [316] 3 4 3 4 2 2 4 3 2 4 1 1 2 1 4 2 3 4 2 2 3 3 2 2 1 3 3 3 2 2 3 2 4 4 3
## [351] 2 3 4 2 3 3 4 4 3 4 4 2 2 2 3 4 3 2 2 1 3 4 2 3 3 2 4 1 2 4 4
Однако это не всегда удобно, особенно если приходится работать с несколькими базами одновременно (наложение переменных с одинаковыми именами, проблемы с редактированием и прочее).
detach(dat) # возвращаем обратно
Допустим, мы хотим добавить в базу переменную Session. Для этого нужно через $ задать имя новой переменной и присвоить ей значение:
dat$Session <- factor(dat$Type_of_Session)
View(dat)
Часто при работе с данными возникает необходимость выбрать несколько переменных или определенную группу наблюдений и анализировать их отдельно - чтобы не загружать каждый раз огромную базу с ненужными показателями.
Можем выбрать несколько переменных (столбцов) и сохранить их в другую базу:
dat[2:4] # 2 и 4 - порядковые номера столбцов, от 2 до 4
Получится маленькая база из трех переменных. И сохраним как новую базу dat1:
dat1 <- dat[2:4]
View(dat1)
Если выбираем столбцы не подряд, обязательно их номера нужно оформить в виде вектора:
dat[c(1, 3)] # не просто dat[1, 3]
В противном случае получится совсем не то:
dat[1, 3]
## [1] Delbieration + Choice
## 5 Levels: Delbieration + Choice ... No Deliberation
Это “совсем не то” связано с тем, что, когда мы указываем в квадратных скобках числа через запятую, R воспринимает первое число как номер строки, второе число - как номер столбца (как в матрицах - сначала строка, потом столбец). Можем посмотреть на исходную базу и убедиться в этом:
View(dat)
Но таким образом мы можем выбирать строки (наблюдения):
dat[, 1:3] # берем все наблюдения (строки), первые 3 переменные (столбцы)
Или столбцы:
dat[1:4, ] # берем первые 4 наблюдения (строки), все переменные (столбцы)
Фильтрация по условиям
Если хотим отобрать из базы определенные наблюдения, это тоже можно сделать с помощью subset()
(“фильтры”). Например, хотим выбрать респондентов с определенным уровнем образования:
sub_educ <- subset(dat, Educ >= 3)
View(sub_educ)
Для указания нескольких условий опять потребуются логические операторы:
y <- subset(dat, Educ >= 3 & Female == 0) # несколько условий
View(y)
Конечно, можем отбирать наблюдения и переменные одновременно:
z <- subset(dat, Educ >= 3 & Female == 0, select = c(Group_Number, Educ, Female))
View(z)
Чтобы удалить переменные, можно действовать двумя способами:
удалить их из базы
оставить все остальные переменные в базе
По смыслу это одно и то же. И то, и другое чаще всего осуществляется с помощью функции subset()
.
Допустим, мы хотим выбрать переменные Educ и Female и сохранить их в новую базу:
dat <- subset(dat, select = c(Educ, Female)) # указываем имя базы, оставляем Educ и Female
View(dat)
А теперь хотим оставить все, кроме переменной Educ:
dat1 <- subset(dat, select = -Educ) # перед ней стоит минус
View(dat1)