-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy path010-intro.qmd
583 lines (376 loc) · 40.1 KB
/
010-intro.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
# Введение в R {#sec-intro}
## Установка R и Rstudio {#sec-install}
Для работы с R необходимо его сначала скачать и установить.
- R
- [на Windows](https://cran.r-project.org/bin/windows/base/), найдите большую кнопку **Download R (номер версии) for Windows.**
- [на Mac](https://cran.r-project.org/bin/macosx/), если маку меньше, чем 5 лет, то смело ставьте \*.pkg файл с последней версией. Если старше, то поищите на той же странице версию для вашей системы.
- [на Linux](https://cran.rstudio.com/bin/linux/), также можно добавить зеркало и установить из командной строки:
<!-- -->
```
sudo apt-get install r-cran-base
```
В данной книге используется следующая версия R:
```{r}
sessionInfo()$R.version$version.string
```
После установки R необходимо скачать и установить *RStudio*:
- [RStudio Desktop](https://posit.co/download/rstudio-desktop/)
Если вдруг что-то установить не получается (или же вы просто не хотите устанавливать на компьютер лишние программы), то можно работать в облаке, делая все то же самое в веб-браузере:
- [Posit Cloud (ранее -- RStudio Cloud)](https://posit.cloud)
Первый и вполне закономерный вопрос: зачем мы ставили R и отдельно еще какой-то *RStudio*? Если опустить незначительные детали, то R -- это сам язык программирования, а *RStudio* -- это **интегрированная среда разработки *(integrated development environment; IDE)****,* которая позволяет в этом языке очень удобно работать.
> *RStudio* -- это не единственная среда для R, но, определенно, самая удобная на сегодняшний день. Почти все пользуются именно ей и не стоит тратить время на поиск чего-то более удобного и лучшего. Если же вы привыкли работать с *Jupyter Notebook*, то в R обычно вместо него используются великолепный *R Markdown* или еще более великолепный *Quarto* -- с помощью последнего и написан этот онлайн-учебник, кстати говоря. И с *R Markdown* и *Quarto* мы тоже будем разбираться (см. @sec-rmd)!
## Знакомство с RStudio {#sec-rstudio}
Так, давайте взглянем на то, что нам тут открылось:
![](images/010-intro_rstudio_tabs.png)
В первую очередь нас интересуют два окна: **1 - Code Editor** (окно для написания скриптов)[^010-intro-1] и **2 - R Console** (консоль). Здесь можно писать команды и запускать их. При этом работа в консоли и работа со скриптом немного различается.
[^010-intro-1]: При первом запуске RStudio вы не увидите это окно. Для того, чтобы оно появилось, нужно нажать `File - New File - R Script`.
В **2 - R Console** вы пишите команду и запускаете ее нажиманием `Enter`. Иногда после запуска команды появляется какой-то результат. Если нажимать стрелку вверх на клавиатуре, то можно выводить в консоль предыдущие команды. Это очень удобно для запуска предыдущих команд с небольшими изменениями.
В **1 - Code Editor** для запуска команды вы должны выделить ее и нажать `Ctrl` + `Enter` (`Cmd` + `Enter` на macOS). Если не нажать эту комбинацию клавиш, то команда не запустится. Можно выделить и запустить сразу несколько команд или даже все команды скрипта. Все команды скрипта можно выделить с помощью сочетания клавиш `Ctrl` + `A` на Windows и Linux, `Cmd` + `A` на macOS [^010-intro-2]. Как только вы запустите команду (или несколько команд), соответствующие строчки кода появятся в **2 - R Console**, как будто бы вы запускали их прямо там.
[^010-intro-2]: В RStudio есть много удобных сочетаний горячих клавиш. Чтобы посмотреть их все, нажмите `Help - Keyboard Shortcuts Help`.
Обычно в консоли удобно что-то писать, чтобы быстро что-то посчитать. Скрипты удобнее при работе с длинными командами и как способ сохранения написанного кода для дальнейшей работы. Для сохранения скрипта нажмите `File - Save As...`. R скрипты сохраняются с разрешением *.R*, но по своей сути это просто текстовые файлы, которые можно открыть и модифицировать в любом текстовом редакторе а-ля "Блокнот".
**3 - Workspace and History** -- здесь можно увидеть переменные. Это поле будет автоматически обновляться по мере того, как Вы будете запускать строчки кода и создавать новые переменные. Еще там есть вкладка с историей всех команд, которые были запущены.
**4 - Plots and files**. Здесь есть очень много всего. Во-первых, небольшой файловый менеджер, во-вторых, там будут появляться графики, когда вы будете их рисовать. Там же есть вкладка с вашими пакетами (`Packages`) и `Help` по функциям. Но об этом потом.
## R как калькулятор {#sec-calc}
R -- полноценный язык программирования, который позволяет решать широкий спектр задач. Но в первую очередь R используется для анализа данных и статистических вычислений. Тем не менее, многими R до сих пор воспринимается как просто продвинутый калькулятор. Ну что ж, калькулятор, так калькулятор.
Давайте начнем с самого простого и попробуем использовать R как калькулятор с помощью арифметических операторов `+`, `-`, `*`, `/`, `^` (степень), `()` и т.д.
Просто запускайте в консоли пока не надоест:
```{r}
40 + 2
3 - 2
5 * 6
99 / 9 #деление
2 ^ 3 #степень, 2 ** 3 тоже работает
13 %/% 3 #целочисленное деление
13 %% 3 #остаток от деления
```
::: callout-caution
## Время мемов
Попробуйте самостоятельно посчитать что-нибудь с разными числами.
![](images/010-intro_meme_practical_cat.jpg){width="400px"}
:::
Ничего сложного, верно? Вводим выражение и получаем результат.
::: {#co-comment .callout-tip}
## *Полезное:* комментарии
Вы могли заметить, что некоторые команды у меня заканчиваются знаком решетки (`#`). Все, что написано в строчке после `#` игнорируется R при выполнении команды. Написанные команды в скрипте рекомендуется сопровождать комментариями, которые будут объяснять вам же в будущем (или кому-то еще), что конкретно происходит в соответствующем куске кода [^010-intro-3]. Кроме того, комментарии можно использовать в тех случаях, когда вы хотите написать кусок кода по-другому, не стирая полностью предыдущий код: достаточно "закомментить" нужные строчки - поставить `#` в начало каждой строки, которую вы хотите переписать. Для этого есть специальное сочетание горячих клавиш: `Ctrl` + `Shift` + `C` (`Cmd` + `Shift` + `C` на macOS) -- во всех выделенных строчках будет написан `#` в начале.
:::
[^010-intro-3]: Во время написания кода вам может казаться понятным то, что вы написали, но при возвращении к коду через некоторое время вы уже не будете этого помнить. Старайтесь писать комментарии как можно чаще!
Согласно данным навязчивых рекламных баннеров в интернете, только 14% россиян могут справиться с этим примером:
```{r}
2 + 2 * 2
```
На самом деле, разные языки программирования ведут себя [по-разному](https://www.quora.com/Do-all-computer-languages-with-operator-precedence-use-the-same-operator-precedence) в таких ситуациях, поэтому ответ 6 (сначала умножаем, потом складываем) не так очевиден.
Порядок выполнения арифметических операций (т.е. приоритет операторов, *operator precedence*) в R как в математике, так что не забывайте про скобочки.
```{r}
(2 + 2) * 2
```
Если Вы не уверены в том, какие операторы имеют приоритет, то используйте скобочки, чтобы точно обозначить, в каком порядке нужно производить операции. Или же смотрите на таблицу приоритета операторов с помощью команды `?Syntax`.
## Функции {#sec-func}
Давайте теперь извлечем корень из какого-нибудь числа. В принципе, тем, кто помнит школьный курс математики, возведения в степень вполне достаточно:
```{r}
16 ^ 0.5
```
Ну а если нет, то можете воспользоваться специальной **функцией**: это обычно какие-то буквенные символы с круглыми скобками сразу после названия функции. Мы подаем на вход (внутрь скобочек) какие-то данные, внутри этих функций происходят какие-то вычисления, которые выдает в ответ какие-то другие данные (или же функция записывает файл, рисует график и т.д.).
Вот, например, функция для корня:
```{r}
sqrt(16)
```
::: callout-important
## Осторожно!
R -- case-sensitive язык, т.е. регистр важен. SQRT(16) не будет работать.
:::
А вот так выглядит функция логарифма:
```{r}
log(8)
```
Так, вроде бы все нормально, но... Если Вы еще что-то помните из школьной математики, то должны понимать, что что-то здесь не так.
Здесь не хватает основания логарифма!
> Логарифм -- показатель степени, в которую надо возвести число, называемое основанием, чтобы получить данное число.
То есть у логарифма 8 по основанию 2 будет значение 3:
$\log_2 8 = 3$
То есть если возвести 2 в степень 3 у нас будет 8:
$2^3 = 8$
Только наша функция считает все как-то не так.
Чтобы понять, что происходит, нам нужно залезть в хэлп этой функции:
```{r, eval = FALSE}
?log
```
Справа внизу в RStudio появится вот такое окно, в котором можно прочитать **документацию *(documentation)*** по выбранной функции:
![](images/010-intro_screen_use_help.png){width="400"}
::: callout-tip
## *Полезное:* Документация в R
Документация в R есть для всех встроенных функций. Еще есть документация для встроенных наборов данных и других объектов, но большая часть документации касается именно функций. Документация всегда имеет одинаковую структуру, которая позволяет быстро понять, что функция требует на входе, что она делает и что возвращает. Подробнее про структуру документации можно почитать [здесь.](https://socviz.co/appendix.html#a-little-more-about-r)
:::
В верхней части документации (*Usage*) функция прописана со всеми используемыми аргументами (arguments). Если через знак `=` для этих аргументов что-то прописано, то это означает, что эти параметры имеют значения по умолчанию.
Действительно, у функции `log()` есть еще аргумент `base =`. По умолчанию он равен числу Эйлера (`r exp(1)`...), т.е. функция считает натуральный логарифм. В большинстве функций R есть какой-то основной аргумент -- данные в том или ином формате, а есть и дополнительные аргументы, которые можно прописывать вручную, если значения по умолчанию вас не устраивают. Обычно эти дополнительные аргументы -- это параметры функции, которые задают то, как именно функция работает.
```{r}
log(x = 8, base = 2)
```
...или просто (если вы уверены в порядке переменных):
```{r}
log(8, 2)
```
Более того, вы можете использовать результат выполнения одних функций в качестве аргумента для других:
```{r}
log(8, sqrt(4))
```
Если эксплицитно писать имена аргументов, то их порядок в функции не важен:
```{r}
log(base = 2, x = 8)
```
А еще можно писать имена аргументов не полностью, если они не совпадают с другими:
```{r}
log(b = 2, x = 8)
```
Мы еще много раз будем возвращаться к функциям. Вообще, функции -- это одна из важнейших штук в R (примерно так же как и в *Python*). Мы будем создавать свои функции, использовать функции как аргументы для функций и многое-многое другое. В R очень крутые возможности работы с функциями. Поэтому подружитесь с функциями, они клевые.
::: {#co_adv_f_as_op .callout-warning}
## *Для продвинутых:* операторы -- это тоже функции
Арифметические знаки, которые мы использовали: `+`,`-`,`/`,`^` и т.д. называются **операторами** и на самом деле тоже являются функциями:
```{r}
`+`(3, 4)
```
Это не очень читаемая запись, конечно, поэтому использовать так обычно не рекомендуется: мы хотим, чтобы код был максимально понятным. Но ведь любопытно, правда?
:::
## В любой непонятной ситуации -- гуглите {#sec-google}
Если вдруг вы не знаете, что искать в хэлпе, или хэлпа попросту недостаточно, то... гуглите!
::: callout-caution
## Время мемов
![](images/010-intro_meme_doctors_googling.jpg)
:::
Нет ничего постыдного в том, чтобы гуглить решения проблем. Это абсолютно нормально. Используйте силу интернета во благо и да помогут вам [*Stackoverflow*](https://stackoverflow.com)[^010-intro-4] и бесчисленные R-туториалы!
[^010-intro-4]: [Stackoverflow](https://stackoverflow.com) -- это сайт с вопросами и ответами. Эдакий аналог *Quora*, *The Question*, ну или *Ответы Mail.ru* в мире программирования.
::: callout-caution
## Время мемов
::: columns
::: {.column width="40%"}
![](images/010_intro_copypaste_stack.png)
:::
::: {.column width="55%"}
![](images/010-intro_meme_copypaste_lazy.jpg)
:::
:::
:::
Главное, помните: загуглить работающий ответ всегда недостаточно. Надо понять, как и почему решение работает. Иначе что-то обязательно пойдет не так.
Кроме того, правильно загуглить проблему -- не так уж и просто. Это отдельное искусство, которое необходимо освоить любому, кто занимается программированием: у меня быстро находить ответ на вопрос в интернете. Это не шутка!
::: callout-caution
## Время мемов
![](images/010_intro_goot_at_googling_twitter.png){width="600"}
:::
Короче говоря:
> Гуглить -- хорошо, бездумно копировать чужие решения -- плохо.
## Переменные {#sec-variables}
Важная штука в программировании на практически любом языке -- возможность сохранять значения в **переменных *(variables)***. В R это обычно делается с помощью вот этих символов: `<-` (но можно использовать и обычное `=`, хотя это не очень принято). Для этого есть удобное сочетание клавиш: нажмите одновременно `Alt` + `-` (или `option` + `-` в macOS).
```{r}
a <- 2
```
::: callout-tip
## Полезное: присвоение и вывод в консоль
Заметьте, при присвоении результат вычисления не выводится в консоль! Если опустить детали, то обычно результат выполнения команды либо выводится в консоль (и не сохраняется), либо записывается в переменную (но тогда не показывается в консоли).
Чтобы вывести в консоль содержание существующей переменной, просто введите ее название:
```{r}
a
```
:::
Справа от `<-` находится значение, которое вы хотите сохранить, или же какое-то выражение, результат которого вы хотите сохранить в эту переменную[^010-intro-5]:
[^010-intro-5]: Есть еще оператор `->`, который позволяет присваивать значения слева направо, но так делать не рекомендуется, хотя это бывает довольно удобным.
Слева от `<-` находится название будущей переменной. Название переменных может быть самым разным.
::: callout-warning
## *Advanced:* синтаксически валидные имена для переменных
Есть несколько ограничений для синтаксически валидных имен переменных: они должны включать в себя буквы, цифры, `.` или `_`, начинаться на букву (или точку, за которой не будет следовать цифра), не должны совпадать с [коротким списком зарезервированных слов](https://stat.ethz.ch/R-manual/R-devel/library/base/html/Reserved.html). Короче говоря, название не должно включать в себя пробелы и большинство других знаков.
Нельзя: - `new variable` - `_new_variable` - `.1var` - `v-r`
Можно: - `new_variable` - `.new.variable` - `var_2`
На самом деле, можно создавать переменные с невалидными именами. Такие названия нужно обрамлять бэктиками (\`):
```{r}
`1 СЛОВНО ...` <- 100
`1 СЛОВНО ...`
```
Это же относится и к другим именам в R, например, к названиям колонок датафрейма (см. @sec-df), но таких имен лучше, конечно, избегать.
:::
::: callout-tip
## *Полезное:* понятные имена переменных
Обязательно делайте названия переменных осмысленными! Старайтесь делать при этом их понятными и короткими, это сохранит вам очень много времени, когда вы (или кто-то еще) будете пытаться разобраться в написанном ранее коде. Если название все-таки получается длинным и состоящим из нескольких слов, то лучше всего использовать нижнее подчеркивание в качестве разделителя: `some_variable`[^010-intro-6].
:::
[^010-intro-6]: Еще иногда используются большие буквы `SomeVariable`, но это плохо читается, а иногда -- точка, но это тоже не рекомендуется.
После присвоения переменная появляется во вкладке **Environment** в RStudio:
![](images/010-intro_env.png)
Теперь использовать переменные в функциях и просто вычислениях:
```{r}
b <- a ^ a + a * a
b
log(b, a)
```
Удалять переменные можно с помощью функции `rm()`:
```{r}
#| error: true
e <- a ^ b
e
rm(e)
e #переменной больше нет, возвращает ошибку
```
## Логические операторы {#sec-logic}
Вы можете сравнивать разные переменные:
```{r}
a == b
```
Заметьте, что сравнивая две переменные мы используем два знака равно `==`, а не один `=`. Иначе это будет означать присвоение.
```{r}
a = b
a
```
::: callout-note
## Время мемов
Теперь Вы сможете понять комикс про восстание роботов на следующей странице (пусть он и совсем про другой язык программирования)
![](images/010-intro_robots.jpg)
Этот комикс объясняет, как важно не путать присваивание и сравнение *(хотя я иногда путаю до сих пор =( )*.
:::
Иногда нам нужно проверить на ***не***равенство:
```{r}
a <- 2
b <- 3
a == b
a != b
```
Восклицательный язык в программировании вообще и в R в частности стандартно означает отрицание.
Еще мы можем сравнивать на больше/меньше:
```{r}
a > b
a < b
a >= b
a <= b
```
Этим мы будем пользоваться в дальнейшем регулярно! Именно на таких простых логических операциях построено большинство операций с данными.
## Типы данных {#sec-data_types}
<!--# Картинка с типами данных -->
### Числовые типы {#sec-type_numeric}
До этого момента мы работали только с ***числами (numeric).*** На самом деле, в R три типа ***numeric:*** ***integer*** **(целые), *double* (дробные), *complex* (комплексные числа)**[^010-intro-7]. R сам будет конвертировать числа в нужный числовой тип при необходимости, поэтому этим можно не заморачиваться за исключением редких случаев.
[^010-intro-7]: **Комплексные числа в R пишутся так: `complexnumber <- 2+2i`. `i` здесь - это та самая мнимая единица, которая является квадратным корнем из -1.**
Если же все-таки нужно задать конкретный тип числа эксплицитно, то можно воспользоваться функциями `as.integer()`, `as.double()` и `as.complex()`.
::: callout-warning
## *Для продвинутых:* числа не то, чем кажутся
Если число выглядит как целое, еще не факт, что это integer. Внутри оно может храниться как дробное, но, как я уже написал, это обычно не так важно. Но если очень нужно сделать именно integer, при создании числа можно поставить в конце `L`:
```{r}
is.integer(5)
is.integer(5L)
```
:::
::: callout-warning
## *Для продвинутых:* ограничения дробных чисел
Про *double* есть еще один маленький секрет. Дело в том, что дробные числа хранятся в R как [числа с плавающей запятой двойной точности](https://ru.wikipedia.org/wiki/Число_двойной_точности) (отсюда и название -- ***"double"*****,** т.е. ***"double precision"*****).** Да-да, компьютеры неточные! Дробные числа в компьютере могут быть записаны только с определенной степенью точности, поэтому иногда встречаются вот такие вот ситуации:
```{r}
sqrt(2) ^ 2 == 2
```
Казалось бы, с обоих сторон -- 2, почему же тогда `FALSE`? Дело в том, что в обоих случаях это дробное число, которое не может равняться ровно двум. Внутри это не два, а что-то вроде 2.0000....001 или 1.9999...999, число записано как степени двойки и отображено в десятичной системе. R не показывает все доступные цифры дробной части ради удобства, поэтому показывает округление, и мы видим просто число 2.
Поэтому при сравнении двух чисел происходит не сравнение их разницы с чистым круглым нулем, а сопоставление с очень маленьким числом -- **машинной ошибкой** или **машинным эпсилоном** ***(machine epsilon).*** Если разница между двумя дробными числами меньше этого эпсилона, то числа считаются равными. Если выходят за пределы этой ошибки, то нет. Размер машинного эпсилона можно посмотреть с помощью `.Machine$double.eps`.
Обычно это все работает хорошо, но некоторые операции "выпрыгивают" за рамки этой ошибки, отсюда и такое "странное" поведение, которое иногда может возникать при сравнении двух чисел. Если хотите углубиться в этот вопрос, то можете почитать [здесь](https://stackoverflow.com/questions/9508518/why-are-these-numbers-not-equal?noredirect=1&lq=1).
Это довольно стандартная ситуация, характерная не только для R. Чтобы ее избежать, можно воспользоваться функцией `all.equal()`:
```{r}
all.equal(sqrt(2) ^ 2, 2)
```
Еще один пример необычного поведения дробных чисел, связанный с их "неточностью", можно наблюдать в ситуациях, где вы ожидаете ноль, а получаете что-то такое:
```{r}
sin(pi)
```
По правилам тригонометрии, $sin(\pi) = 0$, тогда откуда у нас это странное число с `e-16` в конце?
Это то, что называется *экспоненциальной записью (scientific notation)* числа, которую R использует автоматически, если нужно напечатать очень маленькое или очень большое число. Экспоненциальная запись часто используется как в компьютерах, так и во многих науках, так что читать ее полезно уметь.
Если перед нами очень маленькое число, то вместо того, чтобы писать многочисленные нули, можно записать его как $m\times 10^{n}$ , где $m$ -- число от 1 до 10, а $n$ -- это отрицательная степень десяти: $10^{-1} = 0.1$, $10^{-2} = 0.01$, $10^{-3} = 0.001$, ... , $10^{-16} = 0.0000000000000001$.
`е-16` в конце числа -- это и есть \$10\^{-16}\$, а `1.224647` -- это множитель $m$, на который полученное число с очень большим количеством нулей умножается (точнее, только его первые несколько цифр). Получается, что этот множитель не сильно меняет погоды, поэтому когда видите число с `е-`, нужно смотреть в первую очередь именно на степень. Вот так это число выглядит в родной для нас десятичной записи:
```{r}
format(sin(pi), scientific = FALSE)
```
Эта маленькая дробная часть возникла из-за этой "неточности" хранения дробных чисел и самого числа $\pi$ в компьютере, которую мы обсуждали выше.
Аналогично маленьким числам, R использует экспоненциальную запись, когда нужно напечатать очень большое число:
```{r}
2 ^ 40
```
Обратите внимание, что здесь у нас `e+12`, а не `e-12`, что означает \$10\^{12}\$, а не \$10\^{-12}\$. То есть перед нами теперь $1.099512\times 10^{12}$:
```{r}
format(2 ^ 40, scientific = FALSE)
```
Опять же, `1.099512` -- это только первые цифры, в экспоненциальной записи R не показывает их все. Смотреть нужно сначала на степень (`e+12`), только потом -- на множитель впереди.
:::
### Строковый тип {#sec-type_character}
**Строковые *(character)*** данные -- это набор букв, цифр и символов. Чтобы создать строковую переменную, нужные знаки обособляются кавычками.
```{r}
s <- "Всем привет!"
s
class(s)
```
Как и в *Python*, можно использовать как `"`, так и `'` (что удобно, когда строчка внутри уже содержит какие-то кавычки).
```{r}
"Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn"
```
Главное, открывать и закрывать кавычки одинаковыми кавычками ( `"` или `'`)
Чтобы соединить несколько строковых переменных вместе, можно воспользоваться функцией `paste()`[^010-intro-8]:
[^010-intro-8]: Оператор `+`, в отличие от Python, не работает для соединения строк.
```{r}
paste("I", "love", "R")
```
По умолчанию функция `paste()` соединяет строки пробелами, но разделитель можно настроить параметром `sep =`:
```{r}
paste("I", "love", "R", sep = "_<3_")
```
Чтобы соединять строки, так сказать, "без ничего", нужно поставить `sep = ""` или же воспользоваться функцией `paste0()` специально для этого конкретного случая:
```{r}
paste("I", "love", "R", sep = "")
paste0("I", "love", "R")
```
### Логический тип {#sec-type_logical}
**Логические *(logical)*** данные -- это просто `TRUE` или `FALSE`. То же самое, что и *boolean* тип в других языках программирования
```{r}
t1 <- TRUE
f1 <- FALSE
t1
f1
```
::: callout-warning
## *Для продвинутых:* `T` и `F`
Вообще, можно еще писать `T` и `F` (но не `True` и `False`!)
```{r}
t1 <- T
f1 <- F
```
Это плохая практика: R защищает от перезаписи переменные `TRUE` и `FALSE`, но не защищает от этого `T` и `F`.
```{r}
#| error: true
TRUE <- FALSE
TRUE
T <- FALSE
T
```
Теперь удалим эту переменную `T` от греха подальше иначе все перестанет работать при ее использовании:
```{r}
rm(T)
```
:::
Мы уже встречались с логическими значениями при сравнении двух числовых переменных. Теперь вы можете догадаться, что результаты сравнения, например, числовых или строковых переменных, можно тоже сохранять в переменные!
```{r}
comparison <- a == b
comparison
```
Это нам очень понадобится, когда мы будем работать с реальными данными: нам нужно будет постоянно вытаскивать какие-то данные из датасета, что как раз и построено на игре со сравнением переменных.
Чтобы этим хорошо уметь пользоваться, нам нужно еще освоить как работать с логическими операторами. Про один мы немного уже говорили -- это логическое НЕ (`!`). `!` превращает `TRUE` в `FALSE`, а `FALSE` в `TRUE`:
```{r}
t1
!t1
!!t1 #Двойное отрицание!
```
Еще есть логическое И (выдаст `TRUE` только в том случае если обе переменные `TRUE`):
```{r}
t1 & t1
t1 & f1
f1 & t1
f1 & f1
```
А еще логическое ИЛИ (выдаст `TRUE` в случае если хотя бы одна из переменных `TRUE`):
```{r}
t1 | t1
t1 | f1
f1 | t1
f1 | f1
```
Обратите внимание: `t1 | t1`, то есть когда с обоих сторон `TRUE`, тоже возвращает `TRUE`!
::: callout-warning
## *Для продвинутых:* строгое ЛИБО
Если кому-то вдруг понадобится другое ИЛИ (строгое ЛИБО) -- есть функция `xor()`, принимающая два аргумента и возвращая `TRUE` только в том случае, если ровно один из двух аргументов равен `TRUE`. Но на практике она нужна очень редко, тогда как логические И и ИЛИ нужны очень часто: например, вам нужно отобрать только респондентов от 18 до 25, для этого нужно сделать два сравнения: что возраст больше 18 и что возраст меньше 25, после чего соединить два сравнения логическим И.
:::
Итак, мы только что разобрались с самой занудной (хотя и важной) частью - с основными типа данных в R и как с ними работать[^010-intro-9]. Пора переходить к чему-то более интересному и специфическому для R. Вперед к ВЕКТОРАМ!
[^010-intro-9]: Кроме описанных пяти типов данных (integer, double, complex, character и logical) есть еще и шестой -- это raw, сырая последовательность байтов, но нам она не понадобится.