2010-03-11 4 views
7

Я хотел бы написать функцию R, которая принимает формулу в качестве ее первого аргумента, аналогичную lm() или glm() и друзьям. В этом случае, это функция, которая принимает кадр данных и записывает файл в формате SVMLight, который имеет следующую общую форму:Извлечь информацию из условной формулы

<line> .=. <target> <feature>:<value> <feature>:<value> ... <feature>:<value> # <info> 
<target> .=. +1 | -1 | 0 | <float> 
<feature> .=. <integer> | "qid" 
<value> .=. <float> 
<info> .=. <string> 

, например, следующий кадр данных:

result qid  f1  f2  f3  f4 f5  f6  f7  f8 
1  -1 1 0.0000 0.1253 0.0000 0.1017 0.00 0.0000 0.0000 0.9999 
2  -1 1 0.0098 0.0000 0.0000 0.0000 0.00 0.0316 0.0000 0.3661 
3  1 1 0.0000 0.0000 0.1941 0.0000 0.00 0.0000 0.0509 0.0000 
4  -1 2 0.0000 0.2863 0.0948 0.0000 0.34 0.0000 0.7428 0.0608 
5  1 2 0.0000 0.0000 0.0000 0.4347 0.00 0.0000 0.9539 0.0000 
6  1 2 0.0000 0.7282 0.9087 0.0000 0.00 0.0000 0.0000 0.0355 

бы быть представлена ​​следующим образом:

-1 qid:1 2:0.1253 4:0.1017 8:0.9999 
-1 qid:1 1:0.0098 6:0.0316 8:0.3661 
1 qid:1 3:0.1941 7:0.0509 
-1 qid:2 2:0.2863 3:0.0948 5:0.3400 7:0.7428 8:0.0608 
1 qid:2 4:0.4347 7:0.9539 
1 qid:2 2:0.7282 3:0.9087 8:0.0355 

функция Я хотел бы написать можно было бы назвать что-то вроде этого:

write.svmlight(result ~ f1+f2+f3+f4+f5+f6+f7+f8 | qid, data=mydata, file="out.txt") 

Или даже

write.svmlight(result ~ . | qid, data=mydata, file="out.txt") 

Но я не могу понять, как использовать model.matrix() и/или model.frame() знать, какие столбцы он должен написать. Это правильные вещи, на которые нужно смотреть?

Любая помощь очень ценится!

ответ

4

Частичный ответ. Вы можете индексировать формулу объект, чтобы получить дерево разбора формулы:

> f<-a~b+c|d 
> f[[1]] 
`~` 
> f[[2]] 
a 
> f[[3]] 
b + c | d 
> f[[3]][[1]] 
`|` 
> f[[3]][[2]] 
b + c 
> f[[3]][[3]] 
d 

Теперь все, что вам нужно, это код, чтобы идти на это дерево.

ОБНОВЛЕНИЕ: Вот пример функции, которая ходит по дереву.

walker<-function(formu){ 
    if (!is(formu,"formula")) 
    stop("Want formula") 
    lhs <- formu[[2]] 
    formu <- formu[[3]] 

    if (formu[[1]]!='|') 
    stop("Want conditional part") 

    condi <- formu[[3]] 

    flattener <- function(f) {if (length(f)<3) return(f); 
          c(Recall(f[[2]]),Recall(f[[3]]))} 
    vars <- flattener(formu[[2]]) 

    list(lhs=lhs,condi=condi,vars=vars) 
} 

walker(y~a+b|c) 

Также смотрите на документацию для terms.formula и terms.object. Рассмотрение кода для некоторых функций, которые принимают условные формулы, может помочь, например. lmer функция в lme4 упаковка.

+0

Хе-хе, да, идя по дереву, действительно «все, что мне нужно». =) Я посмотрел на lmer(), но мне нужно было бы захватить исходный пакет, потому что его метод 'lmerFrames()', который, похоже, выполняет синтаксический анализ, скрыт. Или есть способ увидеть код для таких методов S4? –

+0

ОК, глядя на источник для 'lmerFrames()' и т. Д. Сейчас. Как ядовито. Думаю, я всегда предполагал, что есть какой-то более легкий способ манипулировать формулами. –

+1

Вы можете обратиться к неэкспортированным функциям в пространствах имен, используя :::, например. lme4 ::: lmerFrames. Обновленный мой ответ, чтобы включить функцию, чтобы ходить по дереву, не делает много проверки ввода на данный момент. –

0

Я использовал

formu.names <- all.vars(formu) 
Y.name <- formu.names[1] 
X.name <- formu.names[2] 
block.name <- formu.names[3] 

В коде я написал о выполнении ретроспективного для теста Фридмана:

http://www.r-statistics.com/2010/02/post-hoc-analysis-for-friedmans-test-r-code/

Но это будет работать только для: Y`X | блок

Я надеюсь на лучший ответ, который другие дадут.