Para compartilhar mais dicas e truques para R , qual é o seu recurso ou truque mais útil? Vetorização inteligente? Entrada / saída de dados? Visualização e gráficos? Análise estatística? Funções especiais? O próprio ambiente interativo?
Um item por postagem, e veremos se conseguimos um vencedor por meio de votos.
[Editar 25 de agosto de 2008]: Então, após uma semana, parece que o simples str()ganhou a votação. Como eu mesma gosto de recomendar essa, é uma resposta fácil de aceitar.
@Dirk: "wiki da comunidade" significa "propriedade da comunidade", não é sinônimo de "questão da enquete". Não dê ouvidos à polícia da comunidade wiki.
Bullying CW novamente. Vou ver seu meta-SO e falar com
ars
13
@ars: é uma pergunta que não tem uma resposta definitiva . Portanto, torne-o CW.
dmckee --- ex-gatinho moderador
2
@JD Longo comentário hilário. infelizmente, estava escondido atrás da dobra. Quer dizer, responder a perguntas R difíceis realmente não compensa a repetição de pilha. Então está tudo bem para mim se os caras que fazem perguntas legais que colocam R no mapa finalmente recebem algum crédito. Além disso, isso é certamente mais útil para usuários de R do que qual seria a sua pergunta capciosa favorita de C para programadores de C ...
Ah, strtambém é abreviação de stringem muitos idiomas.
Hamish Grubijan
Porque não class()? Parece revelar um tipo de informação semelhante. Por que existem dois comandos semelhantes?
hhh
1
class()é apenas uma pequena parte das informações que são str()exibidas
hadley
64
Uma função muito útil que uso com frequência é dput (), que permite fazer dump de um objeto na forma de código R.
# Use the iris data set
R> data(iris)# dput of a numeric vector
R> dput(iris$Petal.Length)
c(1.4,1.4,1.3,1.5,1.4,1.7,1.4,1.5,1.4,1.5,1.5,1.6,1.4,1.1,1.2,1.5,1.3,1.4,1.7,1.5,1.7,1.5,1,1.7,1.9,1.6,1.6,1.5,1.4,1.6,1.6,1.5,1.5,1.4,1.5,1.2,1.3,1.4,1.3,1.5,1.3,1.3,1.3,1.6,1.9,1.4,1.6,1.4,1.5,1.4,4.7,4.5,4.9,4,4.6,4.5,4.7,3.3,4.6,3.9,3.5,4.2,4,4.7,3.6,4.4,4.5,4.1,4.5,3.9,4.8,4,4.9,4.7,4.3,4.4,4.8,5,4.5,3.5,3.8,3.7,3.9,5.1,4.5,4.5,4.7,4.4,4.1,4,4.4,4.6,4,3.3,4.2,4.2,4.2,4.3,3,4.1,6,5.1,5.9,5.6,5.8,6.6,4.5,6.3,5.8,6.1,5.1,5.3,5.5,5,5.1,5.3,5.5,6.7,6.9,5,5.7,4.9,6.7,4.9,5.7,6,4.8,4.9,5.6,5.8,6.1,6.4,5.6,5.1,5.6,6.1,5.6,5.5,4.8,5.4,5.6,5.1,5.1,5.9,5.7,5.2,5,5.2,5.4,5.1)# dput of a factor levels
R> dput(levels(iris$Species))
c("setosa","versicolor","virginica")
Pode ser muito útil postar blocos de dados facilmente reproduzíveis quando você pedir ajuda ou editar ou reordenar os níveis de um fator.
head () e tail () para obter a primeira e a última parte de um dataframe, vetor, matriz, função, etc. Especialmente com grandes frames de dados, esta é uma maneira rápida de verificar se ele foi carregado corretamente.
Um recurso interessante: a leitura de dados usa conexões que podem ser arquivos locais, arquivos remotos acessados via http, canais de outros programas ou mais.
Como um exemplo simples, considere este acesso para N = 10 inteiros aleatórios entre min = 100 e max = 200 de random.org (que fornece números aleatórios verdadeiros com base no ruído atmosférico em vez de um gerador de números pseudo-aleatórios):
R> site <-"http://random.org/integers/"# base URL
R> query <-"num=10&min=100&max=200&col=2&base=10&format=plain&rnd=new"
R> txt <- paste(site, query, sep="?")# concat url and query string
R> nums <- read.table(file=txt)# and read the data
R> nums # and show it
V1 V211651432107118310313241911005138185
R>
Como um aparte, o pacote aleatório fornece várias funções de conveniência para acessar random.org .
BTW-- eu sugiro que você deve fazer auto-respostas CW se (1) você publicá-las prontamente e (2) você não fizer a pergunta CW. Caso contrário, parece que você está tentando burlar o sistema de repetições. YMMV e tudo isso.
dmckee --- ex-moderador gatinho de
1
Não se trata de enganar o sistema, apenas dar início às coisas. Ele ainda está livre para aceitar qualquer outra resposta.
ars de
2
@ars: Ele está livre para aceitar este. Nem vou tentar forçá-lo a fazer um wiki se ele ganhar; siga meu conselho. Mas não vou postar uma auto-resposta preparada sem marcá-la no wiki e também não vou votar em uma sem ela. Pegue isso pelo que vale a pena.
dmckee --- ex-moderador gatinho de
4
@Dirk: é totalmente aceitável, até mesmo incentivado por Jeff e Joel, responder sua própria pergunta. NÃO há exigência, nem mesmo informal, para fazer sua resposta CW. Você claramente não está enganando o sistema. Mais uma vez, simplesmente ignore a polícia da comunidade wiki.
Julieta de
8
Tenho que concordar que parte do propósito dos sites é fornecer as melhores respostas para problemas comuns e um recurso geral. Fazer perguntas e dar boas respostas pode ajudar a fortalecer um tópico. Isso é especialmente útil com tags novas / pequenas, como R.
kpierce8
35
Acho que estou usando with()e within()cada vez mais. Chega de $bagunçar meu código e não é necessário começar a anexar objetos ao caminho de pesquisa. Mais a sério, acho que with()etc. tornam a intenção dos meus scripts de análise de dados muito mais clara.
> df <- data.frame(A = runif(10), B = rnorm(10))> A <-1:10## something else hanging around...> with(df, A + B)## I know this will use A in df![1]0.04334784-0.404446861.993688160.13871605-1.17734837[6]0.424738122.330142261.616907991.419018600.8699079
with()configura um ambiente no qual a expressão R é avaliada. within()faz a mesma coisa, mas permite que você modifique o objeto de dados usado para criar o ambiente.
> df <- within(df, C <- rpois(10, lambda =2))> head(df)
A B C10.62635571-0.5830079120.04810539-0.4525522130.397069791.5966184340.95802501-0.8193090250.76772541-1.9450738260.213350060.21138814
Algo que não percebi quando usei pela primeira vez within()é que você deve fazer uma atribuição como parte da expressão avaliada e atribuir o objeto retornado (como acima) para obter o efeito desejado.
Eu descobri que as planilhas do Google são uma maneira fantástica de todos os colaboradores estarem na mesma página. Além disso, o Formulários Google permite capturar dados dos entrevistados e gravá-los sem esforço em uma planilha do Google. Como os dados mudam com frequência e quase nunca são finais, é muito preferível que R leia uma planilha do Google diretamente do que fazer download de arquivos csv e lê-los.
# Get data from google spreadsheet
library(RGoogleDocs)
ps <-readline(prompt="get the password in ")
auth = getGoogleAuth("[email protected]", ps, service="wise")
sheets.con <- getGoogleDocsConnection(auth)
ts2=getWorksheets("Data Collection Repos",sheets.con)
names(ts2)
init.consent <-sheetAsMatrix(ts2$Sheet1,header=TRUE, as.data.frame=TRUE, trim=TRUE)
Não consigo lembrar qual, mas um ou dois dos seguintes comandos levam vários segundos.
[Editar] Dirk pergunta por que alguém daria nomes inválidos? Eu não sei! Mas certamente encontro esse problema na prática com bastante frequência. Por exemplo, usando o pacote reshape do hadley:
> library(reshape)> df$z <- c(1,1,2,2,2)> recast(df,z~.,id.var="z")
Aggregation requires fun.aggregate: length used as default
z (all)114226> recast(df,z~.,id.var="z")$(all)
Error: unexpected '('in"recast(df,z~.,id.var="z")$("> recast(df,z~.,id.var="z")$`(all)`
Aggregation requires fun.aggregate: length used as default
[1]46
Minha nova coisa favorita é a biblioteca foreach. Ele permite que você faça todas as coisas legais de aplicação, mas com uma sintaxe um pouco mais fácil:
A melhor parte é que, se você estiver fazendo algo que realmente requer uma quantidade significativa de tempo, poderá alternar de %do%para %dopar%(com a biblioteca de back-end apropriada) para paralelizar instantaneamente, mesmo em um cluster. Muito habilidoso.
Eu faço muitas manipulações básicas de dados, então aqui estão duas funções integradas ( transformar , subconjunto ) e uma biblioteca ( sqldf ) que eu uso diariamente.
criar dados de vendas de amostra
sales <- expand.grid(country = c('USA','UK','FR'),
product = c(1,2,3))
sales$revenue <- rnorm(dim(sales)[1], mean=100, sd=10)> sales
country product revenue
1 USA 1108.459652 UK 197.079813 FR 199.662254 USA 2100.347545 UK 287.122626 FR 2112.860847 USA 395.878808 UK 396.435819 FR 394.59259
use transform () para adicionar uma coluna
## transform currency to euros
usd2eur <-1.434
transform(sales, euro = revenue * usd2eur)>
country product revenue euro
1 USA 1108.45965155.53112 UK 197.07981139.21253 FR 199.66225142.9157...
O pacote sqldf fornece uma interface SQL para quadros de dados R
## recast the previous subset() expression in SQL
sqldf('SELECT product, revenue FROM sales \
WHERE country = "USA" \
AND product IN (1,2)')>
product revenue
11108.459722100.3475
Realize uma agregação ou GROUP BY
sqldf('select country, sum(revenue) revenue \
FROM sales \
GROUP BY country')>
country revenue
1 FR 307.11572 UK 280.63823 USA 304.6860
Para uma funcionalidade mais sofisticada do tipo mapa-redução em frames de dados, verifique o pacote plyr . E se encontrar-se querer puxar seu cabelo para fora, eu recomendo verificar Manipulação de dados com R .
como isso difere de tapply (x, fator, diversão) ??
TMS
1
@Tomas ave preserva a ordenação e o comprimento. então você pode, por exemplo, adicionar um vetor de médias de grupo a um conjunto de dados, em uma etapa.
Eduardo Leoni
18
Uma forma de acelerar o código e eliminar os loops for.
em vez de loops for que percorrem um dataframe em busca de valores. apenas pegue um subconjunto do df com esses valores, muito mais rápido.
então, em vez de:
for(i in1:nrow(df)){if(df$column[i]== x){
df$column2[i]<- y
or any other similiar code
}}
faça algo assim:
df$column2[df$column1 == x]<- y
esse conceito básico é aplicável com muita frequência e é uma ótima maneira de se livrar de loops for
Há uma pequena armadilha aqui que costumava me apanhar o tempo todo. Se df $ column1 contiver valores NA, o subconjunto usando == extrairá quaisquer valores iguais a x e quaisquer NAs. Para evitar isso, use "% em%" em vez de "==".
Matt Parker
Matt, você está absolutamente certo e é algo que odeio, mas gosto do seu método. Eu geralmente verifico a coluna para NAs e, em seguida, removo-os com uma função rápida que fiz que pega uma coluna do dataframe e retorna o dataframe menos as linhas com NAs apenas nessa coluna.
Dan
essencialmente, reduzo um dataframe às colunas que preciso ter valores e, em seguida, uso na.omit para obter as linhas corretas e, em seguida, subconjunto do conjunto de dados original com apenas essas linhas. Apenas usar na.omit removeria qualquer linha de qualquer NA, mas posso estar enganado.
Dan
16
Às vezes, você precisa de rbindvários quadros de dados. do.call()vai deixar você fazer isso (alguém teve que me explicar isso quando fiz essa pergunta ao bind, pois não parece ser um uso óbvio).
Boa ideia: acho que isso geralmente é mais simples do que usar unsplit.
Richie Cotton
16
Na programação R (não sessões interativas), eu uso if (bad.condition) stop("message")um monte . Cada função começa com alguns deles e, à medida que trabalho nos cálculos, também os aponto. Acho que adquiri o hábito de usar assert()em C. Os benefícios são duplos. Em primeiro lugar, é muito mais rápido colocar o código em funcionamento com essas verificações. Em segundo lugar, e provavelmente o mais importante, é muito mais fácil trabalhar com o código existente quando você vê essas verificações em todas as telas do seu editor. Você não terá que se perguntar se x>0, ou confiar em um comentário afirmando que é ... você saberá , à primeira vista, que é.
Não é um mau hábito, e R oferece ainda outra maneira: stopfifnot(!bad.condition)que é mais concisa.
Dirk Eddelbuettel
13
A traceback()função é obrigatória quando você tem um erro em algum lugar e não o entende prontamente. Ele imprimirá um traço da pilha, muito útil, pois R não é muito prolixo por padrão.
Então, a configuração options(error=recover)permitirá que você "entre" na função que gera o erro e tente entender o que acontece exatamente, como se você tivesse total controle sobre ela e pudesse inserir um browser()nela.
Essas três funções podem realmente ajudar a depurar seu código.
options(error=recover)é meu método de depuração favorito.
Joshua Ulrich
12
Estou realmente surpreso que ninguém postou sobre aplicar, bater, lapidar e sensacionalmente. Uma regra geral que uso ao fazer coisas em R é que se eu tiver um loop for que está fazendo processamento de dados ou simulações, tento fatorá-lo e substituí-lo por um * apply. Algumas pessoas evitam as funções * apply porque acham que apenas funções de parâmetro único podem ser transmitidas. Nada poderia estar mais longe da verdade! Assim como passar funções com parâmetros como objetos de primeira classe em Javascript, você faz isso em R com funções anônimas. Por exemplo:
> sapply(rnorm(100,0,1), round)[1]11011-1-2022-2-101-101-10-100000[26]20-1-2001-1151-1011120-11-110-11[51]211-2-10-12-11-11-10-1-2110-1-11120[76]000-2-111-21-1111000-1-30-100011> sapply(rnorm(100,0,1), round(x,2))# How can we pass a parameter?
Error in match.fun(FUN): object 'x' not found
# Wrap your function call in an anonymous function to use parameters> sapply(rnorm(100,0,1),function(x){round(x,2)})[1]-0.05-1.74-0.09-1.230.69-1.430.760.550.96-0.47-0.81-0.47[13]0.270.320.47-1.28-1.44-1.930.51-0.82-0.06-1.411.23-0.26[25]0.22-0.04-2.170.60-0.10-0.920.132.621.03-1.33-1.73-0.08[37]0.45-0.930.400.051.09-1.23-0.350.620.01-1.081.70-1.27[49]0.550.60-1.461.08-1.88-0.150.210.060.53-1.16-2.13-0.03[61]0.33-1.070.980.62-0.01-0.53-1.17-0.28-0.950.71-0.58-0.03[73]-1.47-0.75-0.540.42-1.630.05-1.900.40-0.010.14-1.581.37[85]-1.00-0.901.69-0.11-2.19-0.741.34-0.75-0.51-0.99-0.36-1.63[97]-0.980.611.010.55# Note that anonymous functions aren't being called, but being passed.>function(){print('hello #rstats')}()function(){print('hello #rstats')}()> a =function(){print('hello #rstats')}> a
function(){print('hello #rstats')}> a()[1]"hello #rstats"
(Para aqueles que seguem #rstats, também postei isso lá).
Lembre-se de usar apply, sapply, lapply, tapply e do.call! Aproveite a vetorização de R. Você nunca deve ir até um monte de código R e ver:
N =10000
l = numeric()for(i in seq(1:N)){
sim <- rnorm(1,0,1)
l <- rbind(l, sim)}
Não apenas não é vetorizado, mas a estrutura do array em R não cresce como no Python (dobrando o tamanho quando o espaço acaba, IIRC). Portanto, cada etapa de rbind deve primeiro crescer l o suficiente para aceitar os resultados de rbind () e, em seguida, copiar todo o conteúdo de l anterior. Para se divertir, experimente o acima em R. Observe quanto tempo leva (você nem precisará do Rprof ou de qualquer função de tempo). Então tente
N=10000
l <- rnorm(N,0,1)
O seguinte também é melhor do que a primeira versão:
N =10000
l = numeric(N)for(i in seq(1:N)){
sim <- rnorm(1,0,1)
l[i]<- sim
}
apply, sapply, lapply e tapply são úteis. Se você quiser passar parâmetros para uma função nomeada como round, você pode simplesmente passá-lo junto com apply em vez de escrever uma função anônima. Tente "sapply (rnorm (10, 0, 1), round, digits = 2)" que resulta em "[1] -0,29 0,29 1,31 -0,06 -1,90 -0,84 0,21 0,02 0,23 -1,10".
Daniel
11
Seguindo o conselho de Dirk, estou postando exemplos isolados. Espero que não sejam muito "fofos" [inteligentes, mas não me importo] ou triviais para esse público.
Modelos lineares são o pão com manteiga de R. Quando o número de variáveis independentes é alto, temos duas escolhas. A primeira é usar lm.fit (), que recebe a matriz de design xea resposta y como argumentos, de maneira semelhante ao Matlab. A desvantagem dessa abordagem é que o valor de retorno é uma lista de objetos (coeficientes ajustados, resíduos, etc.), não um objeto da classe "lm", que pode ser bem resumido, usado para predição, seleção passo a passo, etc. O segundo abordagem é criar uma fórmula:
> A
X1 X2 X3 X4 y
10.968523630.338271070.2613322570.628170211.642532620.080127550.691598280.0879941580.937804810.980130430.101675450.381193040.8652098320.165016620.483087340.066994580.417564150.2580716160.340277750.7508766...>(f=paste("y ~",paste(names(A)[1:4],collapse=" + ")))[1]"y ~ X1 + X2 + X3 + X4"> lm(formula(f),data=A)
Call:
lm(formula = formula(f), data = A)
Coefficients:(Intercept) X1 X2 X3 X4
0.782360.95406-0.06738-0.43686-0.06644
Que tal se você escolher um por postagem e ilustrar com um exemplo? Podemos continuar por dias a fio e postar novos exemplos com novos comandos ... [BTW: Pelo que me lembro, você precisa de as.formula (paste (...)) para usar a fórmula. ]
Dirk Eddelbuettel
Você não precisa da criação de fórmula explicitamente para cobrir todas as colunas, pois o formulário "y ~. - 1" cobre isso. O "." significa 'todas as colunas, exceto a variável dependente, e o' - 1 'exclui a constante como em seu exemplo.
Dirk Eddelbuettel
Isso é correto para este exemplo específico, mas para X com ncols >> nrows, geralmente removo algumas variáveis independentes, especialmente nos estágios finais da análise. Nesse caso, criar uma fórmula a partir dos nomes dos quadros de dados ainda é útil.
gappy
10
Você pode atribuir um valor que retorna de um bloco if-else.
Em vez de, por exemplo
condition <- runif(1)>0.5if(condition) x <-1else x <-2
Você também pode fazer isso como x <- ifelse (condição, 1, 2), caso em que cada componente é vetorizado.
Shane
Shane, você poderia, mas a menos que você realmente grogue profundamente o que ifelse () faz, você provavelmente não deveria! É fácil de entender mal ...
Harlan
O que há de mágico nisso? É assim que as if-then-elseexpressões funcionam em qualquer linguagem funcional (não deve ser confundido com if-then-elseinstruções ). Muito semelhante ao ?:operador ternário de linguagens semelhantes a C.
Frank de
10
Como um novato total em R e um novato em estatísticas, adoro unclass()
imprimir todos os elementos de um quadro de dados como uma lista comum.
É muito útil dar uma olhada em um conjunto de dados completo de uma só vez para avaliar rapidamente quaisquer problemas potenciais.
CrossTable()do gmodelspacote fornece acesso fácil a crosstabs estilo SAS e SPSS, junto com os testes usuais (Chisq, McNemar, etc.). Basicamente, é uma xtabs()saída sofisticada e alguns testes adicionais - mas torna o compartilhamento da saída com os pagãos mais fácil.
Agradável!! Eu uso gmodels bastante, mas perdi aquele
Abhijit,
Boa resposta, qualquer coisa que possa me afastar de explicações excessivas de tabelas com os pagãos é um bom uso do tempo.
Stedy
7
Definitivamente system(). Ter acesso a todas as ferramentas unix (pelo menos no Linux / MacOSX) de dentro do ambiente R tornou-se rapidamente inestimável em meu fluxo de trabalho diário.
Isso está vinculado ao meu comentário anterior sobre conexões: você também pode usar pipe () para passar dados de ou para comandos Unix. Veja help(connections)para detalhes e exemplos.
Dirk Eddelbuettel
6
Aqui está uma solução alternativa irritante para converter um fator em um numérico. (Semelhante para outros tipos de dados também)
Talvez você quisesse dizer "em um vetor característico". Nesse caso, "as.character (old.var)" é mais simples.
Dirk Eddelbuettel
1
Sempre achei esse conselho (que pode ser lido pelo fator?) Equivocado. Você deve ter certeza de que old.var é um fator, e isso irá variar de acordo com as opções definidas para a sessão R. Usar as.numeric (as.character (old.var)) é mais seguro e mais limpo.
Eduardo Leoni de
Realmente não vale um downvote, mas tanto faz. Isso funciona para mim.
Ryan R. Rosario
Ryan - Você poderia consertar seu código? Se old.var <- fator (1: 2); seu código fornecerá [1] "1" "2" (não numérico.) talvez você quisesse dizer as.numeric (levels (old.var) [old.var])?
Eduardo Leoni de
3
Ou um pouco mais eficiente:as.numeric(levels(old.var))[old.var]
hadley de
6
Embora esta questão já esteja levantada há um tempo, descobri recentemente um grande truque no blog SAS e R para usar o comando cut. O comando é usado para dividir os dados em categorias e vou usar o conjunto de dados iris como um exemplo e dividi-lo em 10 categorias:
> irisSL <- iris$Sepal.Length
> str(irisSL)
num [1:150]5.14.94.74.655.44.654.44.9...> cut(irisSL,10)[1](5.02,5.38](4.66,5.02](4.66,5.02](4.3,4.66](4.66,5.02](5.38,5.74](4.3,4.66](4.66,5.02](4.3,4.66](4.66,5.02][11](5.38,5.74](4.66,5.02](4.66,5.02](4.3,4.66](5.74,6.1](5.38,5.74](5.38,5.74](5.02,5.38](5.38,5.74](5.02,5.38][21](5.38,5.74](5.02,5.38](4.3,4.66](5.02,5.38](4.66,5.02](4.66,5.02](4.66,5.02](5.02,5.38](5.02,5.38](4.66,5.02][31](4.66,5.02](5.38,5.74](5.02,5.38](5.38,5.74](4.66,5.02](4.66,5.02](5.38,5.74](4.66,5.02](4.3,4.66](5.02,5.38][41](4.66,5.02](4.3,4.66](4.3,4.66](4.66,5.02](5.02,5.38](4.66,5.02](5.02,5.38](4.3,4.66](5.02,5.38](4.66,5.02][51](6.82,7.18](6.1,6.46](6.82,7.18](5.38,5.74](6.46,6.82](5.38,5.74](6.1,6.46](4.66,5.02](6.46,6.82](5.02,5.38][61](4.66,5.02](5.74,6.1](5.74,6.1](5.74,6.1](5.38,5.74](6.46,6.82](5.38,5.74](5.74,6.1](6.1,6.46](5.38,5.74][71](5.74,6.1](5.74,6.1](6.1,6.46](5.74,6.1](6.1,6.46](6.46,6.82](6.46,6.82](6.46,6.82](5.74,6.1](5.38,5.74][81](5.38,5.74](5.38,5.74](5.74,6.1](5.74,6.1](5.38,5.74](5.74,6.1](6.46,6.82](6.1,6.46](5.38,5.74](5.38,5.74][91](5.38,5.74](5.74,6.1](5.74,6.1](4.66,5.02](5.38,5.74](5.38,5.74](5.38,5.74](6.1,6.46](5.02,5.38](5.38,5.74][101](6.1,6.46](5.74,6.1](6.82,7.18](6.1,6.46](6.46,6.82](7.54,7.9](4.66,5.02](7.18,7.54](6.46,6.82](7.18,7.54][111](6.46,6.82](6.1,6.46](6.46,6.82](5.38,5.74](5.74,6.1](6.1,6.46](6.46,6.82](7.54,7.9](7.54,7.9](5.74,6.1][121](6.82,7.18](5.38,5.74](7.54,7.9](6.1,6.46](6.46,6.82](7.18,7.54](6.1,6.46](5.74,6.1](6.1,6.46](7.18,7.54][131](7.18,7.54](7.54,7.9](6.1,6.46](6.1,6.46](5.74,6.1](7.54,7.9](6.1,6.46](6.1,6.46](5.74,6.1](6.82,7.18][141](6.46,6.82](6.82,7.18](5.74,6.1](6.46,6.82](6.46,6.82](6.46,6.82](6.1,6.46](6.46,6.82](6.1,6.46](5.74,6.1]10 Levels:(4.3,4.66](4.66,5.02](5.02,5.38](5.38,5.74](5.74,6.1](6.1,6.46](6.46,6.82](6.82,7.18]...(7.54,7.9]
Outro truque. Alguns pacotes, como o glmnet, usam apenas como entradas a matriz de design e a variável de resposta. Se alguém deseja ajustar um modelo com todas as interações entre recursos, não pode usar a fórmula "y ~. ^ 2". O uso expand.grid()nos permite tirar proveito da poderosa indexação de matriz e operações de vetor de R.
Se uma função de modelagem não aceita uma fórmula (o que é muito raro!), Não seria melhor construir a matriz de design com model.matrix?
hadley
Agradável. Não sabia da existência desta função. A função acima é equivalente a model.matrix (~. ^ 2 -1, X) Mas em relação à passagem de matrizes, além de glmnet, é frequente para mim passar ponteiros de array para funções C personalizadas. Na verdade, eu não saberia como passar uma fórmula para uma função. Você tem um exemplo de brinquedo?
gappy
5
Um dos meus truques favoritos, se não um tanto heterodoxos, é o uso de eval()e parse(). Este exemplo talvez ilustra como pode ser útil
NY.Capital <-'Albany'
state <-'NY'
parameter <-'Capital'
eval(parse(text=paste(state, parameter, sep='.')))[1]"Albany"
Esse tipo de situação ocorre com mais frequência do que não e o uso de eval()e parse()pode ajudar a resolvê-lo. É claro que agradeço qualquer feedback sobre formas alternativas de codificar isso.
Isso também pode ser feito com elementos vetoriais nomeados.
Dirk Eddelbuettel
3
biblioteca (fortunas); fortuna (106) Se a resposta for parse (), você geralmente deve repensar a questão. - Thomas Lumley R-help (fevereiro de 2005)
Eduardo Leoni
Aqui está um exemplo em que eval () e parse () podem ser úteis. Isso envolve um pacote Bioconductor, por exemplo, hgu133a.db e onde você está tentando obter várias informações sobre um id de conjunto de probes. Por exemplo: library (hgu133a.db) parameter <- 'SYMBOL' mget ('202431_s_at', env = eval (parse (text = paste ('hgu133a', parameter, sep = '')))) parameter <- 'ENTREZID 'mget (' 202431_s_at ', env = eval (parse (text = paste (' hgu133a ', parameter, sep =' '))))
andrewj
Como Dirk diz, isso é melhor feito com elementos vetoriais nomeados, ou `get (paste (paste (state, parameter, sep = '.'))`
hadley
@Hadley, não sabia que você poderia usar get () dessa forma. Obrigado.
andrewj
5
set.seed() define o estado do gerador de número aleatório.
for (f in files) {if (! (f == 'mysource.r')) {print (paste ('Sourcing', f)) source (paste (d, f, sep = ''))}}
Eu uso o código acima para fornecer todos os arquivos em um diretório na inicialização com vários programas utilitários que uso em minha sessão interativa com R. Tenho certeza de que existem maneiras melhores, mas acho que é útil para o meu trabalho. A linha que faz isso é a seguinte.
Obrigado. Estive analisando um ou dois tópicos sobre roxygen e parece que provavelmente estou no nível em que devo tentar escrever um pacote simples para uso próprio.
mcheema
3
Para realizar uma operação em várias variáveis em um quadro de dados. Isso é roubado de subset.data.frame.
Isso parece legal no início, mas esse tipo de código causará muitos problemas a longo prazo. É sempre melhor ser explícito.
hadley
hum, tenho usado esse truque bastante ultimamente. Você poderia ser mais específico sobre seu problema ilimitado?
Ian Fellows de
Talvez hadley esteja sugerindo usar o pacote plyr em vez disso?
Christopher DuBois
3
Não, esta não é uma sugestão velada para usar o plyr. O problema básico com o seu código é que ele é semanticamente preguiçoso - em vez de fazer o usuário soletrar explicitamente o que deseja, você faz uma "mágica" para adivinhar. O problema com isso é que torna a função muito difícil de programar - ou seja, é difícil escrever uma função que chame get.varssem pular através de um monte de arcos.
hadley
3
Já postei isso uma vez, mas uso tanto que pensei em postar novamente. É apenas uma pequena função para retornar os nomes e números de posição de um data.frame. Não é nada especial com certeza, mas quase nunca consigo terminar uma sessão sem usá-lo várias vezes.
##creates an object from a data.frame listing the column names and location
Respostas:
str()
informa a estrutura de qualquer objeto.fonte
dir()
- faz mais sentido.str
também é abreviação destring
em muitos idiomas.class()
? Parece revelar um tipo de informação semelhante. Por que existem dois comandos semelhantes?class()
é apenas uma pequena parte das informações que sãostr()
exibidasUma função muito útil que uso com frequência é dput (), que permite fazer dump de um objeto na forma de código R.
Pode ser muito útil postar blocos de dados facilmente reproduzíveis quando você pedir ajuda ou editar ou reordenar os níveis de um fator.
fonte
head () e tail () para obter a primeira e a última parte de um dataframe, vetor, matriz, função, etc. Especialmente com grandes frames de dados, esta é uma maneira rápida de verificar se ele foi carregado corretamente.
fonte
Um recurso interessante: a leitura de dados usa conexões que podem ser arquivos locais, arquivos remotos acessados via http, canais de outros programas ou mais.
Como um exemplo simples, considere este acesso para N = 10 inteiros aleatórios entre min = 100 e max = 200 de random.org (que fornece números aleatórios verdadeiros com base no ruído atmosférico em vez de um gerador de números pseudo-aleatórios):
Como um aparte, o pacote aleatório fornece várias funções de conveniência para acessar random.org .
fonte
Acho que estou usando
with()
ewithin()
cada vez mais. Chega de$
bagunçar meu código e não é necessário começar a anexar objetos ao caminho de pesquisa. Mais a sério, acho quewith()
etc. tornam a intenção dos meus scripts de análise de dados muito mais clara.with()
configura um ambiente no qual a expressão R é avaliada.within()
faz a mesma coisa, mas permite que você modifique o objeto de dados usado para criar o ambiente.Algo que não percebi quando usei pela primeira vez
within()
é que você deve fazer uma atribuição como parte da expressão avaliada e atribuir o objeto retornado (como acima) para obter o efeito desejado.fonte
Truque de entrada de dados = pacote RGoogleDocs
http://www.omegahat.org/RGoogleDocs/
Eu descobri que as planilhas do Google são uma maneira fantástica de todos os colaboradores estarem na mesma página. Além disso, o Formulários Google permite capturar dados dos entrevistados e gravá-los sem esforço em uma planilha do Google. Como os dados mudam com frequência e quase nunca são finais, é muito preferível que R leia uma planilha do Google diretamente do que fazer download de arquivos csv e lê-los.
Não consigo lembrar qual, mas um ou dois dos seguintes comandos levam vários segundos.
getGoogleAuth
getGoogleDocsConnection
getWorksheets
fonte
Use crases para fazer referência a nomes não padronizados.
Nesse caso, df [, "1"] também funcionaria. Mas as marcações para trás funcionam dentro das fórmulas!
[Editar] Dirk pergunta por que alguém daria nomes inválidos? Eu não sei! Mas certamente encontro esse problema na prática com bastante frequência. Por exemplo, usando o pacote reshape do hadley:
fonte
read.table
quandocheck.names
é falso - ou seja, quando você deseja trabalhar com os nomes das colunas originais.Não sei se isso é / não é bem conhecido, mas algo de que definitivamente tirei vantagem são os recursos de passagem por referência dos ambientes.
Para este exemplo, não faz sentido por que seria útil, mas se você estiver passando objetos grandes ao redor, pode ajudar.
fonte
Minha nova coisa favorita é a biblioteca foreach. Ele permite que você faça todas as coisas legais de aplicação, mas com uma sintaxe um pouco mais fácil:
A melhor parte é que, se você estiver fazendo algo que realmente requer uma quantidade significativa de tempo, poderá alternar de
%do%
para%dopar%
(com a biblioteca de back-end apropriada) para paralelizar instantaneamente, mesmo em um cluster. Muito habilidoso.fonte
Eu faço muitas manipulações básicas de dados, então aqui estão duas funções integradas ( transformar , subconjunto ) e uma biblioteca ( sqldf ) que eu uso diariamente.
criar dados de vendas de amostra
use transform () para adicionar uma coluna
use subset () para dividir os dados
use sqldf () para dividir e agregar com SQL
O pacote sqldf fornece uma interface SQL para quadros de dados R
Realize uma agregação ou GROUP BY
Para uma funcionalidade mais sofisticada do tipo mapa-redução em frames de dados, verifique o pacote plyr . E se encontrar-se querer puxar seu cabelo para fora, eu recomendo verificar Manipulação de dados com R .
fonte
Subconjuntos de 'x []' são calculados, em que cada subconjunto consiste nas observações com os mesmos níveis de fator. Uso: ave (x, ..., FUN = média)
Eu uso isso o tempo todo. (por exemplo , nesta resposta aqui também )
fonte
Uma forma de acelerar o código e eliminar os loops for.
em vez de loops for que percorrem um dataframe em busca de valores. apenas pegue um subconjunto do df com esses valores, muito mais rápido.
então, em vez de:
faça algo assim:
esse conceito básico é aplicável com muita frequência e é uma ótima maneira de se livrar de loops for
fonte
Às vezes, você precisa de
rbind
vários quadros de dados.do.call()
vai deixar você fazer isso (alguém teve que me explicar isso quando fiz essa pergunta ao bind, pois não parece ser um uso óbvio).fonte
unsplit
.Na programação R (não sessões interativas), eu uso
if (bad.condition) stop("message")
um monte . Cada função começa com alguns deles e, à medida que trabalho nos cálculos, também os aponto. Acho que adquiri o hábito de usarassert()
em C. Os benefícios são duplos. Em primeiro lugar, é muito mais rápido colocar o código em funcionamento com essas verificações. Em segundo lugar, e provavelmente o mais importante, é muito mais fácil trabalhar com o código existente quando você vê essas verificações em todas as telas do seu editor. Você não terá que se perguntar sex>0
, ou confiar em um comentário afirmando que é ... você saberá , à primeira vista, que é.PS. meu primeiro post aqui. Seja gentil!
fonte
stopfifnot(!bad.condition)
que é mais concisa.A
traceback()
função é obrigatória quando você tem um erro em algum lugar e não o entende prontamente. Ele imprimirá um traço da pilha, muito útil, pois R não é muito prolixo por padrão.Então, a configuração
options(error=recover)
permitirá que você "entre" na função que gera o erro e tente entender o que acontece exatamente, como se você tivesse total controle sobre ela e pudesse inserir umbrowser()
nela.Essas três funções podem realmente ajudar a depurar seu código.
fonte
options(error=recover)
é meu método de depuração favorito.Estou realmente surpreso que ninguém postou sobre aplicar, bater, lapidar e sensacionalmente. Uma regra geral que uso ao fazer coisas em R é que se eu tiver um loop for que está fazendo processamento de dados ou simulações, tento fatorá-lo e substituí-lo por um * apply. Algumas pessoas evitam as funções * apply porque acham que apenas funções de parâmetro único podem ser transmitidas. Nada poderia estar mais longe da verdade! Assim como passar funções com parâmetros como objetos de primeira classe em Javascript, você faz isso em R com funções anônimas. Por exemplo:
(Para aqueles que seguem #rstats, também postei isso lá).
Lembre-se de usar apply, sapply, lapply, tapply e do.call! Aproveite a vetorização de R. Você nunca deve ir até um monte de código R e ver:
Não apenas não é vetorizado, mas a estrutura do array em R não cresce como no Python (dobrando o tamanho quando o espaço acaba, IIRC). Portanto, cada etapa de rbind deve primeiro crescer l o suficiente para aceitar os resultados de rbind () e, em seguida, copiar todo o conteúdo de l anterior. Para se divertir, experimente o acima em R. Observe quanto tempo leva (você nem precisará do Rprof ou de qualquer função de tempo). Então tente
O seguinte também é melhor do que a primeira versão:
fonte
Seguindo o conselho de Dirk, estou postando exemplos isolados. Espero que não sejam muito "fofos" [inteligentes, mas não me importo] ou triviais para esse público.
Modelos lineares são o pão com manteiga de R. Quando o número de variáveis independentes é alto, temos duas escolhas. A primeira é usar lm.fit (), que recebe a matriz de design xea resposta y como argumentos, de maneira semelhante ao Matlab. A desvantagem dessa abordagem é que o valor de retorno é uma lista de objetos (coeficientes ajustados, resíduos, etc.), não um objeto da classe "lm", que pode ser bem resumido, usado para predição, seleção passo a passo, etc. O segundo abordagem é criar uma fórmula:
fonte
Você pode atribuir um valor que retorna de um bloco if-else.
Em vez de, por exemplo
você pode fazer
Exatamente como isso funciona é magia profunda.
fonte
if-then-else
expressões funcionam em qualquer linguagem funcional (não deve ser confundido comif-then-else
instruções ). Muito semelhante ao?:
operador ternário de linguagens semelhantes a C.Como um novato total em R e um novato em estatísticas, adoro
unclass()
imprimir todos os elementos de um quadro de dados como uma lista comum.É muito útil dar uma olhada em um conjunto de dados completo de uma só vez para avaliar rapidamente quaisquer problemas potenciais.
fonte
CrossTable()
dogmodels
pacote fornece acesso fácil a crosstabs estilo SAS e SPSS, junto com os testes usuais (Chisq, McNemar, etc.). Basicamente, é umaxtabs()
saída sofisticada e alguns testes adicionais - mas torna o compartilhamento da saída com os pagãos mais fácil.fonte
Definitivamente
system()
. Ter acesso a todas as ferramentas unix (pelo menos no Linux / MacOSX) de dentro do ambiente R tornou-se rapidamente inestimável em meu fluxo de trabalho diário.fonte
help(connections)
para detalhes e exemplos.Aqui está uma solução alternativa irritante para converter um fator em um numérico. (Semelhante para outros tipos de dados também)
fonte
as.numeric(levels(old.var))[old.var]
Embora esta questão já esteja levantada há um tempo, descobri recentemente um grande truque no blog SAS e R para usar o comando
cut
. O comando é usado para dividir os dados em categorias e vou usar o conjunto de dados iris como um exemplo e dividi-lo em 10 categorias:fonte
Outro truque. Alguns pacotes, como o glmnet, usam apenas como entradas a matriz de design e a variável de resposta. Se alguém deseja ajustar um modelo com todas as interações entre recursos, não pode usar a fórmula "y ~. ^ 2". O uso
expand.grid()
nos permite tirar proveito da poderosa indexação de matriz e operações de vetor de R.fonte
model.matrix
?Um dos meus truques favoritos, se não um tanto heterodoxos, é o uso de
eval()
eparse()
. Este exemplo talvez ilustra como pode ser útilEsse tipo de situação ocorre com mais frequência do que não e o uso de
eval()
eparse()
pode ajudar a resolvê-lo. É claro que agradeço qualquer feedback sobre formas alternativas de codificar isso.fonte
set.seed()
define o estado do gerador de número aleatório.Por exemplo:
fonte
Para quem está escrevendo C, ser chamado de R:
.Internal(inspect(...))
é útil. Por exemplo:fonte
d = '~ / Código R / Biblioteca /'
files = list.files (d, '. r $')
for (f in files) {if (! (f == 'mysource.r')) {print (paste ('Sourcing', f)) source (paste (d, f, sep = ''))}}
Eu uso o código acima para fornecer todos os arquivos em um diretório na inicialização com vários programas utilitários que uso em minha sessão interativa com R. Tenho certeza de que existem maneiras melhores, mas acho que é útil para o meu trabalho. A linha que faz isso é a seguinte.
fonte ("~ / Código R / Biblioteca / mysource.r")
fonte
Para realizar uma operação em várias variáveis em um quadro de dados. Isso é roubado de subset.data.frame.
fonte
get.vars
sem pular através de um monte de arcos.Já postei isso uma vez, mas uso tanto que pensei em postar novamente. É apenas uma pequena função para retornar os nomes e números de posição de um data.frame. Não é nada especial com certeza, mas quase nunca consigo terminar uma sessão sem usá-lo várias vezes.
namesind = function (df) {
}
ni <- namesind
fonte
data.frame(VAR = names(df), COL = seq_along(df))