Создать вектор в r studio
Находит широкое применение в различных областях знаний для моделирования, статистического анализа и обработки данных.
Преобразование типов и структур данных друг в друга
Преобразование типов данных осуществляется через группу функций, начинающихся на as.
Пример конвертации целочисленного вектора в текстовый
Особенности приведения чисел выраженных как factors к числовому виду.
Преобразуем вектор целых чисел в номинальную шкалу (factor).
Для обратной конвертации использование функции as.integer недостаточно.
Это связано с внутренним представлением типа данных factor. Эта структура представляет собой набор целочисленных значений, каждому из которых присвоено имя. В данном примере именами являются значения 1 и 0.
Поэтому для корретного преобразования factor в целочисленный тип данных необходимо предварительно провести конвертацию в текстовый вид.
Данная операция часто вызывает затрудние и служит причиной ошибок.
Подобно преобразованию типов данных возможно приведение различных структур данных к другому типу с помощью того же семейства функций, начинающихся на as. .
Преобразоваание матрицы в data.frame
Factors
Factor - представляет номинальную или ранговую шкалу. Используется для представления Y в классификационных моделях.
Основные достоинства:
3.2 Приведение типов
Что будет, если вы объедините два вектора с значениями разных типов? Ошибка?
Мы уже обсуждали, что в обычных векторах (atomic векторах) может быть только один тип данных. В некоторых языках программирования при операции с данными разных типов мы бы получили ошибку. А вот в R при несовпадении типов произойдет попытка привести типы к “общему знаменателю,” то есть конвертировать данные в более “широкий” тип (а иногда – более “узкий” тип, если того требует функция).
FALSE превратился в 0 (а TRUE превратился бы в 1 ), чтобы оба значения можно было объединить в вектор. То же самое произошло бы в случае операций с векторами:
Это называется неявным приведением типов (implicit coercion).
Вот более сложный пример:
Здесь все значения были приведены сразу к строковому типу данных.
У R есть иерархия приведения типов:
Мы из этого списка еще многого не знаем, сейчас важно запомнить, что логические данные – TRUE и FALSE – превращаются в 0 и 1 соответственно, а 0 и 1 в строчки "0" и "1" .
Если Вы боитесь полагаться на приведение типов, то можете воспользоваться функциями as.нужныйтипданных для явного приведения типов (explicit coercion):
Можно превращать и обратно, например, строковые значения в числовые. Если среди числа встретится буква или другой неподходящий знак, то мы получим предупреждение NA – пропущенное значение (мы очень скоро научимся с ними работать).
Один из распространенных примеров использования неявного приведения типов – использования функций sum() и mean() для подсчета в логическом векторе количества и доли TRUE соответсвенно. Мы будем много раз пользоваться этим приемом в дальнейшем!
Векторизация
В R действия выполняются поэлементно сразу над всем набором данных (будь то вектор, матрица, data.frame и т.д.). Векторные вычисления очень эффективны, поэтому всегда когда нужно совершить действия над элементами вектора (матрицы и т.д.) предпочтительнее использовать векторизацию, а не циклы.
Кстати оператор присваивания тоже является функцией, и присвоение можно выполнить в таком виде
Сложение двух векторов одинаковой длины происходит поэлементно
Как упоминалось, векторные вычисления могут производиться над любой структурой данных (вектор, матрица, data.frame и т.д.). Пусть у нас есть матрица
Умножим все ее элементы на 2, или возведем во вторую степень
Векторы
Загрузим файл sol_y1.RData и определим среднее значение растворимости в выборке, медианное значение, максимальное и минимальное значения.
Все приведенные функции векторизированы, поэтому расчет происходит очень быстро и эффективно.
Функция summary возвращает всю вышеприведенную статистику в виде одного вектора значений.
Помимо этих есть еще множество функций рассчета различных статистических характеристик.
Сохранение данных в бинарном формате
Любые объекты созданные в R можно сохранить в бинарном формате в виде файлов .RData . Это позволяет осуществлять быструю загрузку и доступ к сохраненным данным.
Таким образом можно сохранить данные из однажды прочитанного текстового файла в бинарном формате и в дальнейшем загружать эти данные из него.
Чтобы сохранить содержимое переменной x1 используем следующий вызов (указание ключевого слова file является обязательным)
3.4 Ресайклинг
Допустим мы хотим совершить какую-нибудь операцию с двумя векторами. Как мы убедились, с этим обычно нет никаких проблем, если они совпадают по длине. А что если вектора не совпадают по длине? Ничего страшного! Здесь будет работать правило ресайклинга (правило переписывания, recycling rule). Это означает, что если мы делаем операцию на двух векторах разной длины, то если короткий вектор кратен по длине длинному, короткий вектор будет повторяться необходимое количество раз:
А что будет, если совершать операции с вектором и отдельным значением? Можно считать это частным случаем ресайклинга: короткий вектор длиной 1 будет повторятся столько раз, сколько нужно, чтобы он совпадал по длине с длинным:
Если же меньший вектор не кратен большему (например, один из них длиной 3, а другой длиной 4), то R посчитает результат, но выдаст предупреждение.
Проблема в том, что эти предупреждения могут в неожиданный момент стать причиной ошибок. Поэтому не стоит полагаться на ресайклинг некратных по длине векторов. А вот ресайклинг кратных по длине векторов – это очень удобная штука, которая используется очень часто.
Числовые индексы
Выбор элементов вектора по их индексу
Из этого примера видно, что для индексирования и выбора элементов на самом деле используется вектор индексов.
Чтобы выбрать каждый второй элемент по индексу надо сгенерировать вектор, состоящий из четных чисел и использовать его для индексации исходного вектора.
Для удаления элементов по значению индекса перед ними добавляют знак минус
Особенности индексирования позволяют менять положение элементов и дублировать их. Это очень эффективный прием, о котором часто забывают.
С точки зрения индексирования матрицы и data.frames почти ничем не отличаются.
Создадим тестовый набор данных:
Выберем элемент строки 1 и колонки 2
Выберем все значения строки 1. Результатом будет новый data.frame
Выберем все значения колонки 1. Результатом будет вектор! Мы говорили выше, что data.frame это список колонок-векторов, и при выборе одной колонки присходит автоматическое преобразование результата к ветору.
Чтобы избежать этого необходимо добавить опцию drop . Теперь результатом будет data.frame
Для выбора блоков данных в качестве индексов строк и стобцов можно использовать
Отрицательные индексы используются для удаления соответствующих колонок и строк (обратите внимание, что удаляется не один элемент а колонки и строки):
что аналогично предыдущему примеру, приводящему к тому же результату
Логические индексы
Генерация логического индекса (вектора) для вектора a
который можно использовать для выбора соответствующих элементов
Возможна комбинация логических индексов с использованием операторов AND (&) и OR (|)
Логическое отрицание, оператор NOT (!), инвертирует значения логических индексов
Логический индекс (вектор) можно преобразовать в числовой. Функция which возвращает порядковые номера элементов, значение которых TRUE
3.6 Работа с логическими векторами
На работе с логическими векторами построено очень много удобных фишек, связанных со сравнением условий.
Внешний вид RStudio
Важно! R является регистрозависимым языком, поэтому надо быть внимательным при написании имен команд и переменных. Переменные big_table и Big_table рассматриваются как разные.
3.3 Векторизация
Все те арифметические операторы, что мы использовали ранее, можно использовать с векторами одинаковой длины:
Если применить операторы на двух векторах одинаковой длины, то мы получим результат поэлементного применения оператора к двум векторам. Это называется векторизацией (vectorization).
Если после какого-нибудь MATLAB Вы привыкли, что по умолчанию операторы работают по правилам линейной алгебры и m * n будет давать скалярное произведение (dot product), то снова нет. Для скалярного произведения нужно использовать операторы с % по краям:
Абсолютно так же и с операциями с матрицами в R, хотя про матрицы будет немного позже.
В принципе, большинство функций в R, которые работают с отдельными значениями, так же хорошо работают и с целыми векторами. Скажем, если вы хотите извлечь корень из нескольких чисел, то для этого не нужны никакие циклы (как это обычно делается во многих других языках программирования). Можно просто “скормить” вектор функции и получить результат применения функции к каждому элементу вектора:
Таких векторизованных функций в R очень много. Многие из них написаны на более низкоуровневых языках программирования (C, C++, FORTRAN), за счет чего использование таких функций приводит не только к более элегантному, лаконичному, но и к более быстрому коду.
Векторизация в R – это очень важная фишка, которая отличает этот язык программирования от многих других. Если вы уже имеете опыт программирования на другом языке, то вам во многих задачах захочется использовать циклы типа for и while 7.2. Не спешите этого делать! В очень многих случаях циклы можно заменить векторизацией. Тем не менее, векторизация – это не единственный способ избавить от циклов типа for и while 8.5.1.
Чтение данных в бинарном формате
Загрузим ранее сохраненный файл sol_x1.RData
Как вы могли заметить в списке загруженных переменных появилась новая с именем x1 как у ранее сохраненного data.frame.
Однако если в разных файлах сохранены объекты с одинаковым названием, то для их одновременной загрузки эти объекты необходио переименовать. Это можно во время загрузки данных, использовав следующий набор команд:
Проверим загруженный объект x1.1 на идентичность с x1
apply
Семейство функций apply является более удобным аналогом цикла for .
Рассмотрим пример - необходимо найти среднее значение каждой колонки в data.frame.
Решение с использованием цикла for
Решение с использованием функции apply
Правда короче и проще? Кроме того вектор с результатами содержит названия переменных.
А вот выражение, которое вычисляет среднее значение по строкам
На самом деле для операции нахождения среднего и суммы по строкам/столбцам есть отдельные векторизированные функции rowMeans , rowSums и т.д.
Общий вид вызова функции apply
X - матрица, массив или data.frame
MARGIN - порядковый номер размерноси, к которой будет применяться функция FUN (1 для строк, 2 для колонок)
FUN - применяемая функция
Результатом будет являться вектор (если используемая функция возвращает одно значение), массив (если функция возвращает вектор значений) или список (если функция возвращает результат в виде более сложной структуры данных, например data.frame или матрица).
ВАЖНО! При применении функции apply к data.frame, data.frame неявно приводится к матрице. Матрицы как мы помним содержат данные только одного типа. Это означеат что если в data.frame 9 числовых колонок и 1 текстовая, то будет произведена конвертация в текстовую матрицу, и следовательно все действия будут производиться над текстовой матрицей.
Пример
Чуть более сложный пример - надо посчитать для каждой колонки среднее значение и извлечь из него квадратный корень. выполним это с использованием функции apply
Предложите альтернативный вариант расчета.
Data.frames
Продемонстрируем работу с data.frames на примере.
Есть два набора соединений с рассчитанными дескрипторами и их необходимо объединить в один data.frame.
Загрузим оба имеющихся файла данных:
Проверим размерность загруженных данных. Функция dim возвращает размерность данных (число строк и число столбцов), другими словами число соединений и число дескрипторов.
Поскольку число дескрипторов отличается, то выясним какие дескрипторы отсутствуют в каждом из наборов данных.
Функция setdiff возвращает элементы первого вектора, которые отсутствуют во втором
var.names1 содержит имена дескрипторов, которые присутствуют в x1 и отсутствуют в x2 . Аналогично для var.names2 .
Посмотрим сколько таких дескриптров в каждом случае
Т.е. первый набор данных содержит 923 дескриптора, которые отсутствуют вов втором наборе, а второй - 383, которые отсутствуют в первом.
Поскольку мы используем фрагментные дескрипторы, то их отсутствие фактически означает, что число дескриторов данного вида равно нулю. Следовательно мы должны добавить отсутствующие дескрипторы в каждый набор данных и приравнять все их значения нулю.
Чтобы добавить нулевые значения этим дескрипторам мы вызываем их для соответствующего data.frame и присваиваем значение 0 .
Проверям размерность полученных данных
Число колонок (дескрипторов) теперь идентично. Проверим порядок следования дескриптров в каждом наборе, используя следующую конструкцию
Выражение в скобках возвращает вектор логических значений, который содержит TRUE в случае если на одинаковых позициях находятся одинаковые значения и FALSE в противном случае. Функция all возвращает TRUE , если все значения логического вектора равны TRUE .
Проверим действительно ли имена дескрипторов в обоих data.frames совпадают и мы ничего не упустили. Используем для этого функцию %in% , которая принимает два вектора, и если значение первого вектора присутствует во втором, то для этого элемента возвращается значение TRUE . Таким образом выражение записанное ниже можно прочитать как “все ли названия колонок первого набора данных присутствуют во втором наборе”
Аналогично выполняется проверка для второго набора
Две эти проверки можно заменить одной, если предварительно отсортировать имена колонок в обоих наборах почле чего сравнить их
Теперь перед объединением строк обоих data.frames необходимо расположить колонки в одинаковом порядке. Воспользуемся для этого свойством индексов и расположим колонки в x2 в той же последовательности что и в x1
Теперь колонки расположены в одной последовательности. Проверим
Полученные data.frames теперь можно объединить в один с использованием функции rbind - объединение данных по строкам (row bind).
Аналогично когда надо объединить данные по колонкам используется функция cbind .
Загрузим и объединим значения свойства для двух наборов данных
Посмотрим на распределение значений свойства
Онлайн курсы
-
- “Программирование на языке R”, начало курса 2 июня 2014
Семейство функций apply
Индексы списков
Для извлечения определенных элементов списка можно использовать числовые, текстовые и логические индексы. Однако при индексации списков есть некоторые особенности.
Создадим произвольный именованый список из двух элементов.
Выберем первый элемент списка запросом показанным ниже.
Обратите внимание, что в результате мы получим новый список содержащий только один элемент. Проверим это
Выберем первый элемент списка используя другую функцию
В этом случае запрос вернул содержимое первого элемента списка - целочисленный вектор.
Это важная особенность, которую упускают начинающие.
Альтернативный вариант доступа к содержимому одного элемента списка по его имени возможен с использоваем специальной конструкции ($)
Это аналогично следующему вызову с использованием текстового индекса
Сохранение данных в текстовом формате
Функция write.table сохраняет данные в текстовом формате. Она имеет много параметров для гибкой настройки вида сохраняемого файла.
3.8 Заключение
Итак, с векторами мы более-менее разобрались. Помните, что вектора – это один из краеугольных камней вашей работы в R. Если вы хорошо с ними разобрались, то дальше все будет довольно несложно. Тем не менее, вектора – это не все. Есть еще два важных типа данных: списки (list) и матрицы (matrix). Их можно рассматривать как своеобразное “расширение” векторов, каждый в свою сторону. Ну а списки и матрицы нужны чтобы понять основной тип данных в R – data.frame.
Язык R принадлежит к семейству так называемых высокоуровневых объектно-ориентированных языков программирования. Для неспециалиста строгое определение понятия «объект» является достаточно абстрактным. Однако для простоты можно называть объектами все, что мы создаем в ходе работы с R. Их выделяют два основных типа:
- Объекты, предназначенные для хранения данных («data objects») – это векторы, матрицы и массивы, списки, факторы, таблицы данных;
- Функции («function objects») – это поименованные программы, предназначенные для выполнения определенных действий над другими объектами.
Вектор представляет собой поименованный одномерный объект, содержащий набор однотипных элементов (числовые, логические, либо текстовые значения - никакие сочетания не допускаются). Для создания векторов небольшой длины в R используется т.н. функция конкатенации c() (от "concatenate" – объединять, связывать). В качестве аргументов этой функции через запятую перечисляют объединяемые в вектор значения, например:
Вектор можно создать также при помощи функции scan() , которая "считывает" последовательно вводимые с клавиатуры значения:
Один из недостатков создания векторов при помощи функции scan() состоит в том, что если при вводе значений с клавиатуры допущена ошибка, то придется либо начать ввод заново, либо воспользоваться специальными инструментами корректировки (например, функцией fix() ; здесь эти способы не рассматриваются).
Для создания векторов, содержащих совокупность последовательных чисел, удобна функция seq() (от "sequence" – последовательность). Так, вектор с именем S , содержащий совокупность целых чисел от 1 до 7, можно создать следующим образом:
Идентичный результат будет получен при помощи команды
В качестве дополнительного аргумента функции seq() можно задать шаг приращения чисел:
Векторы, содержащие одинаковые значения, создают при помощи функции rep() (от "repeat" – повторять). Например, для формирования текстового вектора Text , содержащего пять значений "test" , следует выполнить команду
Система R способна выполнять самые разнообразные операции над векторами. Так, несколько векторов можно объединить в один, используя уже рассмотренную выше функцию конкатенации
Для работы c определенным элементом вектора необходимо уметь отличать его от других похожих элементов. Для этого при создании вектора всем его компонентам автоматически присваиваются индексные номера, начиная с 1. Чтобы обратится к конкретному элементу необходимо указать имя вектора и индекс этого элемента в квадратных скобках:
Используя индексные номера, можно выполнять различные операции с избранными элементами разных векторов:
Индексирование является мощным инструментом, позволяющим создавать совокупности значений в соответствии с определенными критериями. Например, для вывода на экран 3-го, 4-го и 5-го значений вектора y необходимо выполнить команду
Из этого же вектора мы можем выбрать, например, только первое и четвертое значения, используя уже известную нам функцию конкатенации с() :
Похожим образом мы можем удалить первое и четвертое значения из вектора y , применив знак "минус" перед функцией конкатенации:
В качестве критерия для выбора значений может служить логическое выражение. Для примера выберем из вектора y все значения >2:
- "Равно" ==
- "Не равно" !=
- "Меньше"
- "Больше" >
- "Меньше либо равно"
- "Больше либо равно" >=
- "Логическое И" &
- "Логическое ИЛИ" |
- "Логическое НЕ" !
Для упорядочения значений вектора по возрастанию или убыванию используют функцию sort() в сочетании с аргументом decreasing = FALSE или decreasing = TRUE соответственно ("decreasing" значит «убывающий»):
Характерной особенностью R является векторизация вычислений. Векторизация представляет собой один из способов выполнения параллельных вычислений, при котором программа определенным образом модифицируется для выполнения нескольких однотипных операций одновременно. Очевидно, что такой подход потенциально может привести к значительному ускорению однотипных вычислений над большими массивами данных.
Рассмотрим простейший пример векторизованных вычислений в R. Допустим, у нас имеется вектор из 10 положительных чисел и мы хотим извлечь квадратный корень из каждого из них. Вместо написания цикла для поочередного выполнения этой операции над каждым элементом вектора, мы просто подаем весь этот вектор на функцию sqrt() , которая возвращает вектор с результатами вычислений:
Так же легко мы можем, например, поэлементно умножить исходный вектор на вектор с результатами вычисления квадратного корня:
1. Функция apply() - используется в случаях, когда необходимо применить какую-либо функцию ко всем строкам или столбцам матрицы (или массивов большей размерности):
При необходимости вычисления сумм и средних значений по строкам или столбцам матриц рекомендуется также использовать очень быстрые и специально оптимизированные для этого функции colSums() , rowSums() , colMeans и rowMeans() .
2. Функция lapply() - используется в случаях, когда необходимо применить какую-либо функцию к каждому компоненту списка и получить результат также в виде списка (буква "l" в названии lapply означает list - "список").
3. Функция sapply() - используется в случаях, когда необходимо применить какую-либо функцию к каждому компоненту списка, но результат вывести в виде вектора (буква "s" в названии sapply означает simplify - "упрощать").
В некоторых более "продвинутых" случаях sapply() может выдать результат в виде многомерного массива. Например, если применяемая нами функция возвращает векторы одинаковой длины, sapply() объединит эти векторы в матрицу (по столбцам):
Если применяемая нами функция возвращает матрицу, то sapply() преобразует каждую матрицу в вектор и объединит такие векторы в одну большую матрицу (звучит не очень понятно, но пример хорошо поясняет эту идею):
Поведение sapply() , продемонстрированное в последнем примере, можно отменить при помощи аргумента simplify = "array" - в этом случае матрицы будут объединены в один многомерный массив:
5. Функция mapply() - используется в случаях, когда необходимо поэлементно применить какую-либо функцию одновременно к нескольким объектам (например, получить сумму первых элементов векторов, затему сумму вторых элементов векторов, и т.д.). Результат возвращается в виде вектора или массива другой размерности (см. примеры для sapply() выше). Буква "m" в названии mapply означает multivariate - "многомерный" (имеется в виду одновременное выполнение вычислений над элементами нескольких объектов).
6. Функция rapply() - используется в случаях, когда необходимо применить какую-либо функцию к компонентам вложенного списка (буква "r" в названии rapply означает recursively - "рекурсивно").
В базовом пакете base есть функция read.table , которая отвечает за чтение текстовых файлов. Она имеет множество параметров, что позволяет гибко управлять процессом чтения. Эта функция возвращает data.frame.
При написании команд и функций удобно пользоваться возможность автодополнения. Для этого наберите часть команды, или имени функции или параметра и нажмите сочетание клавиш Ctrl+Пробел. В выпадающем списке можно выбрать подходящую команду.
При написании путей к папкам и файлам можно использовать либо абсолютный либо относительный путь. Например, предыдущий вызов можно оформить как
Для представления пути используются либо символы слэша (/) либо удвоенные символы обратного слэша (\). Это обусловлено тем, что обратный слэш в R это спецсимвол и добавление второго слэша его экранирует и указываает R, что следующий за ним символ надо вопринимать как обычный.
Т.е. обе эти записи пути эквивалетны: "D:/Teaching/R/introduction/md/data/sol_y1.txt" или "D:\\Teaching\\R\\introduction\\md\\data\\sol_y1.txt"
Посмотрим на данные, которые были загружены. Сделать это можно несколькими способами, вот некоторые из них
Функция read.table является не очень эффективной с точки зрения производительности. Файлы, содержащие большое число столбцов считываются очень медленно. Если попробовать прочитать файл sol_x1.txt , который содержит 4058 дескрипторов для 800 соединений, то это займет заметное время.
Можете попробовать выполнить следующий код
Для преодоления этого недостатка есть несколько вариантов, вот два из них:
1. Использовать экспериментальную функцию fread из пакета data.table .
2. Конвертировать текстовые файлы в бинарный формат и в дальнейшем работать с этими файлами.
R - язык функционального программирования
Функции производят операции над объектом и возвращают результат, при этом передаваемый объект не изменяется.
Если необходимо изменить состояние объекта, то результат функции присваивается переменной обозначающей этот объект.
Любая операция в R это функция
3.6.2 all() и any()
Функция all() выдает TRUE только когда все значения логического вектора на входе равны TRUE :
Функция any() выдает TRUE когда есть хотя бы одно значение TRUE :
Вместе с оператором ! можно получить много дополнительных вариантов. Например, есть ли хотя бы один FALSE в векторе?
Все ли значения в векторе равны FALSE ?
3.6.4 оператор %in% и match()
Часто возникает такая задача: нужно проверить вектор на равенство с хотя бы одним значением из другого вектора. Например, мы хотим вычленить всех зеленоглазых и голубоглазых. Может возникнуть идея сделать так:
Перед нами самый страшный случай: результат похож на правильный, но не правильный! Попытайтесь самостоятельно понять почему этот ответ неверный и что произошло на самом деле.
А на самом деле мы просто сравнили два вектора, один из которых короче другого, следовательно, у нас сработало правило ресайклинга.
Как мы видим, это совсем не то, что нам нужно! В данной ситуации нам подойдет сравнение с двумя значениями вместе с логическим ИЛИ.
Однако это не очень удобно, особенно если значений больше 2. Тогда на помощь приходит оператор %in% , который выполняет именно то, что нам изначально нужно: выдает для каждого значения в векторе слева, есть ли это значение среди значений вектора справа.
Основное преимущество оператора %in% в его простоте и понятности. У оператора %in% есть старший брат, более сложный и более мощный. Функция match() работает похожим образом на %in% , но при совпадении значения в левом векторе с одним из значений в правом выдает индекс соответствующего значения вместо TRUE . Если же совпадений нет, то вместо FALSE функция match() выдает NA (что можно поменять параметром nomatch = ).
Зачем это может понадобиться? Во-первых, это способ соединить два набора данных (хотя для этого есть и более подходящие инструменты), во-вторых, так можно заменить все значения кроме выбранных заменить на NA .
Формулы
Формулы - специальная форма выражения отношений между переменными в уравнении. Формулы используются при построении моделей для определения функциональной зависимости между параметрами.
Линейная комбинация (+):
Линейная комбинация с отсутствующим свободным членом (+0)
Функция идентичности I(), при этом выражение в скобках рассматривается как обычное математическое.
Формулы могут содержать математические функции
Символ точки (.) подставляет все имеющиеся переменные. Функция зависимости y от всех остальных переменных, которые будут передаваться в функцию выглядит так
Синтаксис | Модель | Пояснение |
---|---|---|
Y ~ A | \( Y = \beta_ + \beta_A \) | Уравнение регрессии с неявно заданным свободным членом |
Y ~ A + 0 | \( Y = \beta_A \) | Уравнение регрессии без свободного члена |
Y ~ A + B | \( Y = \beta_ + \beta_A + \beta_B \) | Уравнеие модели первого порядка |
Y ~ A + I(A^2) | \( Y = \beta_ + \beta_A + \beta_A^2 \) | Уравнеие модели второго порядка с одной переменной |
Y ~ A:B | \( Y = \beta_ + \beta_AB \) | Уравнение модели первого порядка, в которое входят только произведения переменных |
Y ~ A*B | \( Y = \beta_ + \beta_A + \beta_B + \beta_AB \) | Полное уравнение модели первого порядка, аналогично Y ~ A + B + A:B |
Y ~ (A + B + C)^2 | \( Y = \beta_ + \beta_A + \beta_B + \beta_C + \beta_AB + \beta_AC + \beta_BC \) | Модель первого порядка включающая все произведения до порядка n, аналогично Y ~ A*B*C - A:B:C |
Задания
- Создать функцию, которая будет считывать текстовый файл, содержащий дескрипторы, с использованием функции fread, и возвращать data.frame.
- Прочитать с использованием функции из п.1 и сохранить в бинарном формате файл sol_x2.txt .
- Прочитать файл sol_y1.txt , конвертировать загруженные данные в именованный вектор и сохранить его в бинарном формате. Создать для этого соответствующую функцию.
- Повторить операции п.3 для файла sol_y2.txt
Пакеты (библиотеки функций) в R
Установка новых пакетов возможна через консоль R командой install.packages либо через графический интерфейс.
Ресурсы в сети интернет для знакомства и освоения R
-
- двухминутные видео в стиле “how to …” - QuickR, описываются основные возможности языка
Основные достоинства:
3.6.1 mean() и sum() для подсчета пропорций и количества TRUE
Уже знакомая нам функция sum() позволяет посчитать количество TRUE в логическом векторе. Например, можно удобно посчитать сколько раз значение "blue" встречается в векторе eyes :
Функцию mean() можно использовать для подсчета пропорций TRUE в логическом векторе.
Умножив на 100, мы получим долю выраженную в процентах:
3.7 NA - пропущенные значения
В реальных данных у нас часто чего-то не хватает. Например, из-за технической ошибки или невнимательности не получилось записать какое-то измерение. Для обозначения пропущенных значений в R есть специальное значение NA (расшифровывается как Not Available - недоступное значение). NA – это не строка "NA" , не 0 , не пустая строка "" и не FALSE . NA – это NA . Большинство операций с векторами, содержащими NA будут выдавать NA :
Заметьте, даже сравнение NA c NA выдает NA . Это может прозвучать абсурдно: ну как же так, и то NA , и другое NA – это же одно и то же, они должны быть равны! Не совсем: NA – это отсутствие информации об объекте, неопределенность, неизвестная нам величина. Если мы не знаем двух значений (т.е. имеем два NA ), то это еще не значит, что они равны.
Иногда наличие NA в данных очень бесит:
Получается, что наличие NA “заражает” неопределенностью все последующие действия. Что же делать?
Наверное, надо сравнить вектор с NA и исключить этих пакостников. Давайте попробуем:
Ах да, мы ведь только что узнали, что даже сравнение NA c NA приводит к NA ! Сначала это может показаться нелогичным: ведь с обоих сторон NA , почему же тогда результат их сравнения – это тоже NA , а не TRUE ?
Дело в том, что сравнивая две неопределенности, вы не можете установить между ними знак равенства. Представим себе двух супергероев: Бэтмена и Спайдермена. Допустим, мы не знаем их рост:
Одинаковый ли у них рост?
Мы не знаем! Возможно, да, возможно, и нет. Поэтому у нас здесь остается неопределенность.
Так как же избавиться от NA в данных? Самый простой способ – это функция is.na() :
Результат выполнения is.na(n) выдает FALSE на тех позициях, где у нас числа (или другие значения), и TRUE там, где у нас NA . Чтобы вычленить из вектора n все значения кроме NA нам нужно, чтобы было наоборот: TRUE , если это не NA , FALSE , если это NA . Здесь нам понадобится логический оператор НЕ ! (мы его уже встречали – см. @ref(data_types)), который инвертирует логические значения:
Ура, мы можем считать среднее без NA !
Теперь Вы понимаете, зачем нужно отрицание ( ! )
Вообще, есть еще один из способов посчитать среднее, если есть NA . Для этого надо залезть в хэлп по функции mean():
В хэлпе мы найдем параметр na.rm = , который по умолчанию FALSE . Вы знаете, что нужно делать!
NA может появляться в векторах разных типов. На самом деле, NA - это специальное значение в логических векторах, тогда как в векторах других типов NA появляется как NA_integer_ , NA_real_ , NA_complex_ или NA_character_ , но R обычно сам все переводит в нужный формат и показывает как просто NA . Таким образом, NA в векторах разных типов – это разные NA , хотя на практике эта деталь обычно несущественна.
Кроме NA есть еще NaN – это разные вещи. NaN расшифровывается как Not a Number и получается в результате таких операций как 0 / 0 . Тем не менее, функция is.na() выдает TRUE на NaN , а вот функция is.nan() выдает TRUE на NaN и FALSE на NA :
Другие способы ввода-вывода
Помимо текстовых и бинарных данных R может читать данные из различных баз данных, а также файлов MS Excel, для чего используется подключение дополнительных пакетов. В частности пакет xlsx позволяет работать с данными, сохраненными в одноименном формате.
Векторы и типы данных
Вектор может содержать данные только одного типа.
Какой класс будет иметь вектор?
Имена элементов векторов, матриц, data.frames, списков и т.д.
Все объекты поддерживают присвоение имен содержащимся в них элементам.
Обычный и именованный вектор
Другой способ создания именованного вектора
Аналогично векторам матрицы и data.frames имеют такие свойства как rownames и colnames , которые позволяют изменять имена колонок и строк.
Удаление имен осуществляется присвоением специального типа NULL
Или для векторов
При этом к элементам уже нельзя будет обращаться по имени, а только по индексу.
Особенности векторизации
Если два вектора имеют различное количество элементов, то вектор меньшей длины будет повторяться столько раз чтобы соответствовать длине большего вектора.
Если длина большего вектора кратна длине меньшего вектора, такая операция будет произведена неявно, без уведомления пользоателя.
В случае если длины комбинируемых векторов различны, то будет произведено циклическое совмещение элементов меньшего вектора относительно элементов большего вектора и будет сгенерировано предупреждение.
Очистка рабочей области от загруженных и используемых переменных
Перед загрузкой данных, только что сохраненных в файл sol_x1.RData , сперва очистим рабочую область (удалим все загруженные переменные). Сделать это можно либо функцией rm . Приведенный вызов удалит все загруженные объекты.
Либо кликнув по кнопке Clear .
Объекты также можно удалять выборочно, указывая их названия.
Иногда при длительной работе и загрузке удалении больших объемом данных бывает полезно вызывать сборщик мусора, который принудительно очищает память от уже неиспользуемых данных.
3.6.3 Превращение логических значений в индексы: which()
Как вы уже знаете, и логические векторы, и числовые вектора с индексами могут использоваться для индексирования векторов. Иногда может понадобиться превратить логический вектор в вектор индексов. Для этого есть функция which()
Data.frames
Data.frame - двумерный набор данных (таблица). В отличие от матриц, колонки в data.frame могут содержать данные различного типа. Однако тип данных внутри каждой колонки может быть только один. Это объясняется тем, что data.frame это список векторов (колонок). Поэтому к data.frame могут быть применены различные функции применимые к спискам.
Справка в R - прекрасный источник информации
Полное описание функций и возвращаемых ими значений с примерами можно найти в справке.
Дополнительно можно вызывать справку клавишей F1, когда курсор стоит на имени функции в тексте скрипта или в консоли.
Если необходимо найти какую-либо функцию по ее имени или части имени, то удобно пользоваться функциями из пакета sos .
Установите пакет sos и выполните следующие команды:
Чтение текстовых файлов с использованием функции fread (пакет data.table)
Для просмотра загруженной таблицы в RStudio можно использовать команду
или кликнуть по имени переменной x1 в списке
Результат в обоих случаях будет одинаковым
Проверим объект какого класса получился при загрузке таблицы с использованием функции fread
Приведем объект x1 к типу data.frame
Отметим, что первая колонка содержит названия соединений. Переместим значения этой колонки в поле rownames
Проверим, что получилось.
Индексация векторов, матриц, data.frames и т.д.
Индексация - исключительно эффективный и мощный инструмент для работы с данными.
Индексы могут быть:
- числовыми
- логическими
- текстовыми
Для индексирования используется три типа выражений:
- [ - выбирает элементы вектора/списка/массива и т.д.
- $ - выбирает один элемент из data.frame/списка по его имени.
- [[ - выбирает элементы из вектора/списка/массива и т.д, но отбрасывает имена, если они есть.
Способы создания векторов
Текстовые индексы
Текстовые индексы работают аналогично числовым
Выбор блока данных
Для текстовых индексов отсутствует возможность использования отрицательных значений индексов, т.е. чтобы удалить строку/колонку необходимо сформировать вектов с именами строк/колонок, которые необходимо оставить.
Манипуляции с данными
Матрицы
Матрица - двумерный набор элементов одного типа (таблица).
3.5 Индексирование векторов
Итак, мы подошли к одному из самых сложных моментов. И одному из основных. От того, как хорошо вы научись с этим работать, зависит весь ваш дальнейший успех на R-поприще!
Речь пойдет об индексировании векторов. Задача, которую Вам придется решать каждые пять минут работы в R – как выбрать из вектора (или же списка, матрицы и датафрейма) какую-то его часть. Для этого используются квадратные скобочки [] (не круглые – они для функций!).
Самое простое – индексировать по номеру индекса, т.е. порядку значения в векторе.
Если вы знакомы с другими языками программирования (не MATLAB, там все так же) и уже научились думать, что индексация с 0 – это очень удобно и очень правильно (ну или просто свыклись с этим), то в R вам придется переучиться обратно. Здесь первый индекс – это 1, а последний равен длине вектора – ее можно узнать с помощью функции length() . С обоих сторон индексы берутся включительно.
С помощью индексирования можно не только вытаскивать имеющиеся значения в векторе, но и присваивать им новые:
Конечно, можно использовать целые векторы для индексирования:
Индексирование с минусом выдаст вам все значения вектора кроме выбранных:
Минус здесь “выключает” выбранные значения из вектора, а не означает отсчет с конца как в Python.
Более того, можно использовать логический вектор для индексирования. В этом случае нужен логический вектор такой же длины:
Логический вектор работает здесь как фильтр: пропускает только те значения, где на соответствующей позиции в логическом векторе для индексирования содержится TRUE , и не пропускает те значения, где на соответствующей позиции в логическом векторе для индексирования содержится FALSE .
Ну а если эти два вектора (исходный вектор и логический вектор индексов) не равны по длине, то тут будет снова работать правило ресайклинга!
Есть еще один способ индексирования векторов, но он несколько более редкий: индексирование по имени. Дело в том, что для значений векторов можно (но не обязательно) присваивать имена:
А еще можно “вытаскивать” имена из вектора с помощью функции names() и присваивать таким образом новые имена.
letters – это “зашитая” в R константа – вектор букв от a до z. Иногда это очень удобно! Кроме того, есть константа LETTERS – то же самое, но заглавными буквами. А еще в R есть названия месяцев на английском и числовая константа pi .
Вернемся к нашему вектору n и посчитаем его среднее с помощью функции mean() :
А как вытащить все значения, которые больше среднего?
Сначала получим логический вектор – какие значения больше среднего:
А теперь используем его для индексирования вектора n :
Можно все это сделать в одну строчку:
Предыдущая строчка отражает то, что мы будем постоянно делать в R: вычленять (subset) из данных отдельные куски на основании разных условий.
Списки
Списки содержат упорядоченный набор элементов, каждый из которых может являться вектором, матрицей, массивом, списком и т.д.
Как правило в виде списков удобно хранить либо какие-то однотипные данные соответствующие разным итерациям, например, множество моделей. Или хранить разнородные данные, которые имеют смысловую связь, например, различные статистические характеристики отдельной модели.
Массивы
Массив - многомерный набор элементов одного типа.
Другие функции для работы с текстовыми файлами
Существуют различные дополнительные функции для чтения и записи текстовых файлов с определенным стилем форматирования. Подробную информацию о них можно найти в справочной системе R.
Типы данных
Типы данных в порядке увеличения приоритета:
- Логические (logical)
- Целочисленные (integer)
- Вещественные числа (numeric)
- Комлексные числа (complex)
- Текстовые (character)
- Списки (list)
Индексы data.frames
Выборка данных из data.frames была описана выше и ничем не отличается от других структур данных (вектров, матриц и т.д.). Единственная особенность вытекает из того, что data.frame это список векторов (колонок), то для выбора одной колонки по имени можно использовать конструкцию аналогичную для списков
Такое выражение всегда возвращает вектор.
sapply & lapply
Помимо функции apply есть еще функции sapply и lapply , отличие которых состоит в том, что на вход они могут принимать вектор или список и возвращают вектор/матрицу ( sapply ) или список ( lapply ).
Вспомним, что data.frame является списком векторов-столбцов. Тогда предыдущий пример можно переписать как
Использование lapply вернет уже список
Возведем значения каждой колонки в степень, соответствующую номеру этой колонки - результатом будет новая матрица.
Обратите внимание, что в этом случае в качестве первого параметра передается не data.frame, а вектор индексов колонок, по которым происходит итерация.
Функция seq_along возвращает вектор индексов с первого до последнего элемента вектора/списка.
Использование функций семейства apply позволяет делать код более простым и читабельным.
Например, надо определить класс каждой колонки в data.frame
Как видим в отличие от apply фугкция sapply не производит неявной конвертации data.frame в матрицу и типы данных в колонках остаются неизменными.
Проверить совпадает ли порядок следования имен соединений в x и y .
Создать функцию, которая читала бы формат файлов дескрипторов dat/cds. Подсказка: можно использовать функцию readBin .
Создать функцию, которая будет объединять два набора фрагментных дескрипторов.
Простейшие функции для работы с графикой
Базовый пакет R имеет в своем составе много функций для визуализации данных. Остановимся только на некоторых, которые могут быть полезны при первом знакомстве с данными.
Функция hist - строит гистограмму распределения какой-либо величины. Может помочь составить первое впечатление о нормальности распределения данных. Применим эту функцию к свойству y .
Если стандартное отображение не устраивает, то можно его изменить, например, сделав интервалы меньше.
Во всех случаях очевидно, что распределение данных отличается от нормального. Чтобы проверить это можно воспользоваться следующими двумя функциями, которые строят график зависимости между квантилями нормального распределения и квантилями исследуемого набора значений y . Чем сильнее отличие распределения от прямой, тем больше отклонение распределения от нормального.
Для более подробного знакомства с возможностями базовых функций графического отображения рекомендую ознакомиться со следующими источниками:
Особенности индексов
Если идет обращение к несуществующему индексу, то вернется специальное значение NA
NA специальное значение указывающее, что значение не определено (Not Available).
Если присваивать значение элементу с несуществующим индексом, то этот элемент будет создан.
Другой пример в результате которого создаются NA
Для проверки является ли значение NA используется специальная функция
Все то же самое справедливо и для текстовых индексов
Аналогично для того, чтобы добавить новый элемент в список (колонку/строку в data.frame) используется новое имя или числовой индекс.
Пример с data.frame. Создадим data.frame и добавим новую переменную, которая будет равняться значению первой колонки во второй степени.
Пример со списком. Создадим именованый список из двух элементов и добавим к нему третий элемент.
Если у вас не было линейной алгебры (или у вас с ней было все плохо), то просто запомните, что вектор (atomic vector или просто atomic) – это набор (столбик) чисел в определенном порядке.
Если вы привыкли из школьного курса физики считать вектора стрелочками, то не спешите возмущаться и паниковать. Представьте стрелочки как точки из нуля координат до какой-то точки на координатной плоскости, например, :
Вот последние два числа и будем считать вектором. Попытайтесь теперь мысленно стереть координатную плоскость и выбросить стрелочки из головы, оставив только последовательность чисел :
На самом деле, мы уже работали с векторами в R, но, возможно, вы об этом даже не догадывались. Дело в том, что в R нет как таковых скалярных (т.е. одиночных) значений, есть вектора длиной 1. Такие дела!
Чтобы создать вектор из нескольких значений, нужно воспользоваться функцией c() :
Одна из самых мерзких и раздражающих причин ошибок в коде – это использование с из кириллицы вместо c из латиницы. Видите разницу? И я не вижу. А R видит. И об этом сообщает:
Для создания числовых векторов есть удобный оператор : .
Этот оператор создает вектор от первого числа до второго с шагом 1. Вы не представляете, как часто эта штука нам пригодится… Если же нужно сделать вектор с другим шагом, то есть функция seq() :
Кроме того, можно задавать не шаг, а длину вектора. Тогда функция seq() сама посчитает шаг:
Другая функция – rep() – позволяет создавать вектора с повторяющимися значениями. Первый аргумент – значение, которое нужно повторять, а второй аргумент – сколько раз повторять.
И первый, и второй аргумент могут быть векторами!
Еще можно объединять вектора (что мы, по сути, и делали, просто с векторами длиной 1):
Очень многие функции в R работают именно с векторами. Например, функции sum() (считает сумму значений вектора) и mean() (считает среднее арифметическое всех значений в векторе):
Создание пользовательских функций
Если часто используется одна и та же последовательность команд, то целесообразнее создать функцию, которая бы их выполняла автоматически. Это существенно упрощает текст программы, делает его более модульным, читабельным и простым для внесения изменений.
Создадим простейшую функцию рассчитывающую разность двух векторов
Важно отметить, что при передаче параметров в функции, можно не использовать названия параметров только в том случае, если соблюдается порядок следования параметров. В противном случае необходимо указывать названия параметров.
Продемонстрируем области видимости переменных на примере собственных функций.
Создадим вектор x и вызовем созданную нами функцию. Результат функции это измененный вектор x , однако сам вектор x не изменился.
Таким образом все что передается в функцию попадает в локальную области видимости только этой функции как и все изменения.
Реализуем собственную функцию загрузки бинарных файлов
Ключевое слово return в завершении функции писать не обязательно. По умолчанию функция возвращает результат последней операции.
Для того чтобы сохранить созданную функцию текст функции посещается в (новый) файл R script, который можно создать вызвав меню File - New file - R script или нажав комбинацию Ctrl + Shift + N. После чего пишется текст функции и файл сохраняется с расширением “.R”.
Для загрузки функции из файла используется функция source . Но предварительно очистим содержимое рабочей области.
После чего для загрузки бинарного файла достаточно вызвать
Ранее для чтения текстового файла с дескрипторами мы использовали следующий вызов.
Если часто использовать ее для чтения файлов, то удобнее создать собственную функцию. Создадим два варианта.
Первый вариант
Троеточие используется для передачи дополнительных параметров внутрь функций.
Тогда для загрузки файлов с дескрипторами достаточно вызвать
Какие достоинства и недостатки у каждого из вариантов?
Установка и запуск дополнительных пакетов
Удобный способ уставновки дополнительный пакетов через графический интерфейс RStudio. Важно отметить галочкой автоматическую уставновку зависимостей.
Установка пакета data.table :
Загрузка пакета в рабочую область осуществляется через функции
Использовать функции из установленных пакетов, без их загрузки в рабочую область можно используя следующий вызов:
Если необходимо использовать много различных функций, содержащихся в пакете, или происходит частое обращение к ним в ходе работы, то удобнее использовать первый вариант - загрузка всего пакета в рабочую область.
В случае же, если функция вызывается редко или существует конфликт имен (разные функции в разных пакетах имеют одинаковое название), то предпочтительным становится второй вариант вызова функций, при котором явно указывается какая функция и из какого пакета должна использоваться.
Читайте также: