В R для вывода сообщения на экран есть две команды: print()
и cat()
.
print("There are two commands") # с указанием номера строки и в кавычках
## [1] "There are two commands"
cat("There are two commands") # без указания номера строки и без кавычек
## There are two commands
При желании, если используем print()
, кавычки в выдаче можно убрать, скорректировав параметр quote:
print("There are two commands", quote=FALSE)
## [1] There are two commands
Команда cat()
позволяет не только выводить на экран уже “готовые” элементы, но и склеивать выдачу из нескольких:
w1 <- "there"
w2 <- "are"
w3 <- "two"
w4 <- "commands"
cat(c(w1, w2, w3, w4), sep=" ") # разделитель - пробел
## there are two commands
cat(c(w1, w2, w3, w4), sep="_") # разделитель - знак подчеркивания
## there_are_two_commands
Кавычки (внешние или внутренние) могут быть любые, но если в тексте уже встречаются кавычки, то одни кавычки должны быть одинарные, а другие двойные.
cat('Не хочу писать
"Hello world"!')
## Не хочу писать
## "Hello world"!
cat("Не хочу писать
'Hello world'!")
## Не хочу писать
## 'Hello world'!
Можно выводить каждый элемент с новой строки или с отступом (табуляция):
cat(' 1\n','2\n','3\n') # \n - переход на новую строку
## 1
## 2
## 3
cat(' 1\t','2\t','3\t') # \t - табуляция
## 1 2 3
Конкатенация (склевание) строк:
paste('group', 341) # по умолчанию разделяются пробелом
## [1] "group 341"
paste('01', '10', '2015', sep = '-') # можем задавать разделитель между строками (sep)
## [1] "01-10-2015"
Часто, чтобы повторять действия в R и при этом не копировать одни и те же команды много раз, используются циклы. Есть два цикла: цикл for и цикл while.
Пусть у нас есть вектор u:
u <- c(1, NA, 0, NA, 1, 0, 0, 1, NA)
Нам нужно вывести все элементы вектора на экран. Для этого надо пройтись по каждому элемента вектора u и выполнить команду cat()
:
for (i in u) {
cat(i,'\n') # \n чтобы каждый элемент выводился с новой строки
}
## 1
## NA
## 0
## NA
## 1
## 0
## 0
## 1
## NA
То, по чему итерируем (пробегаемся), указывается в круглых скобках, а то, что делаем в ходе цикла - в фигурных.
Для перебора можно задействовать не только векторы, но и просто промежутки (аналог range() в Python).
for (j in 1:10) {
cat(j)
}
## 12345678910
Цикл while устроен немного по-другому: действие повторяется до тех пор, пока выполняется некоторое условие.
t <- 1 # стартуем со значения 1
while (t < 10){
cat(t, "\n") # пока значение меньше 10, выводим его на экран
t <- t + 1 # переходим к следующему значению
}
## 1
## 2
## 3
## 4
## 5
## 6
## 7
## 8
## 9
Пусть у нас есть вектор w, состоящий из нулей и единиц, и мы хотим по очереди проверять каждый элемент и выводить на экран “yes”, если он равен 1 и “no”, если он равен 0.
w <- c(1, 0, 0, 1, 0, 1)
Для этого помимо цикла нам понадобятся операторы условия if и else. Конструкция с if устроена следующим образом: после if в круглых скобках указывается условие, затем прописывается, что необходимо сделать, если это условие выполняется.
# в круглых скобках - условие, затем - что надо сделать в случае, если оно выполняется
# в случае равенства - не теряем двойной знак =
for (k in w){
if (k == 1) cat('yes\n') else cat('no\n')
}
## yes
## no
## no
## yes
## no
## yes
При этом необязательно, чтобы else был всегда, все зависит от задачи. Например, выведем только те элементы вектора q, которые больше 5:
q <- 1:10
for (j in q){
if (j > 1) cat(j, " ")
}
## 2 3 4 5 6 7 8 9 10
Если есть более сложные, разветвленные условия, то они просто указываются друг за другом. Если необходимо использовать множественные условия (например, какие-то два условия должны выполняться одновременно), то потребуются те же символы, которые используются в логических выражениях (&, |). Рассмотрим следующий пример.
Пусть у нас есть список (вектор) оценок студентов.
grades <- c(7, 4, 10, 6, 3, 11) # вектор оценок
И мы хотим на каждую оценку выдать какой-нибудь комментарий (“хорошо”, “плохо”, “отлично” и др.). Это можно сделать следующим образом:
grades <- c(7, 4, 10, 6, 3, 11) # вектор оценок
for (j in grades) {
if (j < 4) cat(j, 'Bad\n') else
if (j>=4 && j<6) cat(j, 'Not Bad \n') # для одновременности - двойной &
if (j>=6 && j<8) cat(j, 'Good \n')
if (j>=8 && j<=10) cat(j, 'Excellent \n')
if (j>10) cat(j, '"We are the champions - my friend..." \n')
}
## 7 Good
## 4 Not Bad
## 10 Excellent
## 6 Good
## 3 Bad
## 11 "We are the champions - my friend..."
Конечно, в данном примере можно было обойтись без else. Он включен в пример только для того, чтобы показать, что при использовании разветвленных условий никакого нагромождения скобок не требуется.
Иногда возникает необходимость создавать переменные (векторы) с похожими названиями, например, group1, group2, group3 и так далее. Если бы названия переменных были бы обычными строками (текстом), это выглядело бы просто:
for(i in 1:4){
cat(paste("group", i, sep="")) # склеиваем слово и номер и выводим на экран
}
## group1group2group3group4
Но в случае с переменными все не так. Нужно не только создать определенное название, но и сообщить R, что это переменная, которой будет присваиваться значение. Для этого используется функция assign()
. Создадим четыре переменных group1 - group4 и присвоим им значения от 1 до 4 соответственно.
for (i in 1:4){
gr <- paste("group", i, sep="") # название переменной
assign(gr, i) # значение переменной - (чему присваиваем, что присваиваем)
}
Теперь можно проверить, создались ли нужные нам переменные:
group1; group2; group3; group4
## [1] 1
## [1] 2
## [1] 3
## [1] 4
Все на месте.
Функция assign()
удобна тем, что она используется для присвоения значений совсем разным объектам (переменным, векторам, матрицам и целым базам данных) и при этом тип объекта специально указывать не нужно. Если бы мы хотели создать векторы group1 - group4 и заполнить их числами от 1 до 10, то выглядело это бы почти так же, как и в примере выше:
for (i in 1:4){
gr <- paste("group", i, sep="")
assign(gr, 1:10)
}
group1; group2; group3; group4
## [1] 1 2 3 4 5 6 7 8 9 10
## [1] 1 2 3 4 5 6 7 8 9 10
## [1] 1 2 3 4 5 6 7 8 9 10
## [1] 1 2 3 4 5 6 7 8 9 10
Чтобы объединить все, что было рассмотрено на этом занятии, рассмотрим более жизненные примеры - задачи, с которыми можно столкнуться, работая с реальными данными.
Задача 1. Пусть у нас есть данные по некоторым социально-экономическим показателям в регионах за несколько лет (2000-2012 годы). Нас интересуют 25 регионов. Переменная year в базе данных, которую можно рассматривать как вектор, выглядит следующим образом:
year <- rep(2000:2012, 25) # повторяем значения от 2000 до 2012 25 раз
year[1:26] # для краткости выведем на экран первые 26 значений
## [1] 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2000
## [15] 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012
В исследовании нам нужно сравнить социально-экономические показатели регионов до 2004 года включительно и после 2004 (например, оцениваем эффект какой-нибудь реформы и перед построением более сложных моделей хотим просто сравнить величины). Для этого нам понадобится создать переменную, которая будет выполнять роль классификатора: принимать значение 0, если год не превышает 2004, и 1 - в противном случае.
Для начала создадим вектор из пропущенных значений (NA) такой же длины, что и year:
bin <- rep(NA, length(year))
А теперь с помощью цикла и условий будем его заполнять:
for (i in 1:length(year)){
if (year[i] <= 2004) bin[i] = 1
# если i-тый элемент в year не больше 2004
# то на i-ое место в bin ставим 1
else bin[i] = 0
}
Выведем первые 26 элементов нового вектора bin и убедимся, что у нас получилось то, что нужно - бинарная переменная для года:
bin[1:26]
## [1] 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0
Задача 2. Предположим, что был проведен какой-то опрос среди молодежи. Опрашивались респонденты в возрасте от 16 до 27 лет. Есть следующее деление на возрастные группы: 16-18, 19-21, 22-24, 25-27. У нас есть список возрастов респондентов, и мы хотим понять, сколько представителей каждой возрастной группы было опрошено. При этом мы хотим не только их посчитать, но и сохранить их отдельным списком для каждой группы. Другими словами, для каждой возрастной группы мы хотим создать вектор и узнать его длину.
age <- c(16, 23, 25, 25, 27, 17, 16, 24, 17, 19, 21, 18, 25, 26, 22) # список всех возрастов
# конечно, 15 человек - мало для хорошего опроса, но для примера сойдет
for (i in 1:4){
gr <- paste("group", i, sep="")
if (i == 1) assign(gr, age[age>=16 & age<=18]) # первая группа 16-18
if (i == 2) assign(gr, age[age>=19 & age<=21]) # вторая группа 19-21
if (i == 3) assign(gr, age[age>=22 & age<=24]) # третья группа 22-24
if (i == 4) assign(gr, age[age>=25 & age<=27]) # четвертая группа 25-27
}
group1; group2; group3; group4 # сами группы
## [1] 16 17 16 17 18
## [1] 19 21
## [1] 23 24 22
## [1] 25 25 27 25 26
length(group1); length(group2); length(group3); length(group4) # их численность
## [1] 5
## [1] 2
## [1] 3
## [1] 5