Основы программирования: циклы
22/11/13 23:24 Относится к категории: Анализ данных | R

Согласно Wiki, "цикл — разновидность управляющей конструкции в высокоуровневых языках программирования, предназначенная для организации многократного исполнения набора инструкций... Последовательность инструкций, предназначенная для многократного исполнения, называется телом цикла. Единичное выполнение тела цикла называется итерацией. Выражение определяющее, будет в очередной раз выполняться итерация, или цикл завершится, называется условием выхода или условием окончания цикла (либо условием продолжения в зависимости от того, как интерпретируется его истинность — как признак необходимости завершения или продолжения цикла). Переменная, хранящая текущий номер итерации, называется счётчиком итераций цикла или просто счётчиком цикла".
Таким образом, циклы позволяют запускать необходимую часть программного кода до тех пор, пока выполняются условия запуска. Они бывают двух видов - for и while. Циклы for выполняют программный код последовательно для каждого значения в определенном множестве. Можно назвать такой способ запуска референтным контролем. Циклы while запускают код до тех пор, пока соблюдаются условия запуска. Этот способ можно назвать логическим контролем. Поэтому, в случае использования циклов while, следует внимательно подбирать логическое условие, чтобы он не выполнялся бесконечно.
Циклы for
Рассмотрим пример. Многие из вас знают притчу о том, как были придуманы шахматы. Самым интересным в этой истории является способ оплаты творения мудреца. Его суть заключалась в том, что на первую клетку шахматной доски падишах должен был положить одно зернышко пшеницы, на вторую - два, на третью - четыре и так далее. То есть на каждую следующую клетку нужно было положить в два раза больше зерна, чем лежало на предыдущей. В конце мудрец должен был забрать все зерно. Обычные калькуляторы не позволят вам посчитать сколько зерна будет лежать на шахматной доске (с определенной клетки числа станут слишком велики). Считать в ручную тоже не вариант.
А вот с помощью R (или другого языка программирования) сделать это очень просто (строки 1-5, далее другой пример):
Циклы for
Рассмотрим пример. Многие из вас знают притчу о том, как были придуманы шахматы. Самым интересным в этой истории является способ оплаты творения мудреца. Его суть заключалась в том, что на первую клетку шахматной доски падишах должен был положить одно зернышко пшеницы, на вторую - два, на третью - четыре и так далее. То есть на каждую следующую клетку нужно было положить в два раза больше зерна, чем лежало на предыдущей. В конце мудрец должен был забрать все зерно. Обычные калькуляторы не позволят вам посчитать сколько зерна будет лежать на шахматной доске (с определенной клетки числа станут слишком велики). Считать в ручную тоже не вариант.
А вот с помощью R (или другого языка программирования) сделать это очень просто (строки 1-5, далее другой пример):
1 2 3 4 5 | > x = 1 > for (i in 1:63) { x <- x*2 print(as.character(x)) } |
Сначала мы ложим первое зернышко на первую клетку (создаем скаляр x, равный единице). В следующей строке мы пишем for (так начинается цикл этого типа) и в скобках указываем счетчик цикла. В нашем случае (i in 1:63) означает лишь то, что действие будет повторено 63 раза. Далее в фигурных скобках мы прописываем тело цикла, указывающее что конкретно произойдет этих 63 раза. Так, сначала х будет умножено на два и записано само в себя, а потом - выведено на экран. При этом функция as.character() необходима для того, чтобы результаты выводились привычным для нас способом, а не в виде специальных математических сокращений (последнее бывает в тех случаях, когда числа или слишком малы или слишком велики). В результате в первой строке будет выведено "2", во второй - "4" и т.д. до шестдесяттретей в которой будет выведено "9223372036854775808". Короче мудрец улучшил свое благосостояние. А может его просто казнили...
Продолжим тему смертной казни - обратимся к примеру, демонстрирующему решение практической проблемы. Ниже приведен небольшой цикл, который я использовал совсем недавно при анализе отношения населения Украины к отмене смертной казни.
Перед тем, как создать сам цикл, я создал два хранилища данных (строки 6 и 7):
а) пустой список deathPenaltyList (более детально о списках мы поговорим в одной из следующих тем), необходимый для "складирования" основных результатов работы цикла;
б) вектор filt, который включает числа, соответствующие годам проведения социологического мониторинга (этот вектор будет использован в качестве набора элементов, с которым связан счетчик цикла).
Продолжим тему смертной казни - обратимся к примеру, демонстрирующему решение практической проблемы. Ниже приведен небольшой цикл, который я использовал совсем недавно при анализе отношения населения Украины к отмене смертной казни.
Перед тем, как создать сам цикл, я создал два хранилища данных (строки 6 и 7):
а) пустой список deathPenaltyList (более детально о списках мы поговорим в одной из следующих тем), необходимый для "складирования" основных результатов работы цикла;
б) вектор filt, который включает числа, соответствующие годам проведения социологического мониторинга (этот вектор будет использован в качестве набора элементов, с которым связан счетчик цикла).
6 7 8 9 10 11 12 | > deathPenaltyList <- list() > filt <- c(1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2010, 2012) > for (i in 1:length(filt)) { test <- indexes[which(indexes$godNew == filt[i]) , ] test$godNew <- NULL deathPenaltyList[[i]] <- test } |
В счетчике цикла (строка 8) я указываю, что действия необходимо повторить для каждого i в наборе от 1 до значения, соответствующего длине вектора filt (функция length() возвращает длину объекта). Длина вектора равна количеству элеметов, которые в него входят. Следовательно выражение "1:length(filt)" равнозначно выражению "1:17". Тело же цикла заключается в следующем:
Строка 9: записать в test наблюдения фрема indexes, которые соответствуют указанным условиям; так, для первого этапа (или итерации) цикла (i = 1) в соответствии с логическим условием будут отобраны все наблюдения для 1992 года (так как filt[1] = 1992), для втого (i = 2) - наблюдения для 1994 года (так как filt[2] = 1994) и так далее;
Строка 10: в созданном на этом этапе фрейме данных test удалить переменную про год проведения исследования (в дальнейшем она не дает никакой полезной информации, поскольку в массив записываются данные только одного года);
Строка 11: массив данных test записать в список deathPenaltyList на место соответствующее этапу (итерации) цикла.
Что это даст? На каждом этапе будет создан фрейм данных test для соответствующего года (то есть на каждом новом этапе этот фрейм будет переписываться), из него будет удалена ненужная переменная и он будет размещен в список deathPenaltyList на свое собственное место (оно определяется этапом цикла). Следовательно к концу цикла, список будет содержать 17-ть фреймов с данными по каждому из годов. Первоначально же данные за все года размещались в массиве indexes, что не позволяло работать с каждым годом исследования по отдельности.
Этот цикл позволил сократить программный код почти в 17 раз и это хорошо :)
Строка 9: записать в test наблюдения фрема indexes, которые соответствуют указанным условиям; так, для первого этапа (или итерации) цикла (i = 1) в соответствии с логическим условием будут отобраны все наблюдения для 1992 года (так как filt[1] = 1992), для втого (i = 2) - наблюдения для 1994 года (так как filt[2] = 1994) и так далее;
Строка 10: в созданном на этом этапе фрейме данных test удалить переменную про год проведения исследования (в дальнейшем она не дает никакой полезной информации, поскольку в массив записываются данные только одного года);
Строка 11: массив данных test записать в список deathPenaltyList на место соответствующее этапу (итерации) цикла.
Что это даст? На каждом этапе будет создан фрейм данных test для соответствующего года (то есть на каждом новом этапе этот фрейм будет переписываться), из него будет удалена ненужная переменная и он будет размещен в список deathPenaltyList на свое собственное место (оно определяется этапом цикла). Следовательно к концу цикла, список будет содержать 17-ть фреймов с данными по каждому из годов. Первоначально же данные за все года размещались в массиве indexes, что не позволяло работать с каждым годом исследования по отдельности.
Этот цикл позволил сократить программный код почти в 17 раз и это хорошо :)
Циклы while
В целом главное отличие циклов while от циклов for заключается в свойствах счетчиков. Если в циклах for счетчик ссылается на некое множество, то в случае циклов while счетчик проверяет логическое условие. Если это условие не соблюдается в рамках текущей итерации, выполняется тело цикла и он переходит к следующей итерации. Если же условие соблюдается, то цикл завершает свою работу.
Рассмотрим следующий пример:
В целом главное отличие циклов while от циклов for заключается в свойствах счетчиков. Если в циклах for счетчик ссылается на некое множество, то в случае циклов while счетчик проверяет логическое условие. Если это условие не соблюдается в рамках текущей итерации, выполняется тело цикла и он переходит к следующей итерации. Если же условие соблюдается, то цикл завершает свою работу.
Рассмотрим следующий пример:
13 14 15 16 17 | > i <- 5 > while (i > 0) { print("R!!!") i <- i - 1 } |
Выглядит примитивно, не так ли? Суть этого цикла заключается в том, что пока i > 0, будет выполняться тело цикла, а именно - выводиться на экран надпись "R!!!" и вычитаться единица из i (последнее необходимо для того, чтобы цикл завершился после пятого этапа).
Не самый воодушевляющий пример. Насколько мне известно, такие циклы хороши для моделирования развития естественных процессов. И поскольку ничем таким я не занимался, мне придется выдумать что-нибудь... что-нибудь фантастическое :)
Итак, жили были хоббиты и было их 100 особей. За год для каждых десяти хоббитов прирост вследствие рождаемости составлял 1 дополнительного хоббита. Вместе с тем, в результате набегов гоблинов и смертности потери хоббитов составляли 5... штук. Теперь с помощью цикла while посмотрим сколько хоббитов будет через 10 лет. При этом (для того, чтобы мне было легче) будем считать, что каждый год хоббиты сначала рождались, а уже потом умирали и становились жертвами гоблинов.
Не самый воодушевляющий пример. Насколько мне известно, такие циклы хороши для моделирования развития естественных процессов. И поскольку ничем таким я не занимался, мне придется выдумать что-нибудь... что-нибудь фантастическое :)
Итак, жили были хоббиты и было их 100 особей. За год для каждых десяти хоббитов прирост вследствие рождаемости составлял 1 дополнительного хоббита. Вместе с тем, в результате набегов гоблинов и смертности потери хоббитов составляли 5... штук. Теперь с помощью цикла while посмотрим сколько хоббитов будет через 10 лет. При этом (для того, чтобы мне было легче) будем считать, что каждый год хоббиты сначала рождались, а уже потом умирали и становились жертвами гоблинов.
18 19 20 21 22 23 24 25 | > i = 100 > j = 1 > while (j < 11) { i = floor(i * 1.1) i = i - 5 print(i) j = j + 1 } |
Итак, i задает начальное количество хоббитов, j - обозначает первый год. Что касается тела цикла, проанализируйте его самостоятельно :) Единственное замечание по поводу функции floor(). Она округляет десятичную дробь к меньшему целому числу (например 9,99 будет округлено к 9). А использую я ее для того, чтобы хоббиты получались целыми. Кстати, через 10 лет хоббитов станет 174.
статью подготовил кандидат социологических наук Сергей Дембицкий
Data science (3)
Europe (2)
Geopolitics (2)
Infographics (1)
R (26)
Russia (2)
SPSS (2)
Ukraine (2)
Акционализм (1)
Анализ данных (27)
Аномия (1)
Выборка (1)
Выступления (3)
Геополитика (12)
Гражданское общество (2)
Демократизация (1)
Европа (4)
Интернет ресурсы (1)
Инфографика (8)
Исследовательские дизайны (1)
Историческая социология (10)
История социологии (5)
Киберспорт (1)
Книги (7)
Массивы (3)
Методология социальных исследований (1)
Методология социологических исследований (2)
Научная жизнь (3)
Новости (6)
Обратная связь (1)
Персоналии (3)
Православные конфессии в Украине (1)
Президентская власть (1)
Психологический дистресс (18)
Психология (5)
Публицистика (2)
Революция (1)
Результаты исследований (28)
Религия (3)
Россия (2)
Согласование концептов (4)
Социальная гетерогенность (1)
Социальная работа (1)
Социологическая теория (6)
Социологические тесты (1)
Социологическое образование (5)
Теория конфликта (2)
Теория социального измерения (8)
Украина (9)
Учебные планы (2)
Философия (1)
Шкалирование (36)
Экономика (1)
Эмпирическая социология (46)
Europe (2)
Geopolitics (2)
Infographics (1)
R (26)
Russia (2)
SPSS (2)
Ukraine (2)
Акционализм (1)
Анализ данных (27)
Аномия (1)
Выборка (1)
Выступления (3)
Геополитика (12)
Гражданское общество (2)
Демократизация (1)
Европа (4)
Интернет ресурсы (1)
Инфографика (8)
Исследовательские дизайны (1)
Историческая социология (10)
История социологии (5)
Киберспорт (1)
Книги (7)
Массивы (3)
Методология социальных исследований (1)
Методология социологических исследований (2)
Научная жизнь (3)
Новости (6)
Обратная связь (1)
Персоналии (3)
Православные конфессии в Украине (1)
Президентская власть (1)
Психологический дистресс (18)
Психология (5)
Публицистика (2)
Революция (1)
Результаты исследований (28)
Религия (3)
Россия (2)
Согласование концептов (4)
Социальная гетерогенность (1)
Социальная работа (1)
Социологическая теория (6)
Социологические тесты (1)
Социологическое образование (5)
Теория конфликта (2)
Теория социального измерения (8)
Украина (9)
Учебные планы (2)
Философия (1)
Шкалирование (36)
Экономика (1)
Эмпирическая социология (46)
January 2021
September 2020
March 2019
September 2018
August 2018
April 2018
March 2018
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
December 2013
November 2013
October 2013
September 2013
December 2020
November 2020
October 2020September 2020
August 2020
July 2020
June 2020
May 2020
April 2020
March 2020
February 2020
January 2020
December 2019
November 2019
October 2019September 2019
August 2019
July 2019
June 2019May 2019
April 2019March 2019
February 2019
January 2019
December 2018
November 2018
October 2018September 2018
August 2018
July 2018
June 2018
May 2018April 2018
March 2018
February 2018
January 2018December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
December 2014November 2014
October 2014
September 2014August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
December 2013
November 2013
October 2013
September 2013