Was ist Ihre nützlichste Funktion oder der nützlichste Trick , um weitere Tipps und Tricks für R zu teilen ? Clevere Vektorisierung? Dateneingabe / -ausgabe? Visualisierung und Grafik? Statistische Analyse? Spezialfunktionen? Die interaktive Umgebung selbst?
Ein Artikel pro Beitrag, und wir werden sehen, ob wir durch Stimmen einen Gewinner bekommen.
[Edit 25-Aug 2008]: Nach einer Woche scheint es, dass der Einfache str()die Umfrage gewonnen hat. Da ich dieses gerne selbst empfehlen würde, ist es eine einfache Antwort zu akzeptieren.
@ars: Es ist eine Frage, die keine eindeutige Antwort hat . Ergo mach es CW.
dmckee --- Ex-Moderator Kätzchen
2
@ JD Langer lustiger Kommentar. Leider war es hinter der Falte versteckt. Ich meine, die Beantwortung schwieriger R-Fragen zahlt sich nicht wirklich aus. Es ist also in Ordnung für mich, wenn Leute, die nette Fragen gestellt haben, die R auf die Karte setzen, endlich etwas Anerkennung bekommen. Außerdem ist dies für die R-Benutzer sicherlich nützlicher als eine Frage, die Ihre Lieblings-C-Trickfrage für C-Programmierer wäre ...
Warum nicht class()? Es scheint ähnliche Informationen zu geben. Warum gibt es zwei so ähnliche Befehle?
hhh
1
class()ist nur ein kleiner Teil der Informationen, die str()angezeigt werden
Hadley
64
Eine sehr nützliche Funktion, die ich oft benutze, ist dput (), mit der Sie ein Objekt in Form von R-Code sichern können.
# 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")
Es kann sehr nützlich sein, leicht reproduzierbare Datenblöcke zu veröffentlichen, wenn Sie um Hilfe bitten, oder die Ebenen eines Faktors zu bearbeiten oder neu zu ordnen.
head () und tail (), um den ersten und letzten Teil eines Datenrahmens, Vektors, einer Matrix, einer Funktion usw. abzurufen. Insbesondere bei großen Datenrahmen können Sie auf schnelle Weise überprüfen, ob der Datenrahmen in Ordnung ist.
Eine nette Funktion: Beim Lesen von Daten werden Verbindungen verwendet , bei denen es sich um lokale Dateien, Remote-Dateien, auf die über http zugegriffen werden kann, Pipes von anderen Programmen oder mehr handeln kann.
Betrachten Sie als einfaches Beispiel diesen Zugriff für N = 10 zufällige Ganzzahlen zwischen min = 100 und max = 200 von random.org (der echte Zufallszahlen basierend auf atmosphärischem Rauschen anstelle eines Pseudozufallszahlengenerators liefert):
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>
Abgesehen davon bietet das Zufallspaket mehrere praktische Funktionen für den Zugriff auf random.org .
BTW-- Ich würde vorschlagen , dass Sie sollten selfanswers CW machen , wenn (1) Sie nach ihnen prompt und (2) Sie nicht die Frage CW machen. Ansonsten sieht es ein bisschen so aus, als würden Sie versuchen, das Wiederholungssystem zu spielen. YMMV und das alles.
dmckee --- Ex-Moderator Kätzchen
1
Es geht nicht darum, das System zu spielen, sondern nur darum, die Dinge in Gang zu bringen. Er kann immer noch jede andere Antwort akzeptieren.
Ars
2
@ars: Er kann diesen akzeptieren. Ich werde auch nicht versuchen, ihn zum Wiki zu zwingen, wenn er meinen Rat nicht befolgt. Aber ich werde keine vorbereitete Selbstantwort veröffentlichen, ohne sie als Wiki zu markieren, und ich werde auch ohne sie nicht für eine stimmen. Nehmen Sie das für das, was es wert ist.
dmckee --- Ex-Moderator Kätzchen
4
@Dirk: Es ist völlig akzeptabel, sogar von Jeff und Joel ermutigt, Ihre eigene Frage zu beantworten. Es gibt KEINE Anforderung, nicht einmal eine informelle, um Ihre Antwort CW zu geben. Sie spielen das System eindeutig nicht. Ignorieren Sie noch einmal einfach die Community-Wiki-Polizei.
Julia
8
Ich muss zustimmen, dass ein Teil der Website darin besteht, die besten Antworten auf häufig auftretende Probleme und eine allgemeine Ressource bereitzustellen. Das Stellen von Fragen und das Bereitstellen einer guten Antwort kann dabei helfen, ein Thema zu unterstützen. Dies ist besonders nützlich bei neuen / kleinen Tags wie R.
kpierce8
35
Ich finde, ich benutze with()und within()immer mehr. Sie müssen $meinen Code nicht mehr verunreinigen und müssen keine Objekte mehr an den Suchpfad anhängen. Im Ernst, ich finde with()usw. machen die Absicht meiner Datenanalyseskripte viel klarer.
> 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()Richtet eine Umgebung ein, in der der R-Ausdruck ausgewertet wird. within()macht dasselbe, erlaubt Ihnen jedoch, das Datenobjekt zu ändern, das zum Erstellen der Umgebung verwendet wird.
> 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
Als ich sie zum ersten Mal verwendete within(), war mir nicht klar, dass Sie eine Zuweisung als Teil des ausgewerteten Ausdrucks vornehmen und das zurückgegebene Objekt (wie oben) zuweisen müssen, um den gewünschten Effekt zu erzielen.
Ich habe festgestellt, dass Google-Tabellen eine fantastische Möglichkeit für alle Mitarbeiter sind, auf derselben Seite zu sein. Darüber hinaus können Sie mit Google Forms Daten von Befragten erfassen und mühelos in eine Google-Tabelle schreiben. Da sich Daten häufig ändern und fast nie endgültig sind, ist es für R weitaus besser, eine Google-Tabelle direkt zu lesen, als CSV-Dateien herunterzuladen und einzulesen.
# 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)
Ich kann mich nicht erinnern, welcher oder einige der folgenden Befehle einige Sekunden dauern.
[Bearbeiten] Dirk fragt, warum man ungültige Namen geben würde? Ich weiß es nicht! Aber ich stoße in der Praxis sicherlich ziemlich oft auf dieses Problem. Verwenden Sie beispielsweise das Umformungspaket von 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, aber warum sollten Sie syntaktisch gültige Namen (wie x oder y) durch ungültige (wie 1 oder 2) ersetzen müssen, für die die Backticks erforderlich sind?
Dirk Eddelbuettel
3
Dies ist auch nützlich, read.tablewenn check.nameses falsch ist, dh wenn Sie mit den ursprünglichen Spaltennamen arbeiten möchten.
Hadley
25
Ich weiß nicht, wie bekannt dies ist / nicht, aber etwas, das ich definitiv ausgenutzt habe, sind die Pass-by-Reference-Funktionen von Umgebungen.
Das Beste daran ist, dass Sie, wenn Sie etwas tun, das tatsächlich viel Zeit benötigt, von %do%zu %dopar%(mit der entsprechenden Backend-Bibliothek) wechseln können , um auch über einen Cluster hinweg sofort parallel zu arbeiten. Sehr glatt.
Ich mache eine Menge grundlegender Manipulationen von Daten, daher hier zwei integrierte Funktionen ( Transformation , Teilmenge ) und eine Bibliothek ( sqldf ), die ich täglich benutze.
Beispielverkaufsdaten erstellen
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
Verwenden Sie transform (), um eine Spalte hinzuzufügen
## 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...
Verwenden Sie subset (), um die Daten zu schneiden
Verwenden Sie sqldf (), um mit SQL zu schneiden und zu aggregieren
Das sqldf-Paket bietet eine SQL-Schnittstelle für R-Datenrahmen
## 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
Führen Sie eine Aggregation oder GROUP BY durch
sqldf('select country, sum(revenue) revenue \
FROM sales \
GROUP BY country')>
country revenue
1 FR 307.11572 UK 280.63823 USA 304.6860
Teilmengen von 'x []' werden gemittelt, wobei jede Teilmenge aus Beobachtungen mit denselben Faktorstufen besteht. Verwendung: ave (x, ..., FUN = Mittelwert)
Wie unterscheidet sich das von tapply (x, Faktor, Spaß)?
TMS
1
@Tomas ave behält Ordnung und Länge bei. So können Sie beispielsweise in einem Schritt einen Vektor von Gruppenmitteln zu einem Datensatz hinzufügen.
Eduardo Leoni
18
Eine Möglichkeit, Code zu beschleunigen und for-Schleifen zu entfernen.
anstelle von for-Schleifen, die einen Datenrahmen durchlaufen und nach Werten suchen. Nehmen Sie einfach eine Teilmenge des df mit diesen Werten, viel schneller.
also statt:
for(i in1:nrow(df)){if(df$column[i]== x){
df$column2[i]<- y
or any other similiar code
}}
mach so etwas:
df$column2[df$column1 == x]<- y
Dieses Basiskonzept ist extrem häufig anwendbar und eine großartige Möglichkeit, Schleifen loszuwerden
Hier gibt es eine kleine Falle, die mich die ganze Zeit eingeholt hat. Wenn df $ column1 NA-Werte enthält, werden durch Untermenge mit == alle Werte abgerufen , die x und NAs entsprechen. Um dies zu vermeiden, verwenden Sie "% in%" anstelle von "==".
Matt Parker
Matt, du hast absolut Recht und es ist etwas, das ich hasse, aber ich mag deine Methode. Normalerweise überprüfe ich die Spalte auf NAs und entferne sie dann mit einer von mir erstellten Schnellfunktion, die eine Datenrahmenspalte verwendet und den Datenrahmen minus Zeilen mit NAs in genau dieser Spalte zurückgibt.
Dan
Im Wesentlichen reduziere ich einen Datenrahmen auf die Spalten, für die ich Werte haben muss, und verwende dann na.omit, um die richtigen Zeilen zu erhalten, und setze dann das ursprüngliche Dataset nur mit diesen Zeilen unter. Nur mit na.omit würde jede Zeile mit einer NA entfernt, ich könnte mich jedoch irren.
Dan
16
Manchmal müssen Sie rbindmehrere Datenrahmen verwenden. do.call()lassen Sie das tun (jemand musste mir dies erklären, als ich diese Frage stellte, da es keine offensichtliche Verwendung zu sein scheint).
Guter Anruf: Ich finde, dass dies oft einfacher ist als die Verwendung unsplit.
Richie Cotton
16
In R - Programmierung (nicht interaktive Sitzungen), verwende ich if (bad.condition) stop("message")eine Menge . Jede Funktion beginnt mit einigen davon, und während ich Berechnungen durcharbeite, pfeffere ich diese auch ein. Ich glaube, ich habe mir angewöhnt, assert()C zu verwenden. Die Vorteile sind zweifach. Erstens ist es viel schneller, mit diesen Überprüfungen Arbeitscode zu erhalten. Zweitens, und wahrscheinlich noch wichtiger, ist es viel einfacher, mit vorhandenem Code zu arbeiten, wenn Sie diese Überprüfungen auf jedem Bildschirm in Ihrem Editor sehen. Sie müssen sich nicht fragen, ob x>0oder einem Kommentar vertrauen, der besagt, dass es ... Sie werden auf einen Blick wissen , dass es ist.
Keine schlechte Angewohnheit, und R bietet noch einen anderen Weg: stopfifnot(!bad.condition)der prägnanter ist.
Dirk Eddelbuettel
13
Die traceback()Funktion ist ein Muss, wenn Sie irgendwo einen Fehler haben und ihn nicht ohne weiteres verstehen. Es wird eine Spur des Stapels gedruckt, was sehr hilfreich ist, da R standardmäßig nicht sehr ausführlich ist.
Mit dieser Einstellung options(error=recover)können Sie in die Funktion "eintreten", die den Fehler auslöst, und versuchen zu verstehen, was genau passiert, als ob Sie die volle Kontrolle darüber hätten und eine darin einfügen könnten browser().
Diese drei Funktionen können beim Debuggen Ihres Codes wirklich helfen.
Ich bin wirklich überrascht, dass niemand über bewerben, tapply, lapply und sapply geschrieben hat. Eine allgemeine Regel, die ich beim Ausführen von Dingen in R verwende, lautet: Wenn ich eine for-Schleife habe, die Daten verarbeitet oder simuliert, versuche ich, sie herauszufiltern und durch ein * apply zu ersetzen. Einige Leute scheuen die * Apply-Funktionen, weil sie denken, dass nur einzelne Parameterfunktionen übergeben werden können. Nichts könnte weiter von der Wahrheit entfernt sein! Wie das Weitergeben von Funktionen mit Parametern als erstklassige Objekte in Javascript tun Sie dies in R mit anonymen Funktionen. Beispielsweise:
> 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"
(Für diejenigen, die #rstats folgen, habe ich dies auch dort gepostet).
Denken Sie daran, verwenden Sie anwenden, sapply, lapply, tapply und do.call! Nutzen Sie die Vektorisierung von R. Sie sollten niemals zu einem Haufen R-Code gehen und sehen:
N =10000
l = numeric()for(i in seq(1:N)){
sim <- rnorm(1,0,1)
l <- rbind(l, sim)}
Dies wird nicht nur nicht vektorisiert, sondern die Array-Struktur in R wird nicht wie in Python vergrößert (Verdoppelung der Größe, wenn der Speicherplatz knapp wird, IIRC). Daher muss jeder rbind-Schritt zuerst l genug wachsen, um die Ergebnisse von rbind () zu akzeptieren, und dann den gesamten Inhalt des vorherigen l kopieren. Versuchen Sie zum Spaß das Obige in R. Beachten Sie, wie lange es dauert (Sie benötigen nicht einmal Rprof oder eine Timing-Funktion). Dann versuche es
N=10000
l <- rnorm(N,0,1)
Folgendes ist auch besser als die erste Version:
N =10000
l = numeric(N)for(i in seq(1:N)){
sim <- rnorm(1,0,1)
l[i]<- sim
}
auftragen, sapply, lapply und tapply sind nützlich. Wenn Sie Parameter an eine benannte Funktion wie round übergeben möchten, können Sie sie einfach zusammen mit apply übergeben, anstatt eine anonyme Funktion zu schreiben. Versuchen Sie "sapply (rnorm (10, 0, 1), round, digits = 2)", das "[1] -0,29 0,29 1,31 -0,06 -1,90 -0,84 0,21 0,02 0,23 -1,10" ausgibt.
Daniel
11
Auf Dirks Rat hin veröffentliche ich einzelne Beispiele. Ich hoffe, sie sind nicht zu "süß" [klug, aber es ist mir egal] oder trivial für dieses Publikum.
Lineare Modelle sind das A und O von R. Wenn die Anzahl der unabhängigen Variablen hoch ist, hat man zwei Möglichkeiten. Die erste besteht darin, lm.fit () zu verwenden, das ähnlich wie Matlab die Entwurfsmatrix x und die Antwort y als Argumente empfängt. Der Nachteil dieses Ansatzes besteht darin, dass der Rückgabewert eine Liste von Objekten (angepasste Koeffizienten, Residuen usw.) ist, nicht ein Objekt der Klasse "lm", das gut zusammengefasst werden kann und zur Vorhersage, schrittweisen Auswahl usw. verwendet wird. Der zweite Ansatz ist eine Formel zu erstellen:
> 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
Wie wäre es, wenn Sie eine pro Beitrag auswählen und anhand eines Beispiels illustrieren? Wir können dann tagelang weitermachen und neue Beispiele mit neuen Befehlen veröffentlichen ... [Übrigens: Soweit ich mich erinnere, benötigen Sie as.formula (paste (...)) für die Verwendung von Formeln. ]
Dirk Eddelbuettel
Sie benötigen die explizite Formelerstellung nicht, um alle Spalten abzudecken, da die Form "y ~. - 1" sie abdeckt. Das "." bedeutet 'alle Spalten außer der abhängigen Variablen, und' - 1 'schließt die Konstante wie in Ihrem Beispiel aus.
Dirk Eddelbuettel
Das ist richtig für dieses spezielle Beispiel, aber für X mit ncols >> nrows entferne ich oft einige unabhängige Variablen, insbesondere in den letzten Phasen der Analyse. In diesem Fall ist das Erstellen einer Formel aus den Datenrahmennamen immer noch praktisch.
Gappy
10
Sie können einen Wert zuweisen, der von einem if-else-Block zurückkehrt.
Anstelle von z
condition <- runif(1)>0.5if(condition) x <-1else x <-2
Sie können dies auch wie x <- ifelse (Bedingung 1, 2) tun. In diesem Fall wird jede Komponente vektorisiert.
Shane
Shane, du könntest, aber wenn du nicht wirklich tief greifst, was ifelse () tut, solltest du es wahrscheinlich nicht tun! Es ist leicht zu missverstehen ...
Harlan
Was ist daran magisch? So if-then-elsefunktionieren Ausdrücke in jeder funktionalen Sprache (nicht zu verwechseln mit if-then-elseAussagen ). Sehr ähnlich dem ternären ?:Operator von C-ähnlichen Sprachen.
Frank
10
Als absoluter Neuling bei R und Anfänger bei Statistiken liebe ich es unclass()
, alle Elemente eines Datenrahmens als gewöhnliche Liste zu drucken.
Es ist ziemlich praktisch, einen vollständigen Datensatz auf einmal zu betrachten, um potenzielle Probleme schnell zu erkennen.
CrossTable()Das gmodelsPaket bietet einfachen Zugriff auf Kreuztabellen im SAS- und SPSS-Stil sowie die üblichen Tests (Chisq, McNemar usw.). Grundsätzlich ist es xtabs()mit ausgefallener Ausgabe und einigen zusätzlichen Tests - aber es erleichtert das Teilen der Ausgabe mit den Heiden.
Nett!! Ich benutze ziemlich viel gmodels, aber habe dieses verpasst
Abhijit
Gute Antwort, alles, was mich davon abhalten kann, Tische mit den Heiden übermäßig zu erklären, ist eine gute Zeitnutzung.
Stedy
7
Auf jeden Fall system(). Der Zugriff auf alle Unix-Tools (zumindest unter Linux / MacOSX) aus der R-Umgebung heraus ist in meinem täglichen Workflow schnell von unschätzbarem Wert geworden.
Dies knüpft an meinen früheren Kommentar zu Verbindungen an: Sie können auch pipe () verwenden, um Daten von oder an Unix-Befehle zu übergeben. Siehe help(connections)für Details und Beispiele.
Dirk Eddelbuettel
6
Hier ist eine lästige Problemumgehung, um einen Faktor in eine Zahl umzuwandeln. (Ähnliches gilt auch für andere Datentypen)
Vielleicht meinten Sie "in einen Charakter" -Vektor. In diesem Fall ist "as.character (old.var)" einfacher.
Dirk Eddelbuettel
1
Ich habe immer gedacht, dass dieser Rat (der unter? Factor gelesen werden kann) falsch ist. Sie müssen sicher sein, dass old.var ein Faktor ist. Dies hängt von den Optionen ab, die Sie für die R-Sitzung festgelegt haben. Die Verwendung von as.numeric (as.character (old.var)) ist sowohl sicherer als auch sauberer.
Eduardo Leoni
Wirklich keine Abwertung wert, aber was auch immer. Das funktioniert bei mir.
Ryan R. Rosario
Ryan - Könnten Sie Ihren Code reparieren? Wenn old.var <- Faktor (1: 2); Ihr Code gibt [1] "1" "2" (nicht numerisch.) Vielleicht haben Sie als.numerisch (Ebenen (old.var) [old.var]) gemeint?
Eduardo Leoni
3
Oder etwas effizienter:as.numeric(levels(old.var))[old.var]
Hadley
6
Obwohl diese Frage schon eine Weile offen ist, habe ich kürzlich im SAS- und R-Blog einen großartigen Trick für die Verwendung des Befehls entdeckt cut. Der Befehl wird verwendet, um Daten in Kategorien zu unterteilen. Ich werde den Iris-Datensatz als Beispiel verwenden und ihn in 10 Kategorien unterteilen:
> 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]
Ein weiterer Trick. Einige Pakete, wie z. B. glmnet, verwenden nur die Entwurfsmatrix und die Antwortvariable als Eingaben. Wenn man ein Modell mit allen Interaktionen zwischen Merkmalen anpassen möchte, kann man die Formel "y ~. ^ 2" nicht verwenden. Die Verwendung expand.grid()ermöglicht es uns, die leistungsstarken Array-Indizierungs- und Vektoroperationen von R zu nutzen.
Wenn eine Modellierungsfunktion keine Formel akzeptiert (was sehr selten ist!), Wäre es nicht besser, die Entwurfsmatrix mit zu erstellen model.matrix?
Hadley
Schön. Ich wusste nichts von der Existenz dieser Funktion. Die obige Funktion entspricht model.matrix (~. ^ 2 -1, X). Bei der Übergabe von Matrizen übergibt ich neben glmnet jedoch häufig Array-Zeiger an benutzerdefinierte C-Funktionen. In der Tat würde ich nicht wissen, wie man eine Formel an eine Funktion übergibt. Hast du ein Spielzeugbeispiel?
Gappy
5
Einer meiner Lieblingstricks, wenn auch nicht etwas unorthodoxe, ist die Verwendung von eval()und parse(). Dieses Beispiel zeigt vielleicht, wie hilfreich es sein kann
NY.Capital <-'Albany'
state <-'NY'
parameter <-'Capital'
eval(parse(text=paste(state, parameter, sep='.')))[1]"Albany"
Diese Art von Situation tritt häufig auf eval()und parse()kann verwendet werden, um sie anzugehen. Natürlich freue ich mich über Feedback zu alternativen Codierungsmethoden.
Dies kann auch mit benannten Vektorelementen erfolgen.
Dirk Eddelbuettel
3
Bibliothek (Vermögen); Vermögen (106) Wenn die Antwort parse () lautet, sollten Sie die Frage normalerweise überdenken. - Thomas Lumley R-Hilfe (Februar 2005)
Eduardo Leoni
Hier ist ein Beispiel, in dem eval () und parse () nützlich sein können. Hierbei handelt es sich um ein Bioconductor-Paket, z. B. hgu133a.db, bei dem Sie versuchen, verschiedene Informationen zu einer Sondensatz-ID abzurufen. Beispiel: Bibliotheksparameter (hgu133a.db) <- 'SYMBOL' mget ('202431_s_at', env = eval (Analyse (Text = Einfügen ('hgu133a', Parameter, sep = '')))) Parameter <- 'ENTREZID 'mget (' 202431_s_at ', env = eval (parse (text = paste (' hgu133a ', parameter, sep =' '))))
andrewj
Wie Dirk sagt, ist dies besser mit benannten
Vektorelementen
@ Hadley, wusste nicht, dass Sie get () so verwenden könnten. Vielen Dank.
Andrewj
5
set.seed() Legt den Status des Zufallszahlengenerators fest.
für (f in Dateien) {if (! (f == 'mysource.r')) {print (Einfügen ('Sourcing', f)) Quelle (Einfügen (d, f, sep = ''))}}
Ich verwende den obigen Code, um alle Dateien in einem Verzeichnis beim Start mit verschiedenen Hilfsprogrammen zu beschaffen, die ich in meiner interaktiven Sitzung mit R verwende. Ich bin sicher, dass es bessere Möglichkeiten gibt, aber ich finde es nützlich für meine Arbeit. Die Zeile, die dies tut, ist wie folgt.
Vielen Dank. Ich habe mir ein oder zwei Threads zu Sauerstoff angesehen und es scheint, dass ich wahrscheinlich auf dem Niveau bin, auf dem ich versuchen sollte, ein einfaches Selbstgebrauchspaket zu schreiben.
Mcheema
3
Ausführen einer Operation für eine Reihe von Variablen in einem Datenrahmen. Dies wird aus subset.data.frame gestohlen.
Das scheint zunächst cool zu sein, aber diese Art von Code wird Ihnen auf lange Sicht keine Probleme bereiten. Es ist immer besser, explizit zu sein.
Hadley
hum, ich habe diesen Trick in letzter Zeit ziemlich oft benutzt. Könnten Sie genauer über die unbegrenzten Probleme sprechen?
Ian Fellows
Vielleicht schlägt Hadley vor, stattdessen das Plyr-Paket zu verwenden?
Christopher DuBois
3
Nein, dies ist kein verschleierter Vorschlag, stattdessen Plyr zu verwenden. Das grundsätzliche Problem mit Ihrem Code ist, dass er semantisch faul ist - anstatt den Benutzer explizit dazu zu bringen, das zu buchstabieren, was er will, tun Sie etwas "Magie", um zu raten. Das Problem dabei ist, dass es sehr schwierig ist, mit der Funktion zu programmieren - dh es ist schwierig, eine Funktion zu schreiben, die aufruft, get.varsohne durch eine ganze Reihe von Reifen zu springen.
Hadley
3
Ich habe das schon einmal gepostet, aber ich benutze es so oft, dass ich dachte, ich würde es wieder posten. Es ist nur eine kleine Funktion, um die Namen und Positionsnummern eines data.frame zurückzugeben. Es ist zwar nichts Besonderes, aber ich schaffe es fast nie durch eine Sitzung, ohne es mehrmals zu benutzen.
##creates an object from a data.frame listing the column names and location
Antworten:
str()
sagt Ihnen die Struktur eines Objekts.quelle
dir()
- macht mehr Sinn.str
ist auchstring
in vielen Sprachen kurz.class()
? Es scheint ähnliche Informationen zu geben. Warum gibt es zwei so ähnliche Befehle?class()
ist nur ein kleiner Teil der Informationen, diestr()
angezeigt werdenEine sehr nützliche Funktion, die ich oft benutze, ist dput (), mit der Sie ein Objekt in Form von R-Code sichern können.
Es kann sehr nützlich sein, leicht reproduzierbare Datenblöcke zu veröffentlichen, wenn Sie um Hilfe bitten, oder die Ebenen eines Faktors zu bearbeiten oder neu zu ordnen.
quelle
head () und tail (), um den ersten und letzten Teil eines Datenrahmens, Vektors, einer Matrix, einer Funktion usw. abzurufen. Insbesondere bei großen Datenrahmen können Sie auf schnelle Weise überprüfen, ob der Datenrahmen in Ordnung ist.
quelle
Eine nette Funktion: Beim Lesen von Daten werden Verbindungen verwendet , bei denen es sich um lokale Dateien, Remote-Dateien, auf die über http zugegriffen werden kann, Pipes von anderen Programmen oder mehr handeln kann.
Betrachten Sie als einfaches Beispiel diesen Zugriff für N = 10 zufällige Ganzzahlen zwischen min = 100 und max = 200 von random.org (der echte Zufallszahlen basierend auf atmosphärischem Rauschen anstelle eines Pseudozufallszahlengenerators liefert):
Abgesehen davon bietet das Zufallspaket mehrere praktische Funktionen für den Zugriff auf random.org .
quelle
Ich finde, ich benutze
with()
undwithin()
immer mehr. Sie müssen$
meinen Code nicht mehr verunreinigen und müssen keine Objekte mehr an den Suchpfad anhängen. Im Ernst, ich findewith()
usw. machen die Absicht meiner Datenanalyseskripte viel klarer.with()
Richtet eine Umgebung ein, in der der R-Ausdruck ausgewertet wird.within()
macht dasselbe, erlaubt Ihnen jedoch, das Datenobjekt zu ändern, das zum Erstellen der Umgebung verwendet wird.Als ich sie zum ersten Mal verwendete
within()
, war mir nicht klar, dass Sie eine Zuweisung als Teil des ausgewerteten Ausdrucks vornehmen und das zurückgegebene Objekt (wie oben) zuweisen müssen, um den gewünschten Effekt zu erzielen.quelle
Dateneingabetrick = RGoogleDocs-Paket
http://www.omegahat.org/RGoogleDocs/
Ich habe festgestellt, dass Google-Tabellen eine fantastische Möglichkeit für alle Mitarbeiter sind, auf derselben Seite zu sein. Darüber hinaus können Sie mit Google Forms Daten von Befragten erfassen und mühelos in eine Google-Tabelle schreiben. Da sich Daten häufig ändern und fast nie endgültig sind, ist es für R weitaus besser, eine Google-Tabelle direkt zu lesen, als CSV-Dateien herunterzuladen und einzulesen.
Ich kann mich nicht erinnern, welcher oder einige der folgenden Befehle einige Sekunden dauern.
getGoogleAuth
getGoogleDocsConnection
getWorksheets
quelle
Verwenden Sie Backticks, um auf nicht standardmäßige Namen zu verweisen.
In diesem Fall würde auch df [, "1"] funktionieren. Aber Back Ticks funktionieren in Formeln!
[Bearbeiten] Dirk fragt, warum man ungültige Namen geben würde? Ich weiß es nicht! Aber ich stoße in der Praxis sicherlich ziemlich oft auf dieses Problem. Verwenden Sie beispielsweise das Umformungspaket von Hadley:
quelle
read.table
wenncheck.names
es falsch ist, dh wenn Sie mit den ursprünglichen Spaltennamen arbeiten möchten.Ich weiß nicht, wie bekannt dies ist / nicht, aber etwas, das ich definitiv ausgenutzt habe, sind die Pass-by-Reference-Funktionen von Umgebungen.
In diesem Beispiel ist es nicht sinnvoll, warum es nützlich ist, aber wenn Sie große Objekte herumreichen, kann dies hilfreich sein.
quelle
Meine neue Lieblingssache ist die foreach-Bibliothek. Damit können Sie all die netten Dinge anwenden, aber mit einer etwas einfacheren Syntax:
Das Beste daran ist, dass Sie, wenn Sie etwas tun, das tatsächlich viel Zeit benötigt, von
%do%
zu%dopar%
(mit der entsprechenden Backend-Bibliothek) wechseln können , um auch über einen Cluster hinweg sofort parallel zu arbeiten. Sehr glatt.quelle
Ich mache eine Menge grundlegender Manipulationen von Daten, daher hier zwei integrierte Funktionen ( Transformation , Teilmenge ) und eine Bibliothek ( sqldf ), die ich täglich benutze.
Beispielverkaufsdaten erstellen
Verwenden Sie transform (), um eine Spalte hinzuzufügen
Verwenden Sie subset (), um die Daten zu schneiden
Verwenden Sie sqldf (), um mit SQL zu schneiden und zu aggregieren
Das sqldf-Paket bietet eine SQL-Schnittstelle für R-Datenrahmen
Führen Sie eine Aggregation oder GROUP BY durch
Weitere Informationen zu kartenreduzierenden Funktionen für Datenrahmen finden Sie im plyr- Paket. Und wenn Sie sich die Haare ausreißen möchten, empfehlen wir Ihnen, die Datenmanipulation mit R zu überprüfen .
quelle
Teilmengen von 'x []' werden gemittelt, wobei jede Teilmenge aus Beobachtungen mit denselben Faktorstufen besteht. Verwendung: ave (x, ..., FUN = Mittelwert)
Ich benutze es die ganze Zeit. (zB in dieser Antwort hier bei so )
quelle
Eine Möglichkeit, Code zu beschleunigen und for-Schleifen zu entfernen.
anstelle von for-Schleifen, die einen Datenrahmen durchlaufen und nach Werten suchen. Nehmen Sie einfach eine Teilmenge des df mit diesen Werten, viel schneller.
also statt:
mach so etwas:
Dieses Basiskonzept ist extrem häufig anwendbar und eine großartige Möglichkeit, Schleifen loszuwerden
quelle
Manchmal müssen Sie
rbind
mehrere Datenrahmen verwenden.do.call()
lassen Sie das tun (jemand musste mir dies erklären, als ich diese Frage stellte, da es keine offensichtliche Verwendung zu sein scheint).quelle
unsplit
.In R - Programmierung (nicht interaktive Sitzungen), verwende ich
if (bad.condition) stop("message")
eine Menge . Jede Funktion beginnt mit einigen davon, und während ich Berechnungen durcharbeite, pfeffere ich diese auch ein. Ich glaube, ich habe mir angewöhnt,assert()
C zu verwenden. Die Vorteile sind zweifach. Erstens ist es viel schneller, mit diesen Überprüfungen Arbeitscode zu erhalten. Zweitens, und wahrscheinlich noch wichtiger, ist es viel einfacher, mit vorhandenem Code zu arbeiten, wenn Sie diese Überprüfungen auf jedem Bildschirm in Ihrem Editor sehen. Sie müssen sich nicht fragen, obx>0
oder einem Kommentar vertrauen, der besagt, dass es ... Sie werden auf einen Blick wissen , dass es ist.PS. Mein erster Beitrag hier. Sei sanft!
quelle
stopfifnot(!bad.condition)
der prägnanter ist.Die
traceback()
Funktion ist ein Muss, wenn Sie irgendwo einen Fehler haben und ihn nicht ohne weiteres verstehen. Es wird eine Spur des Stapels gedruckt, was sehr hilfreich ist, da R standardmäßig nicht sehr ausführlich ist.Mit dieser Einstellung
options(error=recover)
können Sie in die Funktion "eintreten", die den Fehler auslöst, und versuchen zu verstehen, was genau passiert, als ob Sie die volle Kontrolle darüber hätten und eine darin einfügen könntenbrowser()
.Diese drei Funktionen können beim Debuggen Ihres Codes wirklich helfen.
quelle
options(error=recover)
ist meine Lieblings-Debugging-Methode.Ich bin wirklich überrascht, dass niemand über bewerben, tapply, lapply und sapply geschrieben hat. Eine allgemeine Regel, die ich beim Ausführen von Dingen in R verwende, lautet: Wenn ich eine for-Schleife habe, die Daten verarbeitet oder simuliert, versuche ich, sie herauszufiltern und durch ein * apply zu ersetzen. Einige Leute scheuen die * Apply-Funktionen, weil sie denken, dass nur einzelne Parameterfunktionen übergeben werden können. Nichts könnte weiter von der Wahrheit entfernt sein! Wie das Weitergeben von Funktionen mit Parametern als erstklassige Objekte in Javascript tun Sie dies in R mit anonymen Funktionen. Beispielsweise:
(Für diejenigen, die #rstats folgen, habe ich dies auch dort gepostet).
Denken Sie daran, verwenden Sie anwenden, sapply, lapply, tapply und do.call! Nutzen Sie die Vektorisierung von R. Sie sollten niemals zu einem Haufen R-Code gehen und sehen:
Dies wird nicht nur nicht vektorisiert, sondern die Array-Struktur in R wird nicht wie in Python vergrößert (Verdoppelung der Größe, wenn der Speicherplatz knapp wird, IIRC). Daher muss jeder rbind-Schritt zuerst l genug wachsen, um die Ergebnisse von rbind () zu akzeptieren, und dann den gesamten Inhalt des vorherigen l kopieren. Versuchen Sie zum Spaß das Obige in R. Beachten Sie, wie lange es dauert (Sie benötigen nicht einmal Rprof oder eine Timing-Funktion). Dann versuche es
Folgendes ist auch besser als die erste Version:
quelle
Auf Dirks Rat hin veröffentliche ich einzelne Beispiele. Ich hoffe, sie sind nicht zu "süß" [klug, aber es ist mir egal] oder trivial für dieses Publikum.
Lineare Modelle sind das A und O von R. Wenn die Anzahl der unabhängigen Variablen hoch ist, hat man zwei Möglichkeiten. Die erste besteht darin, lm.fit () zu verwenden, das ähnlich wie Matlab die Entwurfsmatrix x und die Antwort y als Argumente empfängt. Der Nachteil dieses Ansatzes besteht darin, dass der Rückgabewert eine Liste von Objekten (angepasste Koeffizienten, Residuen usw.) ist, nicht ein Objekt der Klasse "lm", das gut zusammengefasst werden kann und zur Vorhersage, schrittweisen Auswahl usw. verwendet wird. Der zweite Ansatz ist eine Formel zu erstellen:
quelle
Sie können einen Wert zuweisen, der von einem if-else-Block zurückkehrt.
Anstelle von z
du kannst tun
Wie genau das funktioniert, ist tiefe Magie.
quelle
if-then-else
funktionieren Ausdrücke in jeder funktionalen Sprache (nicht zu verwechseln mitif-then-else
Aussagen ). Sehr ähnlich dem ternären?:
Operator von C-ähnlichen Sprachen.Als absoluter Neuling bei R und Anfänger bei Statistiken liebe ich es
unclass()
, alle Elemente eines Datenrahmens als gewöhnliche Liste zu drucken.Es ist ziemlich praktisch, einen vollständigen Datensatz auf einmal zu betrachten, um potenzielle Probleme schnell zu erkennen.
quelle
CrossTable()
Dasgmodels
Paket bietet einfachen Zugriff auf Kreuztabellen im SAS- und SPSS-Stil sowie die üblichen Tests (Chisq, McNemar usw.). Grundsätzlich ist esxtabs()
mit ausgefallener Ausgabe und einigen zusätzlichen Tests - aber es erleichtert das Teilen der Ausgabe mit den Heiden.quelle
Auf jeden Fall
system()
. Der Zugriff auf alle Unix-Tools (zumindest unter Linux / MacOSX) aus der R-Umgebung heraus ist in meinem täglichen Workflow schnell von unschätzbarem Wert geworden.quelle
help(connections)
für Details und Beispiele.Hier ist eine lästige Problemumgehung, um einen Faktor in eine Zahl umzuwandeln. (Ähnliches gilt auch für andere Datentypen)
quelle
as.numeric(levels(old.var))[old.var]
Obwohl diese Frage schon eine Weile offen ist, habe ich kürzlich im SAS- und R-Blog einen großartigen Trick für die Verwendung des Befehls entdeckt
cut
. Der Befehl wird verwendet, um Daten in Kategorien zu unterteilen. Ich werde den Iris-Datensatz als Beispiel verwenden und ihn in 10 Kategorien unterteilen:quelle
Ein weiterer Trick. Einige Pakete, wie z. B. glmnet, verwenden nur die Entwurfsmatrix und die Antwortvariable als Eingaben. Wenn man ein Modell mit allen Interaktionen zwischen Merkmalen anpassen möchte, kann man die Formel "y ~. ^ 2" nicht verwenden. Die Verwendung
expand.grid()
ermöglicht es uns, die leistungsstarken Array-Indizierungs- und Vektoroperationen von R zu nutzen.quelle
model.matrix
?Einer meiner Lieblingstricks, wenn auch nicht etwas unorthodoxe, ist die Verwendung von
eval()
undparse()
. Dieses Beispiel zeigt vielleicht, wie hilfreich es sein kannDiese Art von Situation tritt häufig auf
eval()
undparse()
kann verwendet werden, um sie anzugehen. Natürlich freue ich mich über Feedback zu alternativen Codierungsmethoden.quelle
set.seed()
Legt den Status des Zufallszahlengenerators fest.Beispielsweise:
quelle
Für diejenigen, die C schreiben,
.Internal(inspect(...))
ist es praktisch, von R: aufgerufen zu werden . Beispielsweise:quelle
d = '~ / R Code / Library /'
files = list.files (d, '. r $')
für (f in Dateien) {if (! (f == 'mysource.r')) {print (Einfügen ('Sourcing', f)) Quelle (Einfügen (d, f, sep = ''))}}
Ich verwende den obigen Code, um alle Dateien in einem Verzeichnis beim Start mit verschiedenen Hilfsprogrammen zu beschaffen, die ich in meiner interaktiven Sitzung mit R verwende. Ich bin sicher, dass es bessere Möglichkeiten gibt, aber ich finde es nützlich für meine Arbeit. Die Zeile, die dies tut, ist wie folgt.
Quelle ("~ / R Code / Library / mysource.r")
quelle
Ausführen einer Operation für eine Reihe von Variablen in einem Datenrahmen. Dies wird aus subset.data.frame gestohlen.
quelle
get.vars
ohne durch eine ganze Reihe von Reifen zu springen.Ich habe das schon einmal gepostet, aber ich benutze es so oft, dass ich dachte, ich würde es wieder posten. Es ist nur eine kleine Funktion, um die Namen und Positionsnummern eines data.frame zurückzugeben. Es ist zwar nichts Besonderes, aber ich schaffe es fast nie durch eine Sitzung, ohne es mehrmals zu benutzen.
namesind = function (df) {
}}
ni <- namesind
quelle
data.frame(VAR = names(df), COL = seq_along(df))