Почитал отрывки из книги о применении СОК в анализе финансовых данных. Понравилась четырнадцатая глава с конкретными рецептами - советами. Первая глава
даёт хорошее представление о том, что есть СОК. Оцифровка любительская.
Уважаю авторов сайта http://www.omegahat.org и пакетов, выложенных на нём. В основном там разнообразные привязки, как, например, Rlibstree к http://www.icir.org/christian/libstree/ или Rstem.
вторник, 25 декабря 2007 г.
Мимоходом
на
19:30
0
коммент.
среда, 19 декабря 2007 г.
День пятый (пакет XML)
ЗАДАЧА
Выполнить синтаксический анализ HTML документа, выяснить возможности выполнения XPath запросов.
РЕШЕНИЕ
Некоторое время я потратил на "ложный след" - решил проводить вычистку (xml-изацию) документа с помощью JTidy. В связи с чем поставил rJava. К сожалению, это пакет не очень продуман в плане удобства пользования - пользователь обязывается использовать соглашения JNI для именования типов, например,
> .jcall(f, "Ljava/awt/Component;", "add", .jcast(b, "java/awt/Component"))
и делается это непоследовательно - есть разница в объявлении типа для .jcall и.jcast.
Также эти коварные ';'. От пользователя требуется помнить про зоопарк (или иметь под рукой)
I integer D double (numeric) J long (*) F float (*)
V void Z boolean C char (integer) B byte (raw)
и соглашения для массивов: [L/java/lang/String.
Видимо из - за разных моделей типизации в R и Java, не реализовано отслеживание наследования Java - классов, поэтому код
...
> in <- .jnew("java/io/ByteArrayInputStream")
> .jcall(tidy, "Lorg/w3c/tidy/Node;", "parse", in, out)
не работает, поскольку требует явного приведения:
> .jcall(tidy, "Lorg/w3c/tidy/Node;", "parse",
.jcast(in,"java/io/InputStream"),
.jcast(out,"java/io/OutputStream"))
Так что, промежуточный вывод такой - при работе с rJava необходимо как можно больше кода писать на Java (Groovy? - интересный опыт, но что - то есть сомнения в успешности), оставляя на стороне R самый минимум. Что, в общем, очевидно.
Спустя некоторое время обнаружил, что в доках на пакеты в разделе Usage могут перечисляться не только синонимы имён функций, но и различные функции, а пакет XML реализует всю необходимую функциональность для работы с HTML.
htmlTreeParse(file, ignoreBlanks = TRUE, handlers = NULL,
replaceEntities = FALSE, asText = FALSE,
trim = TRUE, isURL = FALSE, asTree = FALSE,
useInternalNodes = FALSE, encoding = character(),
useDotNames = length(grep("^\.", names(handlers))) > 0,
xinclude = FALSE, addFinalizer = TRUE)
парсит документ, представленный в виде дискового файла (возможно сжатого), URL, строки текста.
Задачу решает следующий код:
...
> doc <- htmlTreeParse(file, useInternalNodes=T)
> scnd_table <- getNodeSet(doc, "/html/body/table[2]")
> length(scnd_table)
1
> names(scnd_table[[1]])
ВЫВОД
Пакет XML- превосходная работа! Есть возможность обращения к удалённому документу, выполнения XPath запросов к содержимому, DOM и SAX механизмы обработки. Определённо, если я возьмусь делать свой "Большой Проект", он будет на R.
на
14:45
0
коммент.
четверг, 6 декабря 2007 г.
День четвёртый (web harvesting)
ЗАДАЧА
Для работы с данными из веба надо сначало извлечь их. Затем сконвертировать в объекты, понимаемые R. Поскольку содержание страниц может меняться, надо как - то автоматизировать сбор данных, по возможности сделав его устойчивым к изменению страницы или, по крайней мере, легко модифицируемым.
РЕШЕНИЕ
Полностью автоматизировать сбор, основываясь, например, на регулярности элементов DOM не получится - слишком часто встречаются тучи без смысла вложенных TABLE. Поэтому я сделал ставку на визуальное выделение "интересных" элементов страницы с последующим назначением инструкций по их обработке.
Для работы плагина нужен прокси, чтобы добавить в тело страницы строчки:
script src="scripts/jquery.js" type="text/javascript"
script src="scripts/jqDnR.js" type="text/javascript"
script src="scripts/selector.rule.js" type="text/javascript"
а также загрузить сами сценарии из scripts/. Можно обойтись и без jqDnR.js - функциональность небольшая, а мороки много. Кое - что я сам поправил - убрал прозрачность (были из - за неё проблемы). С остальным разбираться - нет знаний и желания.
Плагин работает неторопливо, поэтому, в частности, два режима работы. В одном клик на навигационной панели приводит к прыжку (откату выделения), в другом - к предпросмотру содержимого элемента.
/*
* SelectorRule - jQuery plugin for a quick navigation over
* html tree
*
* Author: dimiii
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Version: r1
*
*/
(function($) {
var style = {
tasks_panel : {
"position" : "absolute", "zIndex" : "500", "width" : "75%",
"padding" : "5px", "margin" : "0px",
"background-color" : "#eff", "border" : "1px solid #999",
"textAlign" : "left"
},
hint_area : {
"padding" : "5px", "margin" : "5px", "width" : "95%",
"height" : "200px",
"background-color" : "#eff", "border" : "1px dotted"
},
cmd_area : {
"padding" : "5px", "margin" : "5px",
"width" : "50%", "height" : "80px",
"border" : "1px dotted"
},
mouseover : {
"border" : "2px solid lime"
},
mouseclick : {
"border" : "3px solid green"
}
};
/*
Node selector contains
*/
$.fn.nodeSelector = function() {
var click_trace = [];
var tasks_panel = null;
if (!tasks_panel) {
tasks_panel = $() // It seems blogger doesn't understand pre tag.
// So here is a commented tasks_panel's skeleton.
.appendTo("BODY")
.hide()
.bind("click", function(e) {
e.stopPropagation();
});
$(this).bind("contextmenu", function(e) {
display(tasks_panel, e, click_trace);
activate_actions(tasks_panel, click_trace);
return false;
});
}
mk_clickable(document.body, click_trace);
return this;
};
function display(tasks_panel, e, click_trace) {
$(".jqHandle").css("background-color", "lightgrey");
$("#panel_stuff")
.empty()
.append(get_mode_slctr())
.append(get_jump_nav(click_trace, true))
.append(get_hint_text(click_trace))
.append(get_command_panel())
.append(get_btns());
$("A")
.css({"font-weight" : "bold",
"text-decoration" : "none", "color" : "black"})
.bind("mouseover", function() { $(this).css("color", "red"); })
.bind("mouseout",
function() { $(this).css("color", "black"); });
tasks_panel
.css(style.tasks_panel)
.css({"left":0.15* document.width,"top":e.pageY})
.show();
};
function activate_actions(tasks_panel, click_trace)
{
$(".jump_nav")
.bind("click",
function() {
if ("selected" == $("#jumpModeBtn").attr("class")) {
var clcked = click_trace[$(this).attr("id")],
trace_pos = click_trace.pop();
while(trace_pos != clcked) {
$(trace_pos.childNodes).each(
function() { brk_clickable(this); });
$(trace_pos).css({"border" : trace_pos.cssMemo || ""});
trace_pos = click_trace.pop();
}
click_trace.push(clcked);//back
$(clcked.childNodes).each(
function() { mk_clickable(this, click_trace); });
tasks_panel.hide();
} else {
$("#hint_area")
.empty()
.append($(click_trace[$(this).attr("id")]).text());
}
});
$("#closeBtn")
.bind("click", function(){ tasks_panel.hide(); });
$("#commitBtn")
.bind("click", function(){
alert(get_jump_nav(click_trace, false));
tasks_panel.hide(); });
$("#insPathBtn")
.bind("click",
function(){ $("#cmd_area")
.append(get_jump_nav(click_trace, false)); });
$("#jumpModeBtn")
.bind("click",
function() {
if("selected" != $(this).attr("class")) {
$(this).empty().append("[jump]").addClass("selected");
$("#viewModeBtn")
.empty().append("view").removeClass("selected");
}
});
$("#viewModeBtn")
.bind("click",
function() {
if("selected" != $(this).attr("class")) {
$(this)
.empty().append("[view]").addClass("selected");
$("#jumpModeBtn")
.empty().append("jump").removeClass("selected");
}
});
tasks_panel.jqDrag(".jqDrag");
};
function mk_clickable(docnode, click_trace) {
if ($(docnode).attr("id") == "tasks_panel") return;
switch (docnode.nodeName.toString().toLowerCase()) {
// we can't make clickable tbody and tr,
// so let's make clickable their childs
case "tbody":
case "tr":
$(docnode.childNodes).each(
function() { mk_clickable(this, click_trace); });
break;
case "body":
case "div":
case "p":
case "span":
case "a":
case "table":
case "td":
try {
docnode.cssMemo = $(docnode).css("border");
}catch(exc){}
$(docnode)
.bind("mouseover",
function() { $(this).css(style.mouseover); })
.bind("mouseout",
function() { $(this).css({"border" : docnode.cssMemo
|| ""}); })
.bind("click",
function() {
click_trace.push(this);
$(this).css(style.mouseclick);
switch(docnode.parentNode.nodeName.toString()
.toLowerCase()) {
case "tbody":
case "tr":
$(docnode.parentNode.parentNode.childNodes).each(
function() { brk_clickable(this); });
break;
default:
$(docnode.parentNode.childNodes).each(
function() { brk_clickable(this); });
break;
}
$(docnode.childNodes).each(
function() { mk_clickable(this, click_trace); });
});
break;
}
};
function brk_clickable(docnode) {
switch(docnode.nodeName.toString().toLowerCase()) {
case "tbody":
case "tr": // reasons like for mk_clickable
$(docnode.childNodes).each(
function() { brk_clickable(this); });
break;
default:
$(docnode)
.unbind("mouseover").unbind("click").unbind("mouseout");
break;
}
};
/*
Implementations of other functions are skipped.
*/
})(jQuery);
$(function() {
$("BODY A").attr("href", "#");// defence
$("BODY A").unbind("click", function() { mk_clickable(this);} );
$("BODY").nodeSelector();
});
Инструкции предполагается записывать на DSL или непосредственно на R. Окончательный выбор сделаю после более подробного знакомства с библиотекой XML.
ВЫВОД
Работает и каши не просит.
БОНУС
Сегодня, через весьма насыщенный http://twit88.com узнал о существовании http://web-harvest.sourceforge.net. Основательный подход, но пока я никаких преимуществ перед моим "тынц-тынц" методом не вижу. Всё же, следует знать.
на
12:47
0
коммент.
пятница, 2 ноября 2007 г.
А мне книгу дали
Читать времени нет, но отдавать пора. Я отсканировал из неё интересные места. Книга называется что - то вроде: "Анализ финансовых данных и самоорганизующиеся карты Кохонена." Прикладной направленности книга. Но к моим данным, как можно применять SOM, пока не вижу. Хотя для первичного анализа очень симпатично смотрятся картинки, да. Выложу сканы с соответствующей меткой. Забавно - в процессе поиска способа выгрузить файл нашлось готовое решение - http://r.lab.works.googlepages.com/home С готовым акаунтом. Чёрт! Всё таки Google is Evil. И это, определённо, обернётся чем - то плохим. А пока 100 бесплатных мб и идиотский интерфейс персонализации. В качестве теста выложил "Дядя Петрос и проблема Гольдбаха".
на
20:45
0
коммент.
понедельник, 22 октября 2007 г.
День третий (an investigation)
TASK
An Investigation. R and tail recursion. Lazy evaluation in R.
SOLUTION
With a Google's help i found this message:
http://finzi.psych.upenn.edu/R/Rhelp02a/archive/73651.html
> Some functional languages have a feature called tail recursion that
> can provide performance improvements if you write your recursions
> to take advantage of it:
>
> http://en.wikipedia.org/wiki/Tail_recursion
>
> but I don't think R supports it. Is this likely to become available
> in R?
No. For a start, this is usually done by compilers, which we don't got.
In addition, it would be very difficult to do tail recursion optimization
and not break most of the sys.* functions, which give explicit access to
all the frames that would be optimized away.
-thomas
Alas, R doesn't have tail recursion optimization.
That explains last error messages about stack fault.
Now, what do they mean, when they write:
"R is a functional language, with lazy evaluation"?
Here is the answer:
http://tolstoy.newcastle.edu.au/R/help/03b/0731.html
"...R is a functional language, with lazy evaluation and weak dynamic
typing (a variable can change type at will: a <- 1 ; a <- "a" is
allowed). Semantically, everything is copy-on-modify although some
optimization tricks are used in the implementation to avoid the worst
inefficiencies.
Parameter passing is according to the "pass-by-value illusion", i.e.
what is really getting passed down to a function is a "promise", which
embodies the expression used in the call. This is at the core of the
lazy evaluation mechanism: The result of the expression is not
computed until needed. It also allows a function to get hold of the
the expression itself: This is useful for labeling plots but it also
allows some variants of "pass-by-name"-like semantics via evaluation
in the environment of the caller..."
But...
Extra!Extra!
I found more sensational materials...
"Besides lazy evaluation in R is not really lazy evaluation!"
http://www.postech.ac.kr/~gla/paper/R-ism-dec-8.ppt
CONCLUSIONS
So, my first impression, when i started this blog, was:
"Incredibly! Such perfect program for data analysis, visualization,
uses functional language." Now i see, R is not perfect.
на
13:49
0
коммент.
суббота, 20 октября 2007 г.
День второй (lazy list)
ЗАДАЧА
Реализация ленивых списков и ленивых вычислений над ними.
РЕШЕНИЕ
Первоначально я сконструировал список так:
> nums_from <-function(n)
c(function() n,
function()
c(function() n + 1,
function() nums_from(n + 2)))
Сразу же выяснил, что писать функции, работающие с ним не очень удобно:
> ints <- nums_from(1)
> ints[[1]]()
[1] 1
> ints[[2]]()[[1]]()
[1] 2
> ints[[2]]()[[2]]()[[1]]()
[1] 3
Следующий вариант стал более удачным:
> nums_from <-function(n)
pairlist(head = function() n,
tail = function()
pairlist(head = function() n + 1,
tail = function() nums_from(n + 2)))
> ints <- nums_from(1) # ленивый список натуральных числел
> ints$head()
[1] 1
> ints$tail()$head()
[1] 2
> ints$tail()$tail()$head()
[1] 3
В этот момент, я вспомнил, как где - то мне встречалось утверждение о том, что в R модель вычислений ленивая. Последовала незамедлительная проверка, не переливаю ли я из пустого в порожнее:
> nums_from <-function(n) c(n, c(n+1, nums_from(n + 2))) #1
> ints <- nums_from(1) #2
Ошибка: исполнение расположено слишком глубоко: неопределенная рекурсия / options(expressions=)?
> ?options
....
expressions: sets a limit on the number of nested expressions that
will be evaluated. Valid values are 25...500000 with default 5000.
If you increase it, you may also want to start R with a larger protection
stack; see --max-ppsize in Memory. Note too that you may cause a segfault
from overflow of the C stack, and on OSes where it is possible you may
want to increase that
.....
Так что #1 - если вычисления аргументов и ленивые, то непонятно, почему #2 - стек сносит. Т.е. стек сносит понятно почему - вычисления всё - таки производятся, при этом хвостовая реурсия, можно предположить, не оптимизируется. Тут определённо какие - то тонкости. С ними разберусь потом.
> take <- function(count, nums) {
if(count == 1) nums$head()
else c( nums$head(), take(count - 1, nums$tail()) )
}
> take(6, ints)
[1] 1 2 3 4 5 6
> is.even <- function(num) num %% 2 == 0
> sieve <- function(cond, nums) {
if (cond(nums$head()))
pairlist(head = nums$head,
tail = function() sieve(cond, nums$tail()))
else
sieve(cond, nums$tail())
}
> take(3, sieve( is.even, ints ))
[1] 2 4 6
В последнем вызове - sieve( is.even, ints )) уже лениво фильтруются чётные числа. Далее вычисляются 7 первых простых числел:
> nums_down_from <- function(n)
pairlist(head = function() n,
tail=function() pairlist(head = function() n - 1,
tail = function()
nums_down_from(n - 2)))
> has.divider <- function(nums, dvding) {
if (nums$head() == 1) F
else if (dvding %% nums$head() == 0) T
else has.divider(nums$tail(), dvding)
}
> is.prime <- function(num) {
if (num == 1) F
else {
nums <- nums_down_from(floor(sqrt(num)))
!has.divider(nums, num)
}
}
> take(7, sieve( is.prime, ints ))
[1] 2 3 5 7 11 13 17
ВЫВОД
Второй предок R - Scheme. Вполне понятно моё желание поиграться с ленивыми списками и вычислениями. Я это сделал. Но результаты не очень - то и радуют. Похоже, хвостовая рекурсия съедает стек, а вместе с ним и все преимущества ленивости. Да, кстати, и memoization не реализована. Сегодняшний день породил больше вопросов чем ответов.
на
11:45
0
коммент.
среда, 17 октября 2007 г.
День первый (an arithmetic)
ЗАДАЧА
При некотором натуральном n числа 4n+5 и 9n+4 - точные квадраты. Доказать, что число 5n+4 делится на 29.
РЕШЕНИЕ
В действительности - это задача на вычеты, и не важно даже - точные квадраты первые два числа или нет. И вот почему:
9n + 4 - (4n + 5) = 5n - 1, 5n + 4 = 0 mod 29
<=> 5n - 1 = 24 mod 29
Используя R проверим:
> ns <- 1:29 # а дальше повторы
> ns[1] 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
> rst1 <- (4*ns +5) %% 29
> rst1 # где - то здесь вычет первого квадрата
[1] 9 13 17 21 25 0 4 8 12 16 20 24 28 3 7 11 15 19 23 27 2 6 10 14 18 22 26 1 5
> rst2 <- (9*ns +4) %% 29
> rst2 # где - то здесь вычет второго квадрата
[1] 13 22 2 11 20 0 9 18 27 7 16 25 5 14 23 3 12 21 1 10 19 28 8 17 26 6 15 24 4
> (rst2 - rst1) %% 29 # а это вычеты 5n - 1, ищем 24
[1] 4 9 14 19 24 0 5 10 15 20 25 1 6 11 16 21 26 2 7 12 17 22 27 3 8 13 18 23 28
> # Ага, есть такой остаток!
ВЫВОД
В незаконченном "The R Language Definition" пишут, что R происходит от APL и Scheme. Значит по линии APL он в родственных отношениях с J, K и прочими Q. Пусть возможности R по работе с многомерными данными и не столь изощрённы, но эта задачка - была моим первым опытом после установки, и "векторизация" очень понравилась. Кажется, R можно использовать для арифметических экспериментов.
БОНУС
Задача производит впечатление чего - то вырожденного, давалась школьникам на маткружке. В самом деле, не счёт же от них требовали. Очевидно, здесь есть решение "с вывертом". Вот оно:
(4*n+5) = a^2(9*n + 4) = b^2
9*a^2 - 4*b^2 = 29
(3*a - 2*b)*(3*a + 2*b) = 29
Из простоты 29 получаем n = 5
на
23:59
0
коммент.
воскресенье, 14 октября 2007 г.
Запись вводная
Основные темы этих лабораторных записей:
За образец взяты записки inferno программиста. Мотивы те же.
Формат записей следующий:
Задача - тема лабораторной
Решение - решение, как я его вижу на текущий момент
Вывод - оставлю как отдушину для графоманства )
на
21:19
0
коммент.
