Was ist der nützlichste R-Trick? [geschlossen]


88

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.


8
@Dirk: "Community-Wiki" bedeutet "Community-Besitz", es ist kein Synonym für "Umfragefrage". Hören Sie nicht auf die Community-Wiki-Polizei.
Julia


8
CW wieder Mobbing. Ich werde Ihre Meta-SO sehen und Sie erhöhen: meta.stackexchange.com/questions/392/…
ars

13
@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 ...
Matt Bannert

Antworten:


64

str() sagt Ihnen die Struktur eines Objekts.


Python verwendet dir()- macht mehr Sinn.
Hamish Grubijan

17
Ah, strist auch stringin vielen Sprachen kurz.
Hamish Grubijan

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.


42

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.


38

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  V2
1 165 143
2 107 118
3 103 132
4 191 100
5 138 185
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.40444686  1.99368816  0.13871605 -1.17734837
 [6]  0.42473812  2.33014226  1.61690799  1.41901860  0.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 C
1 0.62635571 -0.5830079 1
2 0.04810539 -0.4525522 1
3 0.39706979  1.5966184 3
4 0.95802501 -0.8193090 2
5 0.76772541 -1.9450738 2
6 0.21335006  0.2113881 4

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.


34

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.

# Get data from google spreadsheet
library(RGoogleDocs)
ps <-readline(prompt="get the password in ")
auth = getGoogleAuth("me@gmail.com", 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.

  1. getGoogleAuth

  2. getGoogleDocsConnection

  3. getWorksheets


27

Verwenden Sie Backticks, um auf nicht standardmäßige Namen zu verweisen.

> df <- data.frame(x=rnorm(5),y=runif(5))
> names(df) <- 1:2
> df
           1         2
1 -1.2035003 0.6989573
2 -1.2146266 0.8272276
3  0.3563335 0.0947696
4 -0.4372646 0.9765767
5 -0.9952423 0.6477714
> df$1
Error: unexpected numeric constant in "df$1"
> df$`1`
[1] -1.2035003 -1.2146266  0.3563335 -0.4372646 -0.9952423

In diesem Fall würde auch df [, "1"] funktionieren. Aber Back Ticks funktionieren in Formeln!

> lm(`2`~`1`,data=df)

Call:
lm(formula = `2` ~ `1`, data = df)

Coefficients:
(Intercept)          `1`  
     0.4087      -0.3440  

[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)
1 1     4
2 2     6
> 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] 4 6

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.

zz <- new.env()
zz$foo <- c(1,2,3,4,5)
changer <- function(blah) {
   blah$foo <- 5
}
changer(zz)
zz$foo

In diesem Beispiel ist es nicht sinnvoll, warum es nützlich ist, aber wenn Sie große Objekte herumreichen, kann dies hilfreich sein.


23

Meine neue Lieblingssache ist die foreach-Bibliothek. Damit können Sie all die netten Dinge anwenden, aber mit einer etwas einfacheren Syntax:

list_powers <- foreach(i = 1:100) %do% {
  lp <- x[i]^i
  return (lp)
}

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.


19

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       1 108.45965
2      UK       1  97.07981
3      FR       1  99.66225
4     USA       2 100.34754
5      UK       2  87.12262
6      FR       2 112.86084
7     USA       3  95.87880
8      UK       3  96.43581
9      FR       3  94.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       1 108.45965 155.5311
2      UK       1  97.07981 139.2125
3      FR       1  99.66225 142.9157
...

Verwenden Sie subset (), um die Daten zu schneiden

subset(sales, 
       country == 'USA' & product %in% c(1, 2), 
       select = c('product', 'revenue'))

>
  product  revenue
1       1 108.4597
4       2 100.3475

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
1       1 108.4597
2       2 100.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.1157
2      UK 280.6382
3     USA 304.6860

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 .


18
?ave

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 )


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 in 1: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


11
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).

foo <- list()

foo[[1]] <- data.frame(a=1:5, b=11:15)
foo[[2]] <- data.frame(a=101:105, b=111:115)
foo[[3]] <- data.frame(a=200:210, b=300:310)

do.call(rbind, foo)

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.

PS. Mein erster Beitrag hier. Sei sanft!


12
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.


1
options(error=recover)ist meine Lieblings-Debugging-Methode.
Joshua Ulrich

12

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]  1  1  0  1  1 -1 -2  0  2  2 -2 -1  0  1 -1  0  1 -1  0 -1  0  0  0  0  0
 [26]  2  0 -1 -2  0  0  1 -1  1  5  1 -1  0  1  1  1  2  0 -1  1 -1  1  0 -1  1
 [51]  2  1  1 -2 -1  0 -1  2 -1  1 -1  1 -1  0 -1 -2  1  1  0 -1 -1  1  1  2  0
 [76]  0  0  0 -2 -1  1  1 -2  1 -1  1  1  1  0  0  0 -1 -3  0 -1  0  0  0  1  1


> 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.23  0.69 -1.43  0.76  0.55  0.96 -0.47 -0.81 -0.47
 [13]  0.27  0.32  0.47 -1.28 -1.44 -1.93  0.51 -0.82 -0.06 -1.41  1.23 -0.26
 [25]  0.22 -0.04 -2.17  0.60 -0.10 -0.92  0.13  2.62  1.03 -1.33 -1.73 -0.08
 [37]  0.45 -0.93  0.40  0.05  1.09 -1.23 -0.35  0.62  0.01 -1.08  1.70 -1.27
 [49]  0.55  0.60 -1.46  1.08 -1.88 -0.15  0.21  0.06  0.53 -1.16 -2.13 -0.03
 [61]  0.33 -1.07  0.98  0.62 -0.01 -0.53 -1.17 -0.28 -0.95  0.71 -0.58 -0.03
 [73] -1.47 -0.75 -0.54  0.42 -1.63  0.05 -1.90  0.40 -0.01  0.14 -1.58  1.37
 [85] -1.00 -0.90  1.69 -0.11 -2.19 -0.74  1.34 -0.75 -0.51 -0.99 -0.36 -1.63
 [97] -0.98  0.61  1.01  0.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
1  0.96852363 0.33827107 0.261332257 0.62817021 1.6425326
2  0.08012755 0.69159828 0.087994158 0.93780481 0.9801304
3  0.10167545 0.38119304 0.865209832 0.16501662 0.4830873
4  0.06699458 0.41756415 0.258071616 0.34027775 0.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.78236      0.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.5
if(condition) x <- 1 else x <- 2

du kannst tun

x <- if(condition) 1 else 2

Wie genau das funktioniert, ist tiefe Magie.


6
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-else Aussagen ). 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.


9

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.


1
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)

old.var <- as.numeric(levels(old.var))[as.numeric(old.var)]

2
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.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.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]

5

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.

interArray=function(X){
    n=ncol(X)
    ind=expand.grid(1:n,1:n)
    return(X[,ind[,1]]*X[,ind[,2]])
}

> X
          X1         X2
1 0.96852363 0.33827107
2 0.08012755 0.69159828
3 0.10167545 0.38119304
4 0.06699458 0.41756415
5 0.08187816 0.09805104

> interArray(X)
           X1          X2        X1.1        X2.1
1 0.938038022 0.327623524 0.327623524 0.114427316
2 0.006420424 0.055416073 0.055416073 0.478308177
3 0.010337897 0.038757974 0.038757974 0.145308137
4 0.004488274 0.027974536 0.027974536 0.174359821
5 0.006704033 0.008028239 0.008028239 0.009614007

3
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.


1
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.

Beispielsweise:

> set.seed(123)
> rnorm(1)
[1] -0.5604756
> rnorm(1)
[1] -0.2301775
> set.seed(123)
> rnorm(1)
[1] -0.5604756

Super nützlich mit Beispielen, die zufällige Funktionen verwenden ... hilft dabei, alle auf die gleiche Seite zu bringen
JD Long

5

Für diejenigen, die C schreiben, .Internal(inspect(...))ist es praktisch, von R: aufgerufen zu werden . Beispielsweise:

> .Internal(inspect(quote(a+2)))
  @867dc28 06 LANGSXP g0c0 [] 
  @8436998 01 SYMSXP g1c0 [MARK,gp=0x4000] "+"
  @85768b0 01 SYMSXP g1c0 [MARK,NAM(2)] "a"
  @8d7bf48 14 REALSXP g0c1 [] (len=1, tl=0) 2

4

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")


6
Tu es nicht. Schreiben Sie ein Paket.
Dirk Eddelbuettel

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.

get.vars<-function(vars,data){
    nl <- as.list(1L:ncol(data))
    names(nl) <- names(data)
    vars <- eval(substitute(vars), nl, parent.frame())
    data[,vars]
    #do stuff here
}

get.vars(c(cyl:hwy,class),mpg)

1
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

namesind = function (df) {

temp1=names(df)
temp2=seq(1,length(temp1))
temp3=data.frame(temp1,temp2)
names(temp3)=c("VAR","COL")
return(temp3)
rm(temp1,temp2,temp3)

}}

ni <- namesind


4
Dies ist wirklich ein data.frame(VAR = names(df), COL = seq_along(df))
Einzeiler

sehr elegant, vielleicht schalte ich es auf ni <- function (df) {data.frame (VAR = names (df), COL = seq_along (df))}
kpierce8

1
Ich benutze: data.frame (colnames (the.df))
Tal Galili
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.