Afin de partager d'autres trucs et astuces pour R , quelle est votre fonctionnalité ou astuce la plus utile? Vectorisation intelligente? Entrée / sortie de données? Visualisation et graphisme? Analyses statistiques? Fonctions spéciales? L'environnement interactif lui-même?
Un article par article, et nous verrons si nous obtenons un gagnant au moyen de votes.
[Edit 25-Aug 2008]: Donc après une semaine, il semble que le simple ait str()gagné le sondage. Comme j'aime la recommander moi-même, c'est une réponse facile à accepter.
@Dirk: "wiki de la communauté" signifie "appartenant à la communauté", ce n'est pas un synonyme de "question de sondage". N'écoutez pas la police du wiki de la communauté.
@ars: c'est une question qui n'a pas de réponse définitive . Ergo faites-le CW.
dmckee --- chaton ex-modérateur
2
@JD Long commentaire hilarant. malheureusement, il était caché derrière le pli. Je veux dire que répondre à des questions R difficiles ne paie pas vraiment en termes de répétitions. Donc ça me va si les gars qui ont posé de jolies questions qui mettent R sur la carte obtiennent enfin du crédit. De plus, cela est certainement plus utile pour les utilisateurs de R que pour les programmeurs C,
quelle
Réponses:
64
str() vous indique la structure de n'importe quel objet.
Ah, strc'est aussi l'abréviation de stringdans de nombreuses langues.
Hamish Grubijan
Pourquoi pas class()? Il semble révéler un type d'informations similaire. Pourquoi y a-t-il deux commandes similaires?
hhh
1
class()est juste une petite partie des informations qui str()s'affichent
hadley
64
Une fonction très utile que j'utilise souvent est dput (), qui vous permet de vider un objet sous la forme de code 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")
Il peut être très utile de publier des blocs de données facilement reproductibles lorsque vous demandez de l'aide, ou pour modifier ou réorganiser les niveaux d'un facteur.
head () et tail () pour obtenir la première et la dernière partie d'un dataframe, d'un vecteur, d'une matrice, d'une fonction, etc. Surtout avec de grandes trames de données, c'est un moyen rapide de vérifier qu'il a bien chargé.
Une fonctionnalité intéressante: la lecture des données utilise des connexions qui peuvent être des fichiers locaux, des fichiers distants accessibles via http, des tubes à partir d'autres programmes ou plus.
À titre d'exemple simple, considérons cet accès pour N = 10 entiers aléatoires entre min = 100 et max = 200 de random.org (qui fournit de vrais nombres aléatoires basés sur le bruit atmosphérique plutôt qu'un générateur de nombres pseudo aléatoires):
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 V2
11651432107118310313241911005138185
R>
En passant, le package random fournit plusieurs fonctions pratiques pour accéder à random.org .
BTW-- Je suggère que vous devriez faire selfanswers CW si (1) vous vous ne faites pas les publier rapidement et (2) la question CW. Sinon, il semble que vous essayez de jouer avec le système de représentation. YMMV et tout ça.
dmckee --- ex-moderator chaton
1
Il ne s'agit pas de jouer avec le système, mais simplement de faire démarrer les choses. Il est toujours libre d'accepter toute autre réponse.
ars
2
@ars: Il est libre d'accepter celui-ci. Je ne vais pas non plus essayer de le forcer à le wiki s'il a gagné; t suivre mon conseil. Mais je ne publierai pas de réponse personnelle préparée sans le marquer sur le wiki, et je ne voterai pas pour une sans elle non plus. Prenez ça pour ce que ça vaut.
dmckee --- ex-moderator chaton
4
@Dirk: il est tout à fait acceptable, même encouragé par Jeff et Joel, de répondre à votre propre question. Il n'y a AUCUNE exigence, pas même informelle, pour rendre votre réponse CW. Vous ne jouez clairement pas avec le système. Encore une fois, ignorez simplement la police du wiki de la communauté.
Juliet
8
Je dois admettre qu'une partie du but du site est de fournir les meilleures réponses aux problèmes courants et une ressource générale. Poser des questions et fournir une bonne réponse peut aider à renforcer un sujet. Ceci est particulièrement utile avec les nouvelles / petites balises telles que R.
kpierce8
35
Je trouve que je me sers with()et de within()plus en plus. Plus $besoin de jeter mon code et il n'est pas nécessaire de commencer à attacher des objets au chemin de recherche. Plus sérieusement, je trouve que with()etc. rendent l' intention de mes scripts d'analyse de données beaucoup plus claire.
> 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()met en place un environnement dans lequel l'expression R est évaluée. within()fait la même chose mais vous permet de modifier l'objet de données utilisé pour créer l'environnement.
> df <- within(df, C <- rpois(10, lambda =2))> head(df)
A B C
10.62635571-0.5830079120.04810539-0.4525522130.397069791.5966184340.95802501-0.8193090250.76772541-1.9450738260.213350060.21138814
Ce que je n'avais pas réalisé lors de ma première utilisation, within()c'est que vous devez faire une affectation dans le cadre de l'expression évaluée et affecter l'objet renvoyé (comme ci-dessus) pour obtenir l'effet souhaité.
J'ai trouvé que les feuilles de calcul Google étaient un moyen fantastique pour tous les collaborateurs d'être sur la même page. En outre, Google Forms permet de capturer les données des répondants et de les écrire sans effort dans une feuille de calcul Google. Étant donné que les données changent fréquemment et ne sont presque jamais définitives, il est de loin préférable que R lise directement une feuille de calcul Google plutôt que de télécharger des fichiers csv et de les lire.
# 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)
Je ne peux pas me souvenir de laquelle mais une ou deux des commandes suivantes prend plusieurs secondes.
[Modifier] Dirk demande pourquoi on donnerait des noms invalides? Je ne sais pas! Mais je rencontre certainement ce problème assez souvent dans la pratique. Par exemple, en utilisant le package reshape de 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
Ok, mais pourquoi auriez-vous besoin de remplacer les noms syntaxiquement valides (comme x ou y) par des noms non valides (comme 1 ou 2) nécessitant les rétrospectives?
Dirk Eddelbuettel
3
Il est également utile read.tablelorsque la valeur check.namesest false, c'est-à-dire lorsque vous souhaitez travailler avec les noms de colonne d'origine.
hadley
25
Je ne sais pas à quel point cela est / n'est pas connu, mais j'ai certainement profité des capacités de passage par référence des environnements.
Ma nouvelle chose préférée est la bibliothèque foreach. Il vous permet de faire toutes les bonnes choses d'application, mais avec une syntaxe un peu plus simple:
La meilleure partie est que si vous faites quelque chose qui prend en fait beaucoup de temps, vous pouvez passer de %do%à %dopar%(avec la bibliothèque backend appropriée) pour paralléliser instantanément, même à travers un cluster. Très lisse.
Je fais beaucoup de manipulation de base des données, voici donc deux fonctions intégrées ( transformation , sous - ensemble ) et une bibliothèque ( sqldf ) que j'utilise quotidiennement.
créer des exemples de données de vente
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
utilisez transform () pour ajouter une colonne
## 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...
utiliser sqldf () pour découper et agréger avec SQL
Le package sqldf fournit une interface SQL aux trames de données 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
Effectuer une agrégation 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
Pour une fonctionnalité de réduction de carte plus sophistiquée sur les trames de données, consultez le package plyr . Et si vous trouvez vouloir tirer vos cheveux, je vous recommande de vérifier Manipulation de données avec R .
Les sous-ensembles de «x []» sont moyennés, chaque sous-ensemble étant constitué de ces observations avec les mêmes niveaux de facteurs. Utilisation: ave (x, ..., FUN = mean)
en quoi cela diffère-t-il de tapply (x, factor, fun) ??
TMS
1
@Tomas ave préserve l'ordre et la longueur. vous pouvez, par exemple, ajouter un vecteur de moyennes de groupe à un jeu de données, en une seule étape.
Eduardo Leoni
18
Un moyen d'accélérer le code et d'éliminer les boucles for.
au lieu de boucles for qui parcourent une trame de données à la recherche de valeurs. prenez simplement un sous-ensemble du df avec ces valeurs, beaucoup plus rapidement.
donc au lieu de:
for(i in1:nrow(df)){if(df$column[i]== x){
df$column2[i]<- y
or any other similiar code
}}
faites quelque chose comme ça:
df$column2[df$column1 == x]<- y
ce concept de base s'applique extrêmement souvent et constitue un excellent moyen de se débarrasser des boucles for
Il y a un petit piège ici qui me rattrapait tout le temps. Si df $ column1 contient des valeurs NA, le sous-ensemble utilisant == extraira toutes les valeurs égales à x et toutes les NA. Pour éviter cela, utilisez "% in%" au lieu de "==".
Matt Parker
Matt tu as absolument raison et c'est quelque chose que je déteste, j'aime ta méthode quand même. Je vérifie généralement la colonne pour les NA, puis je les supprime avec une fonction rapide que j'ai créée qui prend une colonne de dataframe et renvoie le dataframe moins les lignes avec NA dans cette colonne.
Dan
essentiellement, je coupe un dataframe aux colonnes dont j'ai besoin pour avoir des valeurs puis utilise na.omit pour obtenir les lignes correctes, puis sous-ensemble le jeu de données d'origine avec seulement ces lignes. Le simple fait d'utiliser na.omit supprimerait n'importe quelle ligne avec n'importe quel NA, mais je pourrais me tromper.
Dan
16
Parfois, vous avez besoin de rbindplusieurs trames de données. do.call()vous laissera faire cela (quelqu'un a dû m'expliquer cela lorsque bind j'ai posé cette question, car cela ne semble pas être une utilisation évidente).
Bon appel: je trouve que c'est souvent plus simple que d'utiliser unsplit.
Richie Cotton
16
Dans la programmation R (pas de sessions interactives), j'utiliser if (bad.condition) stop("message")un grand nombre . Chaque fonction commence par quelques-uns de ceux-ci, et au fur et à mesure que je travaille sur des calculs, je les ajoute également. Je suppose que j'ai pris l'habitude d'utiliser assert()en C. Les avantages sont doubles. Premièrement, il est beaucoup plus rapide d'obtenir du code fonctionnel avec ces vérifications en place. Deuxièmement, et probablement plus important, il est beaucoup plus facile de travailler avec du code existant lorsque vous voyez ces vérifications sur chaque écran de votre éditeur. Vous n'aurez pas à se demander si x>0, ou faire confiance à un commentaire indiquant qu'il est ... vous savez , d'un coup d' oeil, que ce soit.
Ce n'est pas une mauvaise habitude, et R propose encore une autre manière: stopfifnot(!bad.condition)qui est plus concise.
Dirk Eddelbuettel
13
La traceback()fonction est indispensable lorsque vous avez une erreur quelque part et que vous ne la comprenez pas facilement. Il imprimera une trace de la pile, très utile car R n'est pas très verbeux par défaut.
Ensuite, le paramétrage options(error=recover)vous permettra "d'entrer" dans la fonction générant l'erreur et d'essayer de comprendre ce qui se passe exactement, comme si vous en aviez le contrôle total et que vous pouviez y mettre un browser().
Ces trois fonctions peuvent vraiment vous aider à déboguer votre code.
options(error=recover)est ma méthode de débogage préférée.
Joshua Ulrich
12
Je suis vraiment surpris que personne n'ait posté sur Apply, Tapply, Laply, and Sapply. Une règle générale que j'utilise lorsque je fais des choses dans R est que si j'ai une boucle for qui traite des données ou des simulations, j'essaye de la factoriser et de la remplacer par un * apply. Certaines personnes hésitent à utiliser les fonctions * apply parce qu'elles pensent que seules des fonctions à paramètre unique peuvent être transmises. Rien ne pourrait être plus éloigné de la vérité! Comme pour transmettre des fonctions avec des paramètres en tant qu'objets de première classe en Javascript, vous faites cela en R avec des fonctions anonymes. Par exemple:
> 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"
(Pour ceux qui suivent #rstats, je l'ai également posté ici).
N'oubliez pas, utilisez apply, sapply, lapply, tapply et do.call! Profitez de la vectorisation de R. Vous ne devriez jamais marcher jusqu'à un tas de code R et voir:
N =10000
l = numeric()for(i in seq(1:N)){
sim <- rnorm(1,0,1)
l <- rbind(l, sim)}
Non seulement cela n'est pas vectorisé, mais la structure du tableau dans R n'est pas développée comme elle l'est en Python (doubler la taille lorsque l'espace est épuisé, IIRC). Donc, chaque étape de rbind doit d'abord croître suffisamment pour accepter les résultats de rbind (), puis copier tout le contenu précédent. Pour le plaisir, essayez ce qui précède dans R. Notez combien de temps cela prend (vous n'aurez même pas besoin de Rprof ou de toute fonction de minutage). Puis essayez
N=10000
l <- rnorm(N,0,1)
Ce qui suit est également meilleur que la première version:
N =10000
l = numeric(N)for(i in seq(1:N)){
sim <- rnorm(1,0,1)
l[i]<- sim
}
appliquer, sapply, lapply et tapply sont utiles. Si vous voulez passer des paramètres à une fonction nommée comme round, vous pouvez simplement le transmettre avec apply au lieu d'écrire une fonction anonyme. Essayez "sapply (rnorm (10, 0, 1), round, digits = 2)" qui renvoie "[1] -0.29 0.29 1.31 -0.06 -1.90 -0.84 0.21 0.02 0.23 -1.10".
Daniel
11
Sur les conseils de Dirk, je publie des exemples uniques. J'espère qu'ils ne sont pas trop "mignons" [intelligents, mais je m'en fiche] ou triviaux pour ce public.
Les modèles linéaires sont le pain et le beurre de R. Lorsque le nombre de variables indépendantes est élevé, on a deux choix. La première consiste à utiliser lm.fit (), qui reçoit la matrice de conception x et la réponse y comme arguments, de la même manière que Matlab. L'inconvénient de cette approche est que la valeur de retour est une liste d'objets (coefficients ajustés, résidus, etc.), pas un objet de classe "lm", qui peut être bien résumé, utilisé pour la prédiction, la sélection par étapes, etc. l'approche consiste à créer une formule:
> 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
Et si vous en choisissez un par article et que vous l'illustriez avec un exemple? Nous pouvons alors continuer pendant des jours et poster de nouveaux exemples avec de nouvelles commandes ... [BTW: Si je me souviens bien, vous avez besoin de as.formula (coller (...)) pour l'utilisation de la formule. ]
Dirk Eddelbuettel
Vous n'avez pas besoin de la création de formule explicite pour couvrir toutes les colonnes car la forme "y ~. - 1" le couvre. Le "." signifie «toutes les colonnes sauf la variable dépendante, et le« - 1 »exclut la constante comme dans votre exemple.
Dirk Eddelbuettel
C'est vrai pour cet exemple spécifique, mais pour X avec ncols >> nrows, je supprime souvent certaines variables indépendantes, en particulier dans les dernières étapes de l'analyse. Dans ce cas, la création d'une formule à partir des noms de bloc de données est toujours pratique.
gappy
10
Vous pouvez attribuer une valeur renvoyée par un bloc if-else.
Au lieu de, par exemple
condition <- runif(1)>0.5if(condition) x <-1else x <-2
tu peux faire
x <-if(condition)1else2
La façon exacte dont cela fonctionne est une magie profonde.
Vous pouvez également faire cela comme x <- ifelse (condition, 1, 2), auquel cas chaque composant est vectorisé.
Shane
Shane, tu peux, mais à moins que tu ne saches vraiment ce que fait ifelse (), tu ne devrais probablement pas! C'est facile à mal comprendre ...
Harlan
Qu'est-ce qui est magique à ce sujet? C'est juste la façon dont les if-then-elseexpressions fonctionnent dans n'importe quel langage fonctionnel (à ne pas confondre avec les if-then-elseinstructions ). Très similaire à l' ?:opérateur ternaire des langages de type C.
Frank
10
En tant que noob total pour R et novice en statistiques que j'aime unclass()
imprimer tous les éléments d'un bloc de données sous forme de liste ordinaire.
C'est très pratique pour jeter un coup d'œil à un ensemble de données complet en une seule fois afin de détecter rapidement tout problème potentiel.
CrossTable()du gmodelspackage fournit un accès facile aux tableaux croisés de type SAS et SPSS, ainsi qu'aux tests habituels (Chisq, McNemar, etc.). Fondamentalement, c'est xtabs()avec une sortie sophistiquée et des tests supplémentaires - mais cela facilite le partage de la sortie avec les païens.
Agréable!! J'utilise pas mal de gmodels, mais j'ai raté celui-là
Abhijit
Bonne réponse, tout ce qui peut m'empêcher d'expliquer excessivement les tables avec les païens est une bonne utilisation du temps.
Stedy
7
Définitivement system(). Pouvoir accéder à tous les outils unix (au moins sous Linux / MacOSX) depuis l'intérieur de l'environnement R est rapidement devenu inestimable dans mon flux de travail quotidien.
Cela rejoint mon commentaire précédent sur les connexions: vous pouvez également utiliser pipe () pour transmettre des données depuis ou vers des commandes Unix. Voir help(connections)pour des détails et des exemples.
Dirk Eddelbuettel
6
Voici une solution de contournement ennuyeuse pour convertir un facteur en numérique. (Similaire pour d'autres types de données également)
Peut-être que vous vouliez dire "dans un caractère" vecteur. Dans ce cas, "as.character (old.var)" est plus simple.
Dirk Eddelbuettel
1
J'ai toujours pensé que ce conseil (qui peut être lu à? Factor) était erroné. Vous devez être sûr que old.var est un facteur, et cela variera en fonction des options que vous avez définies pour la session R. Utiliser as.numeric (as.character (old.var)) est à la fois plus sûr et plus propre.
Eduardo Leoni
Vaut vraiment pas un vote négatif, mais peu importe. Cela fonctionne pour moi.
Ryan R. Rosario
Ryan - Pourriez-vous corriger votre code? Si old.var <- facteur (1: 2); votre code donnera [1] "1" "2" (pas numérique.) peut-être que vous vouliez dire as.numeric (niveaux (old.var) [old.var])?
Eduardo Leoni
3
Ou un peu plus efficacement:as.numeric(levels(old.var))[old.var]
hadley
6
Bien que cette question soit posée depuis un certain temps, j'ai récemment découvert une excellente astuce sur le blog SAS et R pour utiliser la commande cut. La commande est utilisée pour diviser les données en catégories et je vais utiliser le jeu de données iris comme exemple et le diviser en 10 catégories:
> 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]
Un autre truc. Certains packages, comme glmnet, ne prennent comme entrées que la matrice de conception et la variable de réponse. Si l'on veut ajuster un modèle avec toutes les interactions entre les caractéristiques, elle ne peut pas utiliser la formule "y ~. ^ 2". L'utilisation expand.grid()nous permet de tirer parti de la puissante indexation de tableau et des opérations vectorielles de R.
Si une fonction de modélisation n'accepte pas une formule (ce qui est très rare!), Ne serait-il pas préférable de construire la matrice de conception avec model.matrix?
hadley
Joli. Je ne connaissais pas l'existence de cette fonction. La fonction ci-dessus est équivalente à model.matrix (~. ^ 2 -1, X) Mais en ce qui concerne le passage de matrices, mis à part glmnet, il m'est fréquent de passer des pointeurs de tableau à des fonctions C personnalisées. En effet, je ne saurais pas comment passer une formule à une fonction. Avez-vous un exemple de jouet?
gappy
5
L'une de mes astuces préférées, sinon quelque peu peu orthodoxes, est l'utilisation de eval()et parse(). Cet exemple illustre peut-être comment cela peut être utile
NY.Capital <-'Albany'
state <-'NY'
parameter <-'Capital'
eval(parse(text=paste(state, parameter, sep='.')))[1]"Albany"
Ce type de situation se produit le plus souvent et l'utilisation de eval() et parse()peut aider à y remédier. Bien sûr, je suis heureux de recevoir vos commentaires sur d'autres moyens de coder cela.
Cela peut également être fait avec des éléments vectoriels nommés.
Dirk Eddelbuettel
3
library (fortunes); fortune (106) Si la réponse est parse (), vous devriez généralement repenser la question. - Thomas Lumley R-help (février 2005)
Eduardo Leoni
Voici un exemple où eval () et parse () peuvent être utiles. Cela implique un package Bioconductor, par exemple hgu133a.db et où vous essayez d'obtenir diverses informations sur un identifiant de sonde. Par exemple: 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
Comme le dit Dirk, cela est mieux fait avec des éléments vectoriels nommés, ou `get (paste (state, parameter, sep = '.'))`
hadley
@Hadley, je ne savais pas que vous pouviez utiliser get () de cette façon. Merci.
andrewj
5
set.seed() définit l'état du générateur de nombres aléatoires.
for (f in files) {if (! (f == 'mysource.r')) {print (paste ('Sourcing', f)) source (paste (d, f, sep = ''))}}
J'utilise le code ci-dessus pour rechercher tous les fichiers dans un répertoire au démarrage avec divers programmes utilitaires que j'utilise dans ma session interactive avec R. Je suis sûr qu'il existe de meilleures façons, mais je le trouve utile pour mon travail. La ligne qui fait cela est la suivante.
Merci. J'ai regardé un fil ou deux sur roxygen et il semble que je suis probablement au niveau où je devrais essayer d'écrire un simple package auto-utilisable.
mcheema
3
Pour effectuer une opération sur un certain nombre de variables dans un bloc de données. Ceci est volé de subset.data.frame.
Cela semble cool au début, mais ce type de code ne vous causera aucun problème à long terme. Il vaut toujours mieux être explicite.
hadley
hum, j'utilise ce truc un peu ces derniers temps. Pourriez-vous être plus précis sur ses problèmes illimités?
Ian Fellows
Peut-être qu'Hadley suggère d'utiliser le paquet plyr à la place?
Christopher DuBois
3
Non, ce n'est pas une suggestion voilée d'utiliser plyr à la place. Le problème fondamental avec votre code est qu'il est sémantiquement paresseux - au lieu de forcer l'utilisateur à énoncer explicitement ce qu'il veut, vous faites de la "magie" pour deviner. Le problème avec ceci est que cela rend la fonction très difficile à programmer - c'est-à-dire qu'il est difficile d'écrire une fonction qui appelle get.varssans sauter par de nombreux obstacles.
hadley
3
Je l'ai déjà posté une fois mais je l'utilise tellement que j'ai pensé le poster à nouveau. C'est juste une petite fonction pour renvoyer les noms et les numéros de position d'un data.frame. Il n'y a rien de spécial pour être sûr, mais je n'arrive presque jamais à traverser une session sans l'utiliser plusieurs fois.
##creates an object from a data.frame listing the column names and location
Réponses:
str()
vous indique la structure de n'importe quel objet.la source
dir()
- cela a plus de sens.str
c'est aussi l'abréviation destring
dans de nombreuses langues.class()
? Il semble révéler un type d'informations similaire. Pourquoi y a-t-il deux commandes similaires?class()
est juste une petite partie des informations quistr()
s'affichentUne fonction très utile que j'utilise souvent est dput (), qui vous permet de vider un objet sous la forme de code R.
Il peut être très utile de publier des blocs de données facilement reproductibles lorsque vous demandez de l'aide, ou pour modifier ou réorganiser les niveaux d'un facteur.
la source
head () et tail () pour obtenir la première et la dernière partie d'un dataframe, d'un vecteur, d'une matrice, d'une fonction, etc. Surtout avec de grandes trames de données, c'est un moyen rapide de vérifier qu'il a bien chargé.
la source
Une fonctionnalité intéressante: la lecture des données utilise des connexions qui peuvent être des fichiers locaux, des fichiers distants accessibles via http, des tubes à partir d'autres programmes ou plus.
À titre d'exemple simple, considérons cet accès pour N = 10 entiers aléatoires entre min = 100 et max = 200 de random.org (qui fournit de vrais nombres aléatoires basés sur le bruit atmosphérique plutôt qu'un générateur de nombres pseudo aléatoires):
En passant, le package random fournit plusieurs fonctions pratiques pour accéder à random.org .
la source
Je trouve que je me sers
with()
et dewithin()
plus en plus. Plus$
besoin de jeter mon code et il n'est pas nécessaire de commencer à attacher des objets au chemin de recherche. Plus sérieusement, je trouve quewith()
etc. rendent l' intention de mes scripts d'analyse de données beaucoup plus claire.with()
met en place un environnement dans lequel l'expression R est évaluée.within()
fait la même chose mais vous permet de modifier l'objet de données utilisé pour créer l'environnement.Ce que je n'avais pas réalisé lors de ma première utilisation,
within()
c'est que vous devez faire une affectation dans le cadre de l'expression évaluée et affecter l'objet renvoyé (comme ci-dessus) pour obtenir l'effet souhaité.la source
Astuce d'entrée de données = package RGoogleDocs
http://www.omegahat.org/RGoogleDocs/
J'ai trouvé que les feuilles de calcul Google étaient un moyen fantastique pour tous les collaborateurs d'être sur la même page. En outre, Google Forms permet de capturer les données des répondants et de les écrire sans effort dans une feuille de calcul Google. Étant donné que les données changent fréquemment et ne sont presque jamais définitives, il est de loin préférable que R lise directement une feuille de calcul Google plutôt que de télécharger des fichiers csv et de les lire.
Je ne peux pas me souvenir de laquelle mais une ou deux des commandes suivantes prend plusieurs secondes.
getGoogleAuth
getGoogleDocsConnection
getWorksheets
la source
Utilisez des accolades pour référencer des noms non standard.
Dans ce cas, df [, "1"] fonctionnerait également. Mais les tiques arrière fonctionnent à l'intérieur des formules!
[Modifier] Dirk demande pourquoi on donnerait des noms invalides? Je ne sais pas! Mais je rencontre certainement ce problème assez souvent dans la pratique. Par exemple, en utilisant le package reshape de hadley:
la source
read.table
lorsque la valeurcheck.names
est false, c'est-à-dire lorsque vous souhaitez travailler avec les noms de colonne d'origine.Je ne sais pas à quel point cela est / n'est pas connu, mais j'ai certainement profité des capacités de passage par référence des environnements.
Pour cet exemple, la raison pour laquelle ce serait utile n'a pas de sens, mais si vous passez de gros objets autour, cela peut aider.
la source
Ma nouvelle chose préférée est la bibliothèque foreach. Il vous permet de faire toutes les bonnes choses d'application, mais avec une syntaxe un peu plus simple:
La meilleure partie est que si vous faites quelque chose qui prend en fait beaucoup de temps, vous pouvez passer de
%do%
à%dopar%
(avec la bibliothèque backend appropriée) pour paralléliser instantanément, même à travers un cluster. Très lisse.la source
Je fais beaucoup de manipulation de base des données, voici donc deux fonctions intégrées ( transformation , sous - ensemble ) et une bibliothèque ( sqldf ) que j'utilise quotidiennement.
créer des exemples de données de vente
utilisez transform () pour ajouter une colonne
utilisez subset () pour découper les données
utiliser sqldf () pour découper et agréger avec SQL
Le package sqldf fournit une interface SQL aux trames de données R
Effectuer une agrégation ou GROUP BY
Pour une fonctionnalité de réduction de carte plus sophistiquée sur les trames de données, consultez le package plyr . Et si vous trouvez vouloir tirer vos cheveux, je vous recommande de vérifier Manipulation de données avec R .
la source
Les sous-ensembles de «x []» sont moyennés, chaque sous-ensemble étant constitué de ces observations avec les mêmes niveaux de facteurs. Utilisation: ave (x, ..., FUN = mean)
Je l'utilise tout le temps. (par exemple dans cette réponse ici à so )
la source
Un moyen d'accélérer le code et d'éliminer les boucles for.
au lieu de boucles for qui parcourent une trame de données à la recherche de valeurs. prenez simplement un sous-ensemble du df avec ces valeurs, beaucoup plus rapidement.
donc au lieu de:
faites quelque chose comme ça:
ce concept de base s'applique extrêmement souvent et constitue un excellent moyen de se débarrasser des boucles for
la source
Parfois, vous avez besoin de
rbind
plusieurs trames de données.do.call()
vous laissera faire cela (quelqu'un a dû m'expliquer cela lorsque bind j'ai posé cette question, car cela ne semble pas être une utilisation évidente).la source
unsplit
.Dans la programmation R (pas de sessions interactives), j'utiliser
if (bad.condition) stop("message")
un grand nombre . Chaque fonction commence par quelques-uns de ceux-ci, et au fur et à mesure que je travaille sur des calculs, je les ajoute également. Je suppose que j'ai pris l'habitude d'utiliserassert()
en C. Les avantages sont doubles. Premièrement, il est beaucoup plus rapide d'obtenir du code fonctionnel avec ces vérifications en place. Deuxièmement, et probablement plus important, il est beaucoup plus facile de travailler avec du code existant lorsque vous voyez ces vérifications sur chaque écran de votre éditeur. Vous n'aurez pas à se demander six>0
, ou faire confiance à un commentaire indiquant qu'il est ... vous savez , d'un coup d' oeil, que ce soit.PS. mon premier message ici. Sois gentil!
la source
stopfifnot(!bad.condition)
qui est plus concise.La
traceback()
fonction est indispensable lorsque vous avez une erreur quelque part et que vous ne la comprenez pas facilement. Il imprimera une trace de la pile, très utile car R n'est pas très verbeux par défaut.Ensuite, le paramétrage
options(error=recover)
vous permettra "d'entrer" dans la fonction générant l'erreur et d'essayer de comprendre ce qui se passe exactement, comme si vous en aviez le contrôle total et que vous pouviez y mettre unbrowser()
.Ces trois fonctions peuvent vraiment vous aider à déboguer votre code.
la source
options(error=recover)
est ma méthode de débogage préférée.Je suis vraiment surpris que personne n'ait posté sur Apply, Tapply, Laply, and Sapply. Une règle générale que j'utilise lorsque je fais des choses dans R est que si j'ai une boucle for qui traite des données ou des simulations, j'essaye de la factoriser et de la remplacer par un * apply. Certaines personnes hésitent à utiliser les fonctions * apply parce qu'elles pensent que seules des fonctions à paramètre unique peuvent être transmises. Rien ne pourrait être plus éloigné de la vérité! Comme pour transmettre des fonctions avec des paramètres en tant qu'objets de première classe en Javascript, vous faites cela en R avec des fonctions anonymes. Par exemple:
(Pour ceux qui suivent #rstats, je l'ai également posté ici).
N'oubliez pas, utilisez apply, sapply, lapply, tapply et do.call! Profitez de la vectorisation de R. Vous ne devriez jamais marcher jusqu'à un tas de code R et voir:
Non seulement cela n'est pas vectorisé, mais la structure du tableau dans R n'est pas développée comme elle l'est en Python (doubler la taille lorsque l'espace est épuisé, IIRC). Donc, chaque étape de rbind doit d'abord croître suffisamment pour accepter les résultats de rbind (), puis copier tout le contenu précédent. Pour le plaisir, essayez ce qui précède dans R. Notez combien de temps cela prend (vous n'aurez même pas besoin de Rprof ou de toute fonction de minutage). Puis essayez
Ce qui suit est également meilleur que la première version:
la source
Sur les conseils de Dirk, je publie des exemples uniques. J'espère qu'ils ne sont pas trop "mignons" [intelligents, mais je m'en fiche] ou triviaux pour ce public.
Les modèles linéaires sont le pain et le beurre de R. Lorsque le nombre de variables indépendantes est élevé, on a deux choix. La première consiste à utiliser lm.fit (), qui reçoit la matrice de conception x et la réponse y comme arguments, de la même manière que Matlab. L'inconvénient de cette approche est que la valeur de retour est une liste d'objets (coefficients ajustés, résidus, etc.), pas un objet de classe "lm", qui peut être bien résumé, utilisé pour la prédiction, la sélection par étapes, etc. l'approche consiste à créer une formule:
la source
Vous pouvez attribuer une valeur renvoyée par un bloc if-else.
Au lieu de, par exemple
tu peux faire
La façon exacte dont cela fonctionne est une magie profonde.
la source
if-then-else
expressions fonctionnent dans n'importe quel langage fonctionnel (à ne pas confondre avec lesif-then-else
instructions ). Très similaire à l'?:
opérateur ternaire des langages de type C.En tant que noob total pour R et novice en statistiques que j'aime
unclass()
imprimer tous les éléments d'un bloc de données sous forme de liste ordinaire.C'est très pratique pour jeter un coup d'œil à un ensemble de données complet en une seule fois afin de détecter rapidement tout problème potentiel.
la source
CrossTable()
dugmodels
package fournit un accès facile aux tableaux croisés de type SAS et SPSS, ainsi qu'aux tests habituels (Chisq, McNemar, etc.). Fondamentalement, c'estxtabs()
avec une sortie sophistiquée et des tests supplémentaires - mais cela facilite le partage de la sortie avec les païens.la source
Définitivement
system()
. Pouvoir accéder à tous les outils unix (au moins sous Linux / MacOSX) depuis l'intérieur de l'environnement R est rapidement devenu inestimable dans mon flux de travail quotidien.la source
help(connections)
pour des détails et des exemples.Voici une solution de contournement ennuyeuse pour convertir un facteur en numérique. (Similaire pour d'autres types de données également)
la source
as.numeric(levels(old.var))[old.var]
Bien que cette question soit posée depuis un certain temps, j'ai récemment découvert une excellente astuce sur le blog SAS et R pour utiliser la commande
cut
. La commande est utilisée pour diviser les données en catégories et je vais utiliser le jeu de données iris comme exemple et le diviser en 10 catégories:la source
Un autre truc. Certains packages, comme glmnet, ne prennent comme entrées que la matrice de conception et la variable de réponse. Si l'on veut ajuster un modèle avec toutes les interactions entre les caractéristiques, elle ne peut pas utiliser la formule "y ~. ^ 2". L'utilisation
expand.grid()
nous permet de tirer parti de la puissante indexation de tableau et des opérations vectorielles de R.la source
model.matrix
?L'une de mes astuces préférées, sinon quelque peu peu orthodoxes, est l'utilisation de
eval()
etparse()
. Cet exemple illustre peut-être comment cela peut être utileCe type de situation se produit le plus souvent et l'utilisation de
eval()
etparse()
peut aider à y remédier. Bien sûr, je suis heureux de recevoir vos commentaires sur d'autres moyens de coder cela.la source
set.seed()
définit l'état du générateur de nombres aléatoires.Par exemple:
la source
Pour ceux qui écrivent C pour être appelé à partir de R:
.Internal(inspect(...))
est pratique. Par exemple:la source
d = '~ / R Code / Bibliothèque /'
fichiers = liste.fichiers (d, '. r $')
for (f in files) {if (! (f == 'mysource.r')) {print (paste ('Sourcing', f)) source (paste (d, f, sep = ''))}}
J'utilise le code ci-dessus pour rechercher tous les fichiers dans un répertoire au démarrage avec divers programmes utilitaires que j'utilise dans ma session interactive avec R. Je suis sûr qu'il existe de meilleures façons, mais je le trouve utile pour mon travail. La ligne qui fait cela est la suivante.
source ("~ / R Code / Library / mysource.r")
la source
Pour effectuer une opération sur un certain nombre de variables dans un bloc de données. Ceci est volé de subset.data.frame.
la source
get.vars
sans sauter par de nombreux obstacles.Je l'ai déjà posté une fois mais je l'utilise tellement que j'ai pensé le poster à nouveau. C'est juste une petite fonction pour renvoyer les noms et les numéros de position d'un data.frame. Il n'y a rien de spécial pour être sûr, mais je n'arrive presque jamais à traverser une session sans l'utiliser plusieurs fois.
namesind = fonction (df) {
}
ni <- namesind
la source
data.frame(VAR = names(df), COL = seq_along(df))