При помощи функций read.table(), read.csv(), read.csv2(), read.delim() загружают данные из файла во фрейм данных. Эти функции довольно похожи, только у них разные значения формальных параметров по умолчанию.
Например:
read.csv(sep=',', dec=".") – значения разделены запятыми, дробная часть отделяется точкой
read.csv2(sep=';', dec=",") – значения разделены запятыми, дробная часть отделяется точкой, как принято в России
В реальной жизни мы используем эти функции с параметром file="имя текстового файла с данными"
в наших примерах нагляднее будет в этих функциях вместо параметра file= воспользоваться параметром text=
girls.textdata=
"row.name|name|age|hobby|height
g1|Лена|19|лыжи|166
g2|Жанна|22|вышивка|156,5
g3|Даша|29|лыжи|180
g4|Ира|26|танцы|170
g5|Зина|16|танцы|160"
girls <- read.delim(header=T,
sep="|" , dec = ",",
text= girls.textdata,
row.names = 1,
stringsAsFactors = F
)
Обьяснения параметров:
header=T – считать первую строку файла строкой заголовков и взять имена столбцов из неёrow.names = 1 – взять имена строк из первого столбца файлаstringsAsFactors = F – оставить текстовые строки строками (векторами character), и не преобразовывать текстовые стобцы в столбцы типа фактор, где каждое уникальное значение получает числовой код и в фактор-векторе запоминаются уже числовые коды. В этом примере стобец hobby пропускается, а у стобца height автоматически определяется тип number (вещественное число)Результат импорта:
str(girls)
## 'data.frame': 5 obs. of 4 variables:
## $ name : chr "Лена" "Жанна" "Даша" "Ира" ...
## $ age : int 19 22 29 26 16
## $ hobby : chr "лыжи" "вышивка" "лыжи" "танцы" ...
## $ height: num 166 156 180 170 160
girls
## name age hobby height
## g1 Лена 19 лыжи 166.0
## g2 Жанна 22 вышивка 156.5
## g3 Даша 29 лыжи 180.0
## g4 Ира 26 танцы 170.0
## g5 Зина 16 танцы 160.0
В следующем примере вместо возраста указана дата рождения и имена строк генерируются автоматически вместо чтения их из текстовых данных. Применен параметр colClasses=
girls.textdata2=
"name|birth.date|hobby|height
Лена|1995-02-12|лыжи|166
Жанна|1988-2-20|вышивка|156,5
Даша|1990-12-04|лыжи|180
Ира|2000-11-11|танцы|170"
girls2 <- read.delim(header=T,
colClasses = c("character","Date","NULL", NA),
sep="|" , dec=",",
text= girls.textdata2,
row.names = NULL
)
Обьяснения параметров:
row.names = NULL – не брать имена строк из первого столбца файла, а сгенерировать автоматически: 1,2,3,…colClasses = c("character","character","integer","character", "numeric") – чтобы добится правильной интерпретации данных часто приходится указывать явно типы столбцов (включая имена строк). Возможные типы: logical, integer, numeric, complex, character, raw, а также “factor”, “Date” or “POSIXct”. Кроме того можно укзать “NULL” (именно в кавычках – пропустить соответствующий стобец) или NA (не знаю – сама догадайся, ты функция умная)
stringsAsFactors= – уже не нужен, поскольку есть параметр colClasses=
Результаты:
str(girls2)
## 'data.frame': 4 obs. of 3 variables:
## $ name : chr " Лена" " Жанна" " Даша" " Ира"
## $ birth.date: Date, format: "1995-02-12" "1988-02-20" ...
## $ height : num 166 156 180 170
girls2
## name birth.date height
## 1 Лена 1995-02-12 166.0
## 2 Жанна 1988-02-20 156.5
## 3 Даша 1990-12-04 180.0
## 4 Ира 2000-11-11 170.0
Импортируем также и данные про мальчиков
boys.textdata=
"row.name|name|age|hobby|height
b1|Гена|19|лыжи|188
b2|Женя|32|мотоцикл|166,5
b3|Саша|29|лыжи|180
b4|Дима|26|танцы|170"
boys <- read.delim(header=T,
sep="|" , dec = ",",
text= boys.textdata,
row.names = 1,
stringsAsFactors = F
)
boys
## name age hobby height
## b1 Гена 19 лыжи 188.0
## b2 Женя 32 мотоцикл 166.5
## b3 Саша 29 лыжи 180.0
## b4 Дима 26 танцы 170.0
Узнаем, какая у нас текущая рабочая директория
getwd()
## [1] "/Users/ikochergin/Documents/bivni_msu"
Если папка не сущетсвует, создаем. Если бы первая функция вернула TRUE, то операция || (или) не вызвала бы вторую функцию.
dir.exists("data") || dir.create("data")
## [1] TRUE
Скачиваем файл из интернета и раззиповываем
url_world_data <- "http://crow.academy.ru/~ikocherg/stud_do/2015vesna/world.txt.zip"
download.file(url_world_data,destfile = "data/world.txt.zip")
unzip("data/world.txt.zip",exdir = "data")
Мы еще не проходили еще продвинутые шаблоны строк регулярные выражения, которые сейчас поддерживают практически все языки программирования. Следующий код ищет файлы, соответствующие шаблону (pattern) в текущей папке и еще поддиректориях (рекурсивно: recursive=T). В шаблоне указано, что в начале (^) названия должно быть слово city либо country, затем любые символы в любом количестве (.*) потом в конце ($) названия txt.
list.files(pattern = "^(city|country).*txt$",path=".", recursive = T,include.dirs = T)
## [1] "data/city.txt"
## [2] "data/country.txt"
## [3] "data/countrylanguage.txt"
## [4] "src/world.data/city.txt"
## [5] "src/world.data/country.txt"
## [6] "src/world.data/countrylanguage.txt"
Функции head() и tail() позволяют посмотреть начало и конец векторов и фреймов данных. по умолчанию показывают 6 строк
head(cars)
## speed dist
## 1 4 2
## 2 4 10
## 3 7 4
## 4 7 22
## 5 8 16
## 6 9 10
tail(cars)
## speed dist
## 45 23 54
## 46 24 70
## 47 24 92
## 48 24 93
## 49 24 120
## 50 25 85
Функция readLines() позволяет читать текстовый файл как масив текстовых строк (не разбирая на поля)
city.text <- readLines("data/city.txt")
head(city.text)
## [1] "CityID;Name;CountryCode;District;Population"
## [2] "1;Kabul;AFG;Kabol;1780000"
## [3] "2;Qandahar;AFG;Qandahar;237500"
## [4] "3;Herat;AFG;Herat;186800"
## [5] "4;Mazar-e-Sharif;AFG;Balkh;127800"
## [6] "5;Amsterdam;NLD;Noord-Holland;731200"
city <- read.csv2("data/city.txt",as.is=T)
str(city)
## 'data.frame': 4079 obs. of 5 variables:
## $ CityID : int 1 2 3 4 5 6 7 8 9 10 ...
## $ Name : chr "Kabul" "Qandahar" "Herat" "Mazar-e-Sharif" ...
## $ CountryCode: chr "AFG" "AFG" "AFG" "AFG" ...
## $ District : chr "Kabol" "Qandahar" "Herat" "Balkh" ...
## $ Population : int 1780000 237500 186800 127800 731200 593321 440900 234323 201843 193238 ...
as.is=T эквивалентен параметру stringsAsFactors=Fread.csv2(header=T,dec=",",sep=";") подходят намcountry <- read.csv2("data/country.txt",as.is=T)
str(country)
## 'data.frame': 239 obs. of 15 variables:
## $ CountryCode : chr "ABW" "AFG" "AGO" "AIA" ...
## $ Name : chr "Aruba" "Afghanistan" "Angola" "Anguilla" ...
## $ Continent : chr "North America" "Asia" "Africa" "North America" ...
## $ Region : chr "Caribbean" "Southern and Central Asia" "Central Africa" "Caribbean" ...
## $ SurfaceArea : num 193 652090 1246700 96 28748 ...
## $ IndepYear : int NA 1919 1975 NA 1912 1278 NA 1971 1816 1991 ...
## $ Population : int 103000 22720000 12878000 8000 3401200 78000 217000 2441000 37032000 3520000 ...
## $ LifeExpectancy: num 78.4 45.9 38.3 76.1 71.6 83.5 74.7 74.1 75.1 66.4 ...
## $ GNP : num 828 5976 6648 63.2 3205 ...
## $ GNPOld : num 793 NA 7984 NA 2500 ...
## $ LocalName : chr "Aruba" "Afganistan/Afqanestan" "Angola" "Anguilla" ...
## $ GovernmentForm: chr "Nonmetropolitan Territory of The Netherlands" "Islamic Emirate" "Republic" "Dependent Territory of the UK" ...
## $ HeadOfState : chr "Beatrix" "Mohammad Omar" "Josй Eduardo dos Santos" "Elisabeth II" ...
## $ Capital : int 129 1 56 62 34 55 33 65 69 126 ...
## $ Code2 : chr "AW" "AF" "AO" "AI" ...
Этот пакет позволяет делать с фреймами данных операции аналогичные по возможностям операм языка SQL, кроме того у этого пакета есть возможности интеграции с базами данных.
Шпаргалка по пакету находится в разделе шпаргалок RStudio под именем Data Wrangling Cheat Sheet
library(dplyr)
При загрузке этого пакета загружается оператор %>% “pipe”, позволяющй устраивать конвеер преобразований. Допустим выражение h(g(f(x,p),q),r) выглядит громозко. Можно воспользоваться оператором pipe, подставляющий функции справа от него, в качестве первого параметра результат выражения, находящегося слева от него. Мы может для h(g(f(x,p),q),r) написать эквивалентное выражение x %>% f(p) %>% g(q) %>% h(r). Заметьте, то первый параметр функций не пишется явно.
arrange(df,поле) или arrange(df,desc(поле)) – упорядочить (выдать упорядоченным) фрейм данных в порядке возрастания или убывания указанного поля.select(df,какие столбцы выдавать) выдаст из df только указанные столбцы.filter(df,условия отбора) – выбрать строки, удовлетворяющие условиюgroup_by(df,список полей по которым нужно группировать) – разбить фрейм данных на группы.summarize(df,новое.поле=групповая_функция(поле)) – при помощи групповой функции подсчитать по всему фрейма данных или по каждой группе итоговый показатель при помощи групповых функций (mean,median,min,max,sd,sum,var)Примеры использования этих функций
Выберем нужные столбцы:
select(girls,-c(age))
## name hobby height
## g1 Лена лыжи 166.0
## g2 Жанна вышивка 156.5
## g3 Даша лыжи 180.0
## g4 Ира танцы 170.0
## g5 Зина танцы 160.0
select(girls,name, contains("hei"))
## name height
## g1 Лена 166.0
## g2 Жанна 156.5
## g3 Даша 180.0
## g4 Ира 170.0
## g5 Зина 160.0
Найдем медиану высот девушек, а затем найдем девушку, чья высота равна медиане
( df1 <- summarize(girls,median.height=median(height)) )
## median.height
## 1 166
filter(girls,df1$median.height==height)
## name age hobby height
## 1 Лена 19 лыжи 166
Разобьем таблицу (data frame) девушек на группы по хобби, и выдадим сколько девушек в группе и их средний возраст.
girls %>%
group_by(hobby) %>%
summarize(mean.age=mean(age),count=n())
## Source: local data frame [3 x 3]
##
## hobby mean.age count
## (chr) (dbl) (int)
## 1 вышивка 22 1
## 2 лыжи 24 2
## 3 танцы 21 2
Добавим сортировку по убыванию среднего возраста
girls %>%
group_by(hobby) %>%
summarize(mean.age=mean(age),count=n()) %>%
arrange(desc(mean.age))
## Source: local data frame [3 x 3]
##
## hobby mean.age count
## (chr) (dbl) (int)
## 1 лыжи 24 2
## 2 вышивка 22 1
## 3 танцы 21 2
Например, бабушки на лавочки у подъезда хотят обсудить возможные пары девочек и мальчиков из их подъезда. Они решили рассмотреть пары с общими хобби
girls
## name age hobby height
## g1 Лена 19 лыжи 166.0
## g2 Жанна 22 вышивка 156.5
## g3 Даша 29 лыжи 180.0
## g4 Ира 26 танцы 170.0
## g5 Зина 16 танцы 160.0
boys
## name age hobby height
## b1 Гена 19 лыжи 188.0
## b2 Женя 32 мотоцикл 166.5
## b3 Саша 29 лыжи 180.0
## b4 Дима 26 танцы 170.0
inner_join(x = girls,y=boys,by=c("hobby"))
## name.x age.x hobby height.x name.y age.y height.y
## 1 Лена 19 лыжи 166 Гена 19 188
## 2 Лена 19 лыжи 166 Саша 29 180
## 3 Даша 29 лыжи 180 Гена 19 188
## 4 Даша 29 лыжи 180 Саша 29 180
## 5 Ира 26 танцы 170 Дима 26 170
## 6 Зина 16 танцы 160 Дима 26 170
Заметьте, что человек, у кого с его хобби нет пары не попадает в результат внутреннего соединения. О других типах соединения будет рассказано позже.