4 Перше знайомство з використанням R
Щоб почати роботу з R, його слід або встановити на свій комп’ютер, або скористуватися онлайн-сервісом (наприклад, таким). На погляд авторів курсу, перший шлях є кращим, але (щоб далі до цього не вертатися) скажемо кілька слів про інший, не рекомендований нами шлях.
Рис. 4.4.1 Сервіс Posit cloud пропонує хмарний доступ до R та RStudio. Ви можете зареєструватися тут та обрати вільний доступ (що має суттєві обмеження). На жаль, таке рішення є незручним
Набагато краще рішення — інсталювати R та RStudio на своєму комп’ютері. Для цього слід завантажити інсталятори цих програм та по черзі запустити їх на локальному комп’ютері. Зверніть увагу: встановлювати RStudio слід обов’язково після R, а не до нього. Спочатку ви інсталюєте R, потім — RStudio, а далі ви будете запускати саме RStudio і працювати в ньому; ця оболонка сама звернеться до своєї основи.
Інсталятор R (для вашої операційної системи) ви маєте завантажити тут.
Інсталятор RStudio (для вашої операційної системи) ви маєте завантажити тут. RStudio розраховано на 64-бітні операційні системи, але у разі, якщо у вас — стара 32-бітна система, ви можете використати відповідний варіант з-поміж старих версій.
Після того, як інсталяція відбулася, викликайте RStudio і починайте працювати!
Ви викликали RStudio. Що ви бачите?
Рис. 4.1.2 Вікно RStudio. У правій частині екрана — автоматично згенеровані вступні пояснення
Ліва частина екрана RStudio зайнята консоллю — «пристроєм» для вводу та виводу інформації. Після знаку > стоїть курсор. Наберіть там 2*2 і натисніть Enter. Ви бачите, що можете використовувати R через консоль, і це стосується не лише використання у якості калькулятора.
Втім, команди ми будемо давати переважно не в консолі, а у редакторі скриптів — вікні, що призначене для створення в ньому послідовності команд. У такому стані, як на рис. 4.1.1, редактор скриптів ще не відкритий. Викличте меню RStudio і запропонуйте створення нового файлу. Ви побачите додаткове меню, де треба буде обрати тип такого файлу.
Рис. 4.1.3 Так відкриваються нові вікна для скриптів та документів RMarkdown. Ми почнемо нашу роботу зі скриптів
Ми будемо працювати з двома типами файлів. Перш за все, це — скрипти, послідовності команд R. Такі файли мають розширення *.R (розширення файлу — це позначення його типу, яке визначає, які програми будуть з ним працювати; в операційній системі Windows розширення файлу може бути невидимим).
Пізніше буде корисно навчитися створювати файли RMarkdown. Ця вшита у R мова розмітки текстів та програмного коду дозволяє створювати такі сторінки, як ця: ті, що поєднують текстові пояснення, фрагменти коду та результати виконання цього коду. Файли RMarkdown мають розширення *.Rmd.
4.2 Перші кроки: вікна в RStudio та прості приклади команд в R
Відкриємо в RStudio скрипт (оберемо у такому випадку, що показаний на рис. 4.1.2, опцію R Script). Над консоллю у правій частині екрана з’явиться вікно редактору скриптів.
Напишемо і у цьому вікні найпростіший арифметичний вираз.
2*2
## [1] 4
В файлі RMarkdown, де створюється даний текст, введена (в особливу вставку для програмних кодів, що називається чанком) лише команда, що була написана у вікні скриптів. Ви читаєте текст, що згенерував RMarkdown; до команди R у чанку він додав результат її виконання — те, що RStudio виводить у консолі.
Додамо у вікні скриптів ще кілька команд.
vect <- c(1:20, 100)
vect
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
## [20] 20 100
?c
Перед тим, як повторити команду, яку вона виконувала, консоль виводить символ >. Перед тим, як вивести результат, RStudio у квадратних дужках нумерує його елементи. Якщо вивід складається з одного числа, перед ним буде стояти [1]; якщо елементів більше, на початку кожного рядку буде позначатися номер першого елементу кожного рядку (це можна побачити на рисунку). Після кожної з команд ви бачите результат її виконання. Не відбилося у текстовому вигляді у документі, що згенерував RMarkdown, лише виконання команди ?c, втім, його можна побачити на рисунку (скрину екрана RStudio).
Рис. 4.2.1 Виділена у вікні скриптів послідовність команд була виконана кнопкою Run. Наслідки її виконання ми бачимо в усіх інших вікнах RStudio
Розглянемо рис. 4.2.1 детальніше. У вікні редактора скриптів (справа нагорі) ми бачимо команди, які були виконані.
Часто корисно виконувати скрипт покроково. Для виконання поточного рядку коду можна скористатися поєднанням клавіш Ctrl+Enter або кнопкою Run, що розташована у верхній частині вікна редактора. Код буде виконаний, і курсор переміститься на наступний рядок. Для виконання відразу декількох рядків (або частини рядка) треба виділити необхідний фрагмент і натиснути клавіші Ctrl+Enter або Run. Щоб виконати всі рядки скрипту, слід або виділити його цілком (Ctrl+A) і натиснути Run, або натиснути кнопку Sourse.
У вікні консолі (справа унизу) ми бачимо відповідь R на подані команди. Поруч з вікном консолі є й «роздільники» (як у паперовій теці), що дозволяють відкрити інші вікна, які зараз не є актуальними для нашого обговорення.
Зліва нагорі ми бачимо ще кілька роздільників; відкрито вікно середовища (Environment), де показані об’єкти, якими оперує R.
Зліва внизу — ще кілька «роздільників»; відкрито вікно допомоги (Help). Якби наші команди, введені у вікні скриптів, створювали б якусь діаграму, у нас було б відкрито вікно діаграм (Plots).
Ctrl+1 — переміщує курсор у вікно редактора скриптів; Ctrl+2 — переміщує курсор в консоль; Ctrl+L — очищає вікно консолі від тексту; Esc — перериває обчислення.
Панель історія (History) дозволяє переглянути історію команд, виділити деякі з них і відправити в консоль (To Console) або в редактор скриптів (To Source).
Проаналізуємо, що саме ми бачимо в цих вікнах. У другому рядку у редакторі скриптів ми ввели команду vect <- c(1:20, 100). Цією командою ми створили об’єкт, який має назву vect — цією назвою ми підкреслили, що цей об’єкт є вектором, базовим типом об’єктів для R.
Загалом, логіка роботи з R є такою. Ми створюємо певні об’єкти відповідними командами, а потім перетворюємо ці об’єкти та здійснюємо з ними різноманітні дії за допомогою наступних команд. Саме для цього нам потрібні скрипти — послідовності команд. Для того, щоб не заплутатися з тим, з якими об’єктами ми працюємо, дуже корисним є вікно Environment.
Створення або перебудова об’єктів відбувається з використанням символу привласнення: <- (спрацює і просто знак =, але його використання у такому випадку є в R «нестильним»). У випадку команди vect <- c(1:20, 100) відбувається створення об’єкта vect, якому привласнюється результат роботи функції c(). Вказана у попередньому реченні команда створює вектор vect; він з’являється у вікні Environment. А щоб «побачити» цей об’єкт в консолі, його слід викликати — просто назвати його ім’я.
Як узнати, що саме робить функція c()? Ввести у редакторі скриптів або у консолі команду ?c або help(c) (результат буде тій самий). Ця команда викличе у вікні Help детальний опис вказаної функції (звісно, англійською мовою). Функція c(), здається, єдина, назва якої складається з однієї літери. Вона об’єднує (combine або ж concatenate) певні об’єкти у вектор (або ж у список, list).
Зверніть увагу, як ми назвали цю функцію: c(). Крім її імені c, ми бачимо дужки, у яких мають бути вказані її аргументи. Аргументи функції c() — це ті об’єкти або величини (або інші функції!), які мають бути поєднані у створюваному об’єкті. Ці аргументи перелічуються через кому у тому порядку, у якому вони будуть поєднані.
Звісно, є функції, що використовуються без дужок, як-от арифметичні операції. Але це виключення. Деякі функції навіть не мають аргументів, але все одно застосовуються з дужками. Наприклад, команда: ls() виведе у консоль перелік об’єктів, які зараз активні у оточенні, Environment, програми. У дужки у такому випадку не треба нічого ставити, вони просто демонструють, що ми маємо справу з функцією. Сама по собі ця програма не є критично необхідною, адже на перелік об’єктів можна просто подивитися у вікні Environment. Втім, ця команда може стати частиною іншої, більш корисної команди. Команда rm(list = ls()) видаляє усе, що є в Environment. Це може бути дуже корисним, коли після розв’язання однієї задачі користувач R переходить до іншої, або в інших ситуаціях, коли об’єкти від попередніх розрахунків можуть заважати наступним.
Створюючи об’єкт vect ми поєднали результат роботи функції і окрему величину. Річ у тому, що символ : працює як функція: коли він розташований між двома числами, він вибудовує послідовність чисел між ними, що відрізняються одне від одного на одиницю.
Дослідимо, як працює ця команда.
6:12
## [1] 6 7 8 9 10 11 12
Вибудувано послідовність натуральних чисел. А що буде, якщо спочатку буде розташовано більше число?
12:6
## [1] 12 11 10 9 8 7 6
Працює. Початок та кінець ряду визначають, висхідний він або низхідний. А чи можна використовувати від’ємні числа?
-1:5
## [1] -1 0 1 2 3 4 5
Можна. А чи можна використовувати нецілі числа? Перед тим, як це перевірити, зазначимо важливу деталь. В різних традиціях використовують різні символи для десяткових роздільників. На Заході частіше десятковим роздільником є крапка: 3/2=1.5. У кириличній традиції у цій ролі зазвичай використовують кому: 3/2=1,5. У R ніякого вибору нема: десятковий роздільник — кома. Саме тому, якщо у такому разі використати команду 1,5:3, замість результату ви отримаєте повідомлення Error: unexpected ‘,’ in “1,”. Для R кома має розділяти різні елементи там, де це передбачено правилами!
1.5:5.3
## [1] 1.5 2.5 3.5 4.5
Ми бачимо, що перше з чисел задає особливості ряду, а останнє визначає, скільки елементів ряду в ньому вміститься.
А якщо відстань між початком ряду та його кінцем менша за одиницю?
1.5:2.3
## [1] 1.5
У такому разі ряд складатиметься з одного елемента.
А чи можна використовувати у команді арифметичні вирази? До речі, символ ^ позначає піднесення в ступінь.
2^3:(10+1)
## [1] 8 9 10 11
Таким чином, команда vect <- c(1:20, 100) мала вибудувати послідовність натуральних чисел від 1 до 20, доєднати до них значення 100 та створити об’єкт (вектор) з назвою vect. Саме це ми і бачимо!
Додамо ще одне важливе зауваження. R вимагає чіткості та акуратності! Ви розумієте, чим відрізняються команди vect <- c(1:20, 100) та vect <- с(1:20, 100)? Скопіюйте їх та спробуйте виконати в R! Одна з них спрацює, а інша викличе повідомлення Error in с(1:20, 100) : could not find function “с”. Як ви думаєте, чому? А чому такі складнощі найчастіше виникають саме з функцією c?
У людини, яка починає працювати з R, з великою ймовірністю виникає типове питання. Як запам’ятати усі ці команди? Коли ви просунетеся у роботі з цим інструментом далі, ви впевнитеся, що ситуація зовсім не така жахлива, як може здаватися на початку. Найпростіші команди ви швидко запам’ятаєте, адже вам доведеться достатньо часто їх використовувати. З більш рідкісними або більш «накрученими» командами дещо складніше, але у цілому зовсім не трагічно. Важливо, щоб ви або пам’ятали, що якусь проблему можна розв’язати за допомогою якоїсь функції, або хоча б мали на це надію. Далі вам необхідно знайти зразок, зрозуміти, як він працює та переробити його під ваші власні потреби. Спочатку це здається складним, але кожного разу відбувається легше та легше. З часом у вас зберуться написані вами скрипти та їх чернетки, де буде зібрана колекція команд, що потрібні для розв’язання ваших задач. Чим далі ви просуватиметеся в опануванні R, тим легше вам буде робити наступні кроки.
4.3 Нашвидкуруч: приклад простих розрахунків з уведеними просто в R даними
У більшості випадків робота з R починається з того, що в нього завантажуються дані з якогось джерела (найчастіше — з електронних таблиць), але іноді цілком корисним може бути аналіз даних, уведених просто в R. Найчастіше це має сенс у разі, коли аналізуються відносно невеликі за обсягом дані. Наприклад, відносно невеликі за обсягом дані потрібні для використання χ2-тесту (chi-squared test, читається «хі-квадрат»), або тесту узгодженості Пірсона. Цей тест використовується для порівняння двох розподілів. Його зручно використовувати у разі, коли мова йде про розподіли по меристичним, ранговим або якісним (атрибутивним) ознакам (детальніше — див. пункт 1.6). У разі порівняння розподілів метричних ознак χ2-тест використовують, якщо порівнювані значення розбиті по певній кількості інтервалів, як у гістограмі.
Використаємо для прикладу дані, що були отримані студентами II курсу на навчально-польовій практиці на біологічній станції в Гайдарах). Дві студентки встановили склад вибірки з 230 зелених жаб, серед яких більшість складали самці. Студентки визначали, належать ці жаби до батьківського виду гібридогенного комплексу зелених жаб, Pelophylax ridibundus (позначення RR), чи до міжвидових геміклональних гібридів, Pelophylax esculentus, серед яких вирізняли диплоїдів (позначення 2n) та триплоїдів (3n). Ці три категорії жаб у даному контексті можна називати просто «формами».
Фактично, результати цього підрахунку можна виразити шістьма числами: чисельністю трьох зареєстрованих форм жаб серед самиць та самців. Ці дані нескладно напряму ввести у R.
Створимо два вектори: Forms (де перелічимо три форми зелених жаб, яких вирізняли у дослідженні) та Sexes (де перелічимо статі, які порівнювалися). Далі створимо матрицю Koryakov, в якій рядки відповідатимуть формам жаб, а стовпці — статям. Зрозуміло, що ця матриця матиме 6 комірок. Перелічимо зареєстровані кількості різних категорій жаб прямо у команді, якою створимо матрицю; врахуємо, що матриця заповнюється по стовпцях (спочатку перший стовпчик від першого рядка до останнього, потім — другий…).
Forms <- c( "RR", "2n", "3n")
Sexes <- c("Females", "Males")
Koryakov <- matrix(c(3, 10, 1, 5, 136, 9), nrow = length(Forms), ncol = length(Sexes), dimnames = list(Forms, Sexes))
Koryakov
## Females Males
## RR 3 5
## 2n 10 136
## 3n 1 9
Чи відрізняється розподіл за формами жаб серед самиць та самців? Таке питання має важливий сенс — залежно від відповіді на нього, можна припустити, яку статеву хромосому, жіночу чи чоловічу несе геном відсутнього у басейні Сіверського Донця батьківського виду жаб, Pelophylax lessonae. В кожній категорії зареєстрована кількість самиць була меншою; може, зареєстровані відмінності розподілу статей за формами є просто наслідком випадковості?
Сформулюємо нульову та альтернативну гіпотези.
H0 — самиці і самці жаб в досліджуваній вибірці мають однаковий розподіл за формами, що позначені RR, 2n та 3n; зареєстровані відмінності у розподілах для двох статей є наслідком випадковості при формуванні вибірки.
H1 — самиці і самці жаб в досліджуваній вибірці відрізняються за розподілами за формами, що позначені RR, 2n та 3n.
Оберемо, яку саме гіпотезу ми приймемо, з використанням тесту χ2.
chisq.test(Koryakov)
## Warning in chisq.test(Koryakov): Chi-squared approximation may be incorrect
##
## Pearson's Chi-squared test
##
## data: Koryakov
## X-squared = 9.155, df = 2, p-value = 0.01028
У цьому дослідженні, яке є пошуковим, ми приймаємо, що α, критичний рівень значущості, тобто ймовірність здійснити статистичну помилку першого роду та помилково прийняти альтернативну гіпотезу, коли вірною є нульова, дорівнює 0.05 (детальніше — у пункті 1.5). Ми отримали, що p-value = 0.0102899. Таким чином, встановлені з використанням χ2-тесту відмінності між розподілами самиць та самців зелених жаб за формами є значущими.
Втім, у використанні тесту χ2 у такому випадку є важливий недолік. Його використання є коректним, якщо очікуване значення у кожній комірці перевищує 5. Досліджена вибірка є недостатньо чисельною. У такому разі можна використовувати точний тест Фішера («Fisher’s exact test»).
fisher.test(Koryakov)
##
## Fisher's Exact Test for Count Data
##
## data: Koryakov
## p-value = 0.02096
## alternative hypothesis: two.sided
Ми бачимо, що відмінності між розподілами лишилися значущими, хоча і не настільки, як у попередньому випадку: p-value = 0.02096.
У даному пункті ми не будемо обговорювати деталі використання тесту χ2 та точного тесту Фішера, адже тут ми просто обговорюємо особливості використання R у статистичних підрахунках. Так чи інакше, ми навели приклад аналізу даних, введених прямо у скрипт R.
4.4 До початку дослідження: визначення робочої директорії
Ми хочемо розглянути простий випадок використання R. Втім навіть у такому простому випадку бажано розглянути дії, які дуже часто доводиться виконувати на самому початку роботи. Ці дії слід обговорити дещо детальніше, ніж це необхідно для прикладу, що розглядається.
Під час певної сесії R він працює з певною директорією, текою на диску. Саме в тій теці він шукає файли, які відкриває (якщо йому не вказано конкретний шлях до іншої теки), саме в ній він зберігає створювані та службові файли. Якщо шлях до робочої теки не вказаний, R працює з кореневою директорію; це з багатьох поглядів є невдалим рішенням. Зручно, коли кожен окремий аналіз, що проводиться з використанням R, пов’язаний з окремою директорією. У такому разі слід створити у зручному місці директорію, де буде знаходитися файл з первинними даними для аналізу (чи, навпаки, вказати для R як робочу саме ту директорію, де знаходяться первинні дані).
Щоб вказати робочу директорію засобами RStudio, слід пройти наступним шляхом: Session / Set Working Directory / Choose Directory. Крім того, можна просто увести команду setwd(“PATH”) (у такому випадку “PATH” — це адреса потрібної теки, записана відповідно до правил операційної системи). Адресу директорії треба вказувати повністю, починаючи з фізичного або логічного диска у Windows або з материнської директорії у Linux.
Як узнати цю адресу? Спитати у R!
Рис. 4.4.1 Якщо ми змінимо робочу директорію засобами RStudio, у консолі з’явиться її адреса
Після того, як обрано нову робочу директорію, RStudio повідомить, яку саме команду воно виконало. Цю команду можна скопіювати і вставити у скрипт; у такому разі, при виконанні послідовності команд, що пов’язана з певним робочим простором, R буде відразу спрямовуватися у потрібне місце.
4.5 До початку дослідження: читання файлів .csv (і використання «ґраток»)
У типовому випадку R працює з первинними даними, які, найчастіше за все, збираються у якомусь іншому програмному забезпеченні. Далі їх треба перенести у R. Зазвичай, типовим «шлюзом» для перенесення даних між різними програмами є файли формату .csv, Comma-Separated Values. Фактично, це звичайний текстовий файл, де дані таблиці представлені у вигляді рядків. Окремі комірки таблиці при цьому відділяються певним знаком пунктуації (у типовому випадку це — коми).
Почнемо з простого випадку. На рисунку — електронна таблиця, де зібрані дані про довжину (у пікселях) сперматозоїдів п’яти різних самців гібридних жаб, Pelophylax esculentus.
Рис. 4.5.1 Заголовок таблиці ExampleSperm, яку збережено у форматі .csv
Зберігаємо в електронних таблицях файл з вимірами сперматозоїдів як .csv, переносимо його у теку, з якою працює R. Тепер читаємо цей файл засобами R.
У наведеному далі фрагменті коду використаємо важливу особливість R-скриптів. В тексті самого скрипту можна використовувати коментарі, що позначаються «ґратками» (#). Коментарі можуть бути використані у робочому рядку після певного виконуваного тексту, як це зроблено у наступному прикладі в першому рядку. У такому разі, R виконує команди, що розташовані до «ґратки», ліворуч від цього символу, та ігнорує усе, що розташовано праворуч від #. «Ґраткою» можна прикрити й цілий рядок, якщо розташувати цей символ на початку рядка.
До речі, R дозволяє прикрити «ґраткою» будь-яку кількість рядків або, навпаки, зняти з початку рядків таки символи; для цього достатньо виділити певну кількість рядків та натиснути Shaft+Ctrl+C.
setwd("~/data/BioStat_Course") # Ця адреса має сенс лише на компʼютері автора цього фрагменту тексту, D.Sh.
Sperm <- read.csv('ExampleSperm.csv') # Цей файл має бути розташований у робочій директорії!
# Подивитися структуру файлу Sperm:
str(Sperm)
## 'data.frame': 1188 obs. of 2 variables:
## $ Male : int 1 1 1 1 1 1 1 1 1 1 ...
## $ Lenght_pxl: int 202 228 148 170 346 189 169 293 123 139 ...
summary(Sperm) # Ще одна команда, яку можна використати для оцінки вмісту об'єкта з даними
## Male Lenght_pxl
## Min. :1.000 Min. : 51.0
## 1st Qu.:2.000 1st Qu.: 99.0
## Median :3.000 Median :127.5
## Mean :3.003 Mean :153.6
## 3rd Qu.:4.000 3rd Qu.:183.0
## Max. :5.000 Max. :516.0
4.6 Ще до початку: датафрейми, фактори, attach(), файли .RData
Як ми бачимо, в R з’явився об’єкт Sperm, де адекватно відбито структуру даних й заголовки стовпців (це наслідок використання атрибутів функції read.csv() за замовченням). Втім, в отриманому об’єкті слід зробити певні зміни. До речі, що це за об’єкт?
class(Sperm)
## [1] "data.frame"
Об’єкт Sperm належить до класу dataframe. Це слово можна перекладати українською по-різному; ми будемо використовувати просто кальку, датафрейм. Це — таблиця з даними, що складається з векторів (лінійних послідовностей даних), які мають однакову довжину. У цьому датафрейм подібний до матриці, але має одну важливу особливість. У матрицях усі дані мають однаковий тип — наприклад, текстовий або числовий (детальніше — пізніше). У датафреймі різні вектори можуть містити дані різних типів (але кожен вектор — дані якогось певного типу). Наш випадок має бути саме таким.
У таблиці з вимірами довжини сперматозоїдів різних самців гібридних жаб два стовпці (що перетворилися на два вектори у складі датафрейма Sperm) є різними. Перший містить номер особини; це просто код, що розділяє дані у другому стовпці (векторі) на 5 груп. Другий результат вимірів. Це — просто число.
Щоб краще зрозуміти різницю між цими типами даних, можна замислитися про таке. Чи має сенс, припустимо, визначення того, наскільки один сперматозоїд довший за інший? Звісно! Ми можемо відняти одне значення довжини сперматозоїда від іншого та вирахувати різницю між ними. А чи має сенс вираховування різниці між номерами різних особин? Ні! Для першого стовпця та вектора має значення лише те, однакові ці коди або різні. У такому разі ми маємо запланувати детально обговорити різноманіття типів об’єктів та типів даних у R, а зараз просто відбити цю різницю у датафреймі Sperm.
Ми вже встановили тип даних у обох векторів у складі датафрейма Sperm — подивіться на результат виконання команди str(Sperm): обидві змінні у цьому об’єкті мають позначку int, тобто integer. Як буде більш детально обговорено далі, це — позначення простого числового формату, дані у якому можуть бути виражені будь-яким числом. До речі, у результатах виконання цієї команди ми можемо побачити, як слід називати окремі вектори у складі датафреймів: перед назвою вектора там стоїть символ долара. Наприклад, подивимося на початок першого вектору.
head(Sperm$Male)
## [1] 1 1 1 1 1 1
Ми отримали перші п’ять значень обговорюваного вектора; функція head() за умовчанням виводить саме таку кількість. А якби нас цікавила інша кількість значень? Слід вказати цю кількість як атрибут функції head(); ви вже знаєте, що типовий спосіб додавання атрибутів — вказати їх у команді після коми.
head(Sperm$Male, 10)
## [1] 1 1 1 1 1 1 1 1 1 1
А чи слід кожного разу повторювати назву датафрейму, адже зрозуміло, що ми звертаємося кожного разу саме до нього? Можна і не повторювати, але доведеться вказати R, де саме слід шукати об’єкти Male та Lenght_pxl. Для цього слід використати функцію attach().
attach(Sperm)
Тепер ми можемо звертатися до векторів у складі датафрейму Sperm напряму; впевнимося у цьому на прикладі функції tail(), що цілком аналогічна розглянутій функції head(), але виводить у консолі останні елементи вказаного об’єкту.
tail(Male, 12)
## [1] 5 5 5 5 5 5 5 5 5 5 5 5
Як повідомити R, що дані у векторі Male мають інший тип, ніж у векторі Lenght_pxl (де дані дійсно мають належати до типу integer)? Перетворити перший вектор на фактор, тобто вектор, що приймає значення з чітко визначеного набору можливих даних і може бути використаний для поділу даних на групи.
Sperm$Male <- factor(Sperm$Male)
Ми виконали зміну об’єкта завдяки функції привласнення <-. Логіка тут така: Новий_стан <- функція(Старий_стан). Ми можемо впевнитися, що тип даних у першому векторі змінився.
str(Sperm)
## 'data.frame': 1188 obs. of 2 variables:
## $ Male : Factor w/ 5 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ Lenght_pxl: int 202 228 148 170 346 189 169 293 123 139 ...
Тепер вектор Male перетворився на вектор, що приймає 5 різних значень — те саме, що ми мали отримати!
Може бути так, що ми будемо звертатися до датафрейму Sperm у різних R-скриптах? Звісно. І кожного разу читати .csv-файл, перетворювати перший вектор на фактор та робити усі інші зміни, які можуть знадобитися? Можна й так; достатньо лише повторювати раз за разом відповідну послідовність рядків у R-скриптах. Але є й інше рішення: зберегти потрібний об’єкт R у вигляді окремого файлу, до якого можна буде звертатися пізніше.
save(Sperm, file = "SpermatozoaLength.RData")
Ця команда збереже файл з розширенням .RData у робочу директорію, з якою працює R; за необхідності можна вказати і іншу необхідну адресу, як-от save(Sperm, file = “/home/dsh/!_Courses/BioStatistica/SpermatozoaLength.RData”).
Отриманий файл можна буде у будь-який момент прочитати. У разі файлу .RData, що розташований у робочій директорії, це можна зробити наступною командою.
load("SpermatozoaLength.RData")
4.7 І ще до початку: проблеми з десятковими роздільниками та кодуванням в .csv-файлах
Чи завжди робота з .csv-файлами є такою простою, як у наведеному прикладі з файлом ExampleSperm.csv? На жаль, ні. Наприклад, поширеною є проблема, що пов’язана з використанням різних десяткових роздільників. Наприклад, в одному з попередніх розділів вже було наведено посилання на файл PelophylaxExample.csv. Там результати вимірів жаб вказані з точністю до мм, а як десятковий роздільник використано кому. Якщо ми спробуємо прочитати його так само як попередній файл, командою PE <- read.csv(‘PelophylaxExamples.csv’), R повідомить про помилку: “Error in read.table(file = file, header = header, sep = sep, quote = quote, : more columns than column names”. Логічно: файл має певну кількість заголовків стовпців, а в рядках з даними ті значення, що містять всередині кому, R розуміє як два різні значення! Що ж робити?
Рис. 4.7.1 Файл у форматі .csv слід зберігати так, щоб R міг його «зрозуміти»
Як показано на рисунку, під час збереження файлів .csv слід не використовувати коми як символи, що розділяють полі (комірки) та рядки. У такому разі цей файл можна буде прочитати, якщо вказати R, як саме його слід розуміти.
PE <- read.csv('PelophylaxExamples.csv', sep = ";", dec = ",") # Цей файл має бути розташований у робочій директорії!
Файл .csv прочитано. Результат читання цього файлу збережено у датафреймі PE. Подивимося, що у нас вийшло!
head(PE)
## Code Place East North Basin Sex DNA Genotyp Lc Ltc Fm
## 1 LL_f_603 Krasnocuts`k 35.16 50.07 Dnipro female 14.03 LL 60.3 19.4 26.4
## 2 LL_f_562 Chernetchina 35.13 50.05 Dnipro female 13.95 LL 56.2 18.7 26.6
## 3 LL_f_592 Chernetchina 35.13 50.05 Dnipro female 13.99 LL 59.2 19.5 28.1
## 4 LL_m_595 Chernetchina 35.13 50.05 Dnipro male 13.95 LL 59.5 19.9 28.5
## 5 LL_f_602 Chernetchina 35.13 50.05 Dnipro female 14.02 LL 60.2 21.8 28.7
## 6 LLR_f_625 Izbickoe 36.73 50.20 Don female 21.83 LLR 62.5 22.1 30.3
## Ti Dp Ci Cs
## 1 25.5 7.6 4.2 11.9
## 2 24.9 6.2 4.1 15.2
## 3 26.1 7.9 3.7 13.2
## 4 28.6 7.5 3.8 11.4
## 5 28.1 8.0 4.5 15.8
## 6 29.2 8.3 3.7 14.5
Як і у випадку попереднього файлу, деякі ознаки, які R прочитав як прості текстові ознаки, є факторами. Чи вважати фактором ознаку Place — відкрите питання. З одного боку, місця збору зразків можуть бути різними, і їхній вичерпний перелік може бути неможливим. З іншого боку, можлива ситуація, коли жаби з одного оселища порівнюються з жабами з іншого оселища. У такому разі, ознаку Place слід розглядати як фактор. Відносно ознак Basin, Sex та Genotyp сумнівів нема — це фактори.
attach(PE)
Basin <- as.factor(Basin)
Sex <- as.factor(Sex)
Genotyp <- as.factor(Genotyp)
save(PE, file = "PelophylaxExamples.RData")
Зазвичай, перший рядок таких таблиць, як ті, з якими ми працюємо, містить назви стовпців. За умовчанням R враховує ці заголовки. А коли заголовків нема, може бути потрібним використати аргумент OBJECT <- read.csv(‘FILENAME.csv’, …, header =FALSE).
До речі, певні труднощі можуть виникати при читанні файлів, де використовувалася кирилиця (найпростіше рішення — не використовувати її в статистичних файлах загалом!). Коли кирилиця читається неправильно (замість з дитинства знайомих літер, що заспокоюють та викликають довіру, — «козявушки», вони ж «кракозябри», що травмують нашу психіку самим своїм виглядом), слід встановити, з яким кодуванням було збережено файл .csv та вказати необхідне кодування окремим атрибутом, наприклад OBJECT <- read.csv(‘FILENAME.csv’, sep = “SIMBOL”, dec = “SIMBOL”, encoding = “UTF-8”) або OBJECT <- read.csv(‘FILENAME.csv’, encoding = “Windows-1251”).
Зверніть увагу! Як це зроблено у попередній команді, ім’я файлу слід вводити з одинарними прямими лапками, а символи, які треба використовувати як розділювачі, — брати у подвійні прямі лапки. Загалом, важливим джерелом помилок, які можуть перешкоджати роботі в R, є плутанина з подібними один на одного символами. Наприклад, причиною колізії, що обговорюється наприкінці пункту 4.2, є використання замість літери c з латиниці літери с з кирилиці (вони знаходяться на клавіатурі в одному місці та майже не відрізняються одна від одної, і тому їх дуже легко переплутати). Дещо подібний комплекс проблем пов’язаний і з лапками. Наприклад, якщо ви напишете так: sep = “;”, R просто нічого не зрозуміє. Подвійні (як і одинарні) лапки повинні бути прямими, тобто такими, які в найбільш поширеній розкладці ставляться при натисканні клавіші, що відповідає за українську літеру «Є» або російську — «Э» (до речі, ось приклад третього типу лапок). Щоб R виконав команду, треба писати виключно sep = “;”. На щастя, ви можете побачити, чи «розуміє» вас RStudio. Якщо RStudio приймає синтаксис введеного тексту, він підсвічує назви файлів, роздільники і інші елементи набраного користувачем тексту.
Рис. 4.7.2 «Підсвічування» елементів тексту в RStudio: у другому рядку ім’я файлу і знак десяткового розділювача (dec) підсвічені зеленим, а знак розділювача комірок (sep) — ні (там використано неправильні лапки)
Загалом, в RStudio є достатньо зручні засоби допомоги під час створення команд. Припустимо, ми плануємо роздивитися структуру створеного фрейму з використанням команди str(NAME). Під час набору назви функції RStudio у віконці, що спливає (хінті), запропонує варіанти, що починаються подібним чином, та виведе нагадування про властивості цих функцій. RStudio запропонує можливі варіанти продовження початого тексту під час зупинки у наборі або при натисканні клавіші Tab.