Trik R apa yang paling berguna? [Tutup]

88

Untuk berbagi lebih banyak tip dan trik untuk R , apa fitur atau trik Anda yang paling berguna? Vektorisasi pintar? Masukan / keluaran data? Visualisasi dan grafik? Analisis statistik? Fungsi khusus? Lingkungan interaktif itu sendiri?

Satu item per posting, dan kami akan melihat apakah kami mendapatkan pemenang melalui voting.

[Sunting 25-Agustus 2008]: Jadi setelah satu minggu, tampaknya yang sederhana str()memenangkan jajak pendapat. Karena saya sendiri yang ingin merekomendasikannya, ini adalah jawaban yang mudah untuk diterima.

Dirk Eddelbuettel
sumber
8
@Dirk: "wiki komunitas" berarti "milik komunitas", bukan sinonim untuk "pertanyaan polling". Jangan mendengarkan polisi wiki komunitas.
Juliet
4
Mempertimbangkan meta.stackexchange.com/questions/11740/… seharusnya CW.
dmckee --- kucing mantan moderator
8
CW bullying lagi. Saya akan melihat meta-SO Anda dan membesarkan Anda: meta.stackexchange.com/questions/392/…
ars
13
@ars: ini adalah pertanyaan yang tidak memiliki jawaban pasti . Ergo membuatnya menjadi CW.
dmckee --- ex-moderator anak kucing
2
@JD Long komen kocak. sayangnya itu tersembunyi di balik flip. Maksud saya, menjawab pertanyaan R yang sulit tidak benar-benar bermanfaat. Jadi tidak apa-apa bagi saya jika orang yang memberikan pertanyaan bagus yang menempatkan R di peta akhirnya mendapatkan pujian. Selain itu, hal ini tentunya lebih berguna bagi pengguna R daripada pertanyaan trik C favorit Anda bagi pemrogram C ...
Matt Bannert

Jawaban:

64

str() memberi tahu Anda struktur objek apa pun.

hadley
sumber
Penggunaan Python dir()- lebih masuk akal.
Hamish Grubijan
17
Ah, strjuga kependekan dari stringbanyak bahasa.
Hamish Grubijan
Mengapa tidak class()? Tampaknya mengungkapkan jenis informasi yang serupa. Mengapa ada dua perintah yang serupa?
hhh
1
class()hanyalah sebagian kecil dari informasi yang str()ditampilkan
hadley
64

Salah satu fungsi yang sangat berguna yang sering saya gunakan adalah dput (), yang memungkinkan Anda membuang objek dalam bentuk kode 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")

Akan sangat berguna untuk mengeposkan potongan data yang dapat direproduksi dengan mudah saat Anda meminta bantuan, atau untuk mengedit atau menyusun ulang level suatu faktor.

juba
sumber
42

head () dan tail () untuk mendapatkan bagian pertama dan terakhir dari kerangka data, vektor, matriks, fungsi, dll. Khususnya dengan bingkai data besar, ini adalah cara cepat untuk memeriksa apakah telah dimuat dengan baik.

Rob Hyndman
sumber
38

Satu fitur bagus: Membaca data menggunakan koneksi yang dapat berupa file lokal, file jarak jauh diakses melalui http, pipa dari program lain atau lebih.

Sebagai contoh sederhana, pertimbangkan akses ini untuk N = 10 bilangan bulat acak antara min = 100 dan max = 200 dari random.org (yang menyediakan bilangan acak sebenarnya berdasarkan kebisingan atmosfer daripada generator bilangan acak semu):

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>

Sebagai tambahan, paket acak menyediakan beberapa fungsi kemudahan untuk mengakses random.org .

Dirk Eddelbuettel
sumber
BTW Saya akan menyarankan bahwa Anda harus membuat selfanswers CW jika (1) Anda posting mereka segera dan (2) Anda tidak membuat pertanyaan CW. Jika tidak, sepertinya Anda mencoba mempermainkan sistem rep. YMMV dan semua itu.
dmckee --- kucing mantan moderator
1
Ini bukan mempermainkan sistem, hanya memulai sesuatu. Dia masih bebas menerima jawaban lain.
ars
2
@ars: Dia bebas menerima yang ini. Saya juga tidak akan berusaha memaksanya untuk menulis wiki jika dia tidak mau menuruti nasihat saya. Tetapi saya tidak akan memposting jawaban mandiri yang telah disiapkan tanpa menandainya sebagai wiki, dan saya juga tidak akan memilih yang tanpa itu. Ambillah itu untuk apa nilainya.
dmckee --- ex-moderator anak kucing
4
@ Dirk: sepenuhnya dapat diterima, bahkan didorong oleh Jeff dan Joel, untuk menjawab pertanyaan Anda sendiri. TIDAK ada persyaratan, bahkan yang informal sekalipun, untuk membuat jawaban Anda CW. Anda jelas tidak mempermainkan sistem. Sekali lagi, abaikan saja polisi wiki komunitas.
Juliet
8
Saya harus setuju bahwa bagian dari tujuan situs adalah memberikan jawaban terbaik untuk masalah umum dan sumber daya umum. Mengajukan pertanyaan dan memberikan jawaban yang baik dapat membantu memperkuat suatu topik. Ini sangat berguna dengan tag baru / kecil seperti R.
kpierce8
35

Saya merasa saya sedang menggunakan with()dan within()lebih banyak lagi. Tidak ada lagi $mengotori kode saya dan seseorang tidak perlu mulai melampirkan objek ke jalur pencarian. Lebih serius lagi, saya menemukan with()dll membuat maksud dari skrip analisis data saya jauh lebih jelas.

> 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()menyiapkan lingkungan di mana ekspresi R dievaluasi. within()melakukan hal yang sama tetapi memungkinkan Anda untuk memodifikasi objek data yang digunakan untuk membuat lingkungan.

> 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

Sesuatu yang tidak saya sadari ketika saya pertama kali menggunakan within()adalah bahwa Anda harus melakukan tugas sebagai bagian dari ekspresi yang dievaluasi dan menetapkan objek yang dikembalikan (seperti di atas) untuk mendapatkan efek yang diinginkan.

Gavin Simpson
sumber
34

Trik Masukan Data = paket RGoogleDocs

http://www.omegahat.org/RGoogleDocs/

Menurut saya, Google spreadsheet merupakan cara yang luar biasa bagi semua kolaborator untuk berada di halaman yang sama. Selain itu, Formulir Google memungkinkan seseorang untuk mengambil data dari responden dan dengan mudah menulisnya ke spreadsheet Google. Karena data sering berubah dan hampir tidak pernah final, jauh lebih baik bagi R untuk membaca spreadsheet Google secara langsung daripada langsung mengunduh file csv dan membacanya.

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

Saya tidak dapat mengingat yang mana kecuali satu atau dua dari perintah berikut membutuhkan beberapa detik.

  1. getGoogleAuth

  2. getGoogleDocsConnection

  3. getWorksheets

Farrel
sumber
27

Gunakan backticks untuk mereferensikan nama non standar.

> 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

Dalam hal ini, df [, "1"] juga akan berfungsi. Tapi kutu belakang bekerja di dalam formula!

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

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

Coefficients:
(Intercept)          `1`  
     0.4087      -0.3440  

[Sunting] Dirk bertanya mengapa seseorang memberikan nama yang tidak valid? Saya tidak tahu! Tapi dalam prakteknya saya cukup sering menghadapi masalah ini. Misalnya, menggunakan paket pembentukan kembali 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
Eduardo Leoni
sumber
Oke, tapi mengapa Anda perlu mengganti nama yang valid secara sintaksis (seperti x atau y) dengan yang tidak valid (seperti 1 atau 2) yang membutuhkan backticks?
Dirk Eddelbuettel
3
Ini juga berguna read.tablejika check.namessalah - yaitu saat Anda ingin bekerja dengan nama kolom asli.
hadley
25

Tidak tahu seberapa terkenal ini / tidak, tetapi sesuatu yang pasti saya manfaatkan adalah kemampuan referensi lewat lingkungan.

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

Untuk contoh ini tidak masuk akal mengapa ini berguna, tetapi jika Anda melewati objek besar di sekitarnya, itu dapat membantu.

geoffjentry
sumber
23

Hal favorit baru saya adalah perpustakaan foreach. Ini memungkinkan Anda melakukan semua hal terapan yang bagus, tetapi dengan sintaks yang agak lebih mudah:

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

Bagian terbaiknya adalah jika Anda melakukan sesuatu yang sebenarnya membutuhkan banyak waktu, Anda dapat beralih dari %do%ke %dopar%(dengan pustaka backend yang sesuai) untuk memparalelkan secara instan, bahkan di seluruh kluster. Sangat apik.

JAShapiro
sumber
19

Saya melakukan banyak manipulasi data dasar, jadi berikut adalah dua fungsi built-in ( transform , subset ) dan satu library ( sqldf ) yang saya gunakan setiap hari.

membuat contoh data penjualan

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

gunakan transform () untuk menambahkan kolom

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

gunakan subset () untuk memotong data

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

>
  product  revenue
1       1 108.4597
4       2 100.3475

gunakan sqldf () untuk mengiris dan menggabungkan dengan SQL

The paket sqldf menyediakan sebuah antarmuka SQL untuk data frame R

##  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

Lakukan agregasi atau GROUP BY

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

Untuk fungsionalitas seperti pengurangan peta yang lebih canggih pada bingkai data, lihat paket plyr . Dan jika menemukan diri Anda ingin menarik rambut Anda, saya sarankan memeriksa Manipulasi Data dengan R .

medriscoll
sumber
18
?ave

Subset dari 'x []' dirata-ratakan, di mana setiap subset terdiri dari observasi dengan tingkat faktor yang sama. Penggunaan: ave (x, ..., FUN = mean)

Saya menggunakannya sepanjang waktu. (misalnya dalam jawaban ini di sini )

Eduardo Leoni
sumber
apa bedanya dengan tapply (x, factor, fun) ??
TMS
1
@Tomas ave mempertahankan pemesanan dan panjangnya. jadi Anda bisa, misalnya, menambahkan vektor dari group means ke dataset, dalam satu langkah.
Eduardo Leoni
18

Cara untuk mempercepat kode dan menghilangkan loop.

bukannya untuk loop yang mengulang melalui dataframe mencari nilai. ambil saja subset dari df dengan nilai tersebut, lebih cepat.

jadi alih-alih:

for(i in 1:nrow(df)){
  if (df$column[i] == x) {
    df$column2[i] <- y
    or any other similiar code
  }
}

lakukan sesuatu seperti ini:

df$column2[df$column1 == x] <- y

konsep dasar itu sangat sering diterapkan dan merupakan cara terbaik untuk menghilangkan loop

Dan
sumber
11
Ada jebakan kecil di sini yang biasa menangkap saya sepanjang waktu. Jika df $ column1 berisi nilai NA, subset menggunakan == akan menarik nilai apa pun yang sama dengan x dan NAs apa pun. Untuk menghindarinya, gunakan "% in%" daripada "==".
Matt Parker
Matt kau benar sekali dan itu sesuatu yang aku benci, aku suka metodemu. Saya biasanya memeriksa kolom untuk NAs dan kemudian menghapusnya dengan fungsi cepat yang saya buat yang mengambil kolom dataframe dan mengembalikan baris dataframe minus dengan NAs hanya di kolom itu.
Dan
pada dasarnya, saya membagi kerangka data ke kolom yang saya perlukan untuk memiliki nilai kemudian menggunakan na.omit untuk mendapatkan baris yang benar dan kemudian subset dataset asli hanya dengan baris tersebut. Hanya menggunakan na.omit akan menghapus baris apa pun dengan NA apa pun, saya bisa saja salah.
Dan
16

Terkadang Anda perlu rbindbeberapa bingkai data. do.call()akan membiarkan Anda melakukan itu (seseorang harus menjelaskan hal ini kepada saya ketika mengikat saya mengajukan pertanyaan ini, karena tampaknya ini bukan penggunaan yang jelas).

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)
andrewj
sumber
Keputusan yang bagus: Saya menemukan bahwa ini seringkali lebih sederhana daripada menggunakan unsplit.
Richie Cotton
16

Dalam pemrograman R (bukan sesi interaktif), saya menggunakan if (bad.condition) stop("message")sebuah banyak . Setiap fungsi dimulai dengan beberapa di antaranya, dan saat saya mengerjakan komputasi, saya juga memasukkannya ke dalamnya. Sepertinya saya terbiasa menggunakan assert()C. Manfaatnya dua kali lipat. Pertama, jauh lebih cepat untuk mendapatkan kode yang berfungsi dengan pemeriksaan ini. Kedua, dan mungkin yang lebih penting, jauh lebih mudah untuk bekerja dengan kode yang ada saat Anda melihat pemeriksaan ini di setiap layar di editor Anda. Anda tidak perlu bertanya-tanya apakah x>0, atau percaya pada komentar yang menyatakan bahwa itu ... Anda akan tahu , dari sekilas, bahwa itu benar.

PS. posting pertama saya disini. Bersikaplah lembut!

lembab
sumber
12
Bukan kebiasaan buruk, dan R menawarkan cara lain: stopfifnot(!bad.condition)yang lebih ringkas.
Dirk Eddelbuettel
13

The traceback()Fungsi adalah suatu keharusan ketika Anda memiliki suatu tempat kesalahan dan tidak mengerti mudah. Ini akan mencetak jejak tumpukan, sangat membantu karena R tidak terlalu bertele-tele secara default.

Kemudian pengaturan options(error=recover)akan memungkinkan Anda untuk "masuk" ke dalam fungsi yang meningkatkan kesalahan dan mencoba dan memahami apa yang sebenarnya terjadi, seolah-olah Anda memiliki kendali penuh atas hal itu dan dapat memasukkannya browser()ke dalamnya.

Ketiga fungsi ini benar-benar dapat membantu men-debug kode Anda.

Calimo
sumber
1
options(error=recover)adalah metode debugging favorit saya.
Joshua Ulrich
12

Saya benar-benar terkejut tidak ada yang memposting tentang apply, tapply, lapply, dan sapply. Aturan umum yang saya gunakan saat melakukan hal-hal di R adalah jika saya memiliki loop for yang melakukan pemrosesan atau simulasi data, saya mencoba memfaktorkannya dan menggantinya dengan * apply. Beberapa orang menghindar dari fungsi * apply karena mereka pikir hanya fungsi parameter tunggal yang dapat diteruskan. Tidak ada yang bisa lebih jauh dari kebenaran! Seperti meneruskan fungsi dengan parameter sebagai objek kelas pertama dalam Javascript, Anda melakukan ini di R dengan fungsi anonim. Sebagai contoh:

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

(Bagi mereka yang mengikuti #rstats, saya juga memposting ini di sana).

Ingat, gunakan apply, sapply, lapply, tapply, dan do.call! Ambil keuntungan dari vektorisasi R. Anda tidak boleh berjalan ke sekumpulan kode R dan melihat:

N = 10000
l = numeric()
for (i in seq(1:N)) {
    sim <- rnorm(1, 0, 1)
    l <- rbind(l, sim)
}

Ini tidak hanya tidak vektor, tetapi struktur array di R tidak tumbuh seperti di Python (menggandakan ukuran saat ruang habis, IIRC). Jadi setiap langkah rbind pertama-tama harus tumbuh cukup untuk menerima hasil dari rbind (), lalu salin semua konten l sebelumnya. Untuk bersenang-senang, coba yang di atas di R. Perhatikan berapa lama waktu yang dibutuhkan (Anda bahkan tidak perlu Rprof atau fungsi pengaturan waktu). Kalau begitu coba

N=10000
l <- rnorm(N, 0, 1)

Berikut ini juga lebih baik dari versi pertama:

N = 10000
l = numeric(N)
for (i in seq(1:N)) {
    sim <- rnorm(1, 0, 1)
    l[i] <- sim
}
Vince
sumber
apply, sapply, lapply dan tapply berguna. Jika Anda ingin meneruskan parameter ke fungsi bernama seperti round, Anda bisa meneruskannya dengan apply daripada menulis fungsi anonim. Coba "sapply (rnorm (10, 0, 1), round, digits = 2)" yang menghasilkan "[1] -0.29 0.29 1.31 -0.06 -1.90 -0.84 0.21 0.02 0.23 -1.10".
Daniel
11

Atas saran Dirk, saya memposting satu contoh. Saya berharap mereka tidak terlalu "manis" [pintar, tapi saya tidak peduli] atau remeh untuk penonton ini.

Model linier adalah roti dan mentega dari R. Ketika jumlah variabel independen tinggi, seseorang memiliki dua pilihan. Yang pertama adalah menggunakan lm.fit (), yang menerima matriks desain x dan respons y sebagai argumen, mirip dengan Matlab. Kelemahan dari pendekatan ini adalah bahwa nilai yang dikembalikan adalah daftar objek (koefisien yang dipasang, residual, dll), bukan objek kelas "lm", yang dapat diringkas dengan baik, digunakan untuk prediksi, pemilihan bertahap, dll. Pendekatan membuat rumus:

> 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  
gappy
sumber
Bagaimana jika Anda memilih satu per posting dan mengilustrasikan dengan contoh? Kami kemudian dapat terus berjalan selama berhari-hari dan mengirim contoh baru dengan perintah baru ... [BTW: Seingat saya, Anda memerlukan as.formula (paste (...)) untuk penggunaan rumus. ]
Dirk Eddelbuettel
Anda tidak memerlukan pembuatan rumus secara eksplisit untuk mencakup semua kolom karena formulir "y ~. - 1" mencakupnya. The "." berarti 'semua kolom kecuali variabel dependen, dan' - 1 'tidak termasuk konstanta seperti pada contoh Anda.
Dirk Eddelbuettel
Itu benar untuk contoh khusus ini, tetapi untuk X dengan ncols >> nrows, saya sering menghapus beberapa variabel independen, terutama pada tahap akhir analisis. Dalam hal ini, membuat rumus dari nama bingkai data masih berguna.
gappy
10

Anda dapat menetapkan nilai yang dikembalikan dari blok if-else.

Dari pada, mis

condition <- runif(1) > 0.5
if(condition) x <- 1 else x <- 2

Anda dapat melakukan

x <- if(condition) 1 else 2

Cara kerjanya adalah sihir yang dalam.

Richie Cotton
sumber
6
Anda juga dapat melakukan ini seperti x <- ifelse (condition, 1, 2), dalam hal ini setiap komponen divektorisasi.
Shane
Shane, Anda bisa, tetapi kecuali Anda benar-benar memahami apa yang dilakukan ifelse (), Anda mungkin tidak boleh melakukannya! Sangat mudah untuk salah paham ...
Harlan
Apa yang ajaib tentang itu? Itulah cara if-then-elseekspresi bekerja dalam bahasa fungsional apa pun (jangan disamakan dengan if-then-else pernyataan ). Sangat mirip dengan ?:operator terner bahasa mirip C.
Frank
10

Sebagai pemula total untuk R dan pemula di statistik, saya suka unclass() mencetak semua elemen bingkai data sebagai daftar biasa.

Ini sangat berguna untuk melihat kumpulan data lengkap sekaligus untuk melihat dengan cepat masalah potensial apa pun.

John
sumber
9

CrossTable()dari gmodelspaket menyediakan akses mudah ke tab silang gaya SAS dan SPSS, bersama dengan pengujian biasa (Chisq, McNemar, dll.). Pada dasarnya, ini xtabs()dengan keluaran mewah dan beberapa tes tambahan - tetapi itu membuat keluaran berbagi dengan kafir lebih mudah.

Matt Parker
sumber
Bagus!! Saya cukup sering menggunakan gmodels, tapi melewatkan yang itu
Abhijit
Jawaban yang bagus, apapun yang dapat menjauhkan saya dari penjelasan tabel yang berlebihan dengan para kafir adalah penggunaan waktu yang baik.
Stedy
7

Pasti system(). Untuk dapat memiliki akses ke semua alat unix (setidaknya di Linux / MacOSX) dari dalam lingkungan R dengan cepat menjadi sangat berharga dalam alur kerja harian saya.

Paolo
sumber
1
Itu terkait dengan komentar saya sebelumnya tentang koneksi: Anda juga dapat menggunakan pipa () untuk meneruskan data dari, atau ke, perintah Unix. Lihat help(connections)detail dan contoh.
Dirk Eddelbuettel
6

Berikut adalah solusi yang mengganggu untuk mengubah faktor menjadi numerik. (Serupa untuk tipe data lain juga)

old.var <- as.numeric(levels(old.var))[as.numeric(old.var)]
Ryan Rosario
sumber
2
Mungkin yang Anda maksud adalah vektor "menjadi karakter". Dalam hal ini "as.character (old.var)" lebih sederhana.
Dirk Eddelbuettel
1
Saya selalu menganggap nasihat ini (yang dapat dibaca di? Faktor) salah arah. Anda harus memastikan old.var adalah faktor, dan ini akan bervariasi sesuai dengan opsi yang Anda tetapkan untuk sesi R. Menggunakan as.numeric (as.character (old.var)) lebih aman dan lebih bersih.
Eduardo Leoni
Benar-benar tidak layak untuk downvote, tapi terserah. Ini berhasil untuk saya.
Ryan R. Rosario
Ryan - Bisakah Anda memperbaiki kode Anda? Jika old.var <- factor (1: 2); kode Anda akan memberikan [1] "1" "2" (bukan numerik.) mungkin yang Anda maksud sebagai.numerik (level (old.var) [old.var])?
Eduardo Leoni
3
Atau sedikit lebih efisien:as.numeric(levels(old.var))[old.var]
hadley
6

Meskipun pertanyaan ini telah muncul untuk beberapa waktu, saya baru-baru ini menemukan trik hebat di blog SAS dan R untuk menggunakan perintah cut. Perintah tersebut digunakan untuk membagi data menjadi beberapa kategori dan saya akan menggunakan dataset iris sebagai contoh dan membaginya menjadi 10 kategori:

> 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]
Stedy
sumber
5

Trik lain. Beberapa paket, seperti glmnet, hanya menerima matriks desain dan variabel respons sebagai masukan. Jika seseorang ingin menyesuaikan model dengan semua interaksi antara fitur, dia tidak dapat menggunakan rumus "y ~. ^ 2". Menggunakan expand.grid()memungkinkan kita untuk memanfaatkan pengindeksan array yang kuat dan operasi vektor R.

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
gappy
sumber
3
Jika fungsi pemodelan tidak menerima rumus (yang sangat jarang!) Bukankah lebih baik untuk membuat matriks desain dengan model.matrix?
hadley
Bagus. Saya tidak tahu keberadaan fungsi ini. Fungsi di atas setara dengan model.matrix (~. ^ 2 -1, X) Tetapi mengenai matriks yang lewat, selain dari glmnet, saya sering melewatkan pointer array ke fungsi C kustom. Memang, saya tidak akan tahu cara meneruskan rumus ke suatu fungsi. Apakah Anda punya contoh mainan?
gappy
5

Salah satu trik favorit saya, jika bukan merupakan trik ortodoks, adalah penggunaan eval()dan parse(). Contoh ini mungkin menggambarkan bagaimana itu dapat membantu

NY.Capital <- 'Albany'
state <- 'NY'
parameter <- 'Capital'
eval(parse(text=paste(state, parameter, sep='.')))

[1] "Albany"

Jenis situasi ini terjadi lebih sering daripada tidak, dan penggunaan eval()dan parse()dapat membantu mengatasinya. Tentu saja, saya menyambut baik umpan balik tentang cara alternatif pengkodean ini.

andrewj
sumber
1
Ini bisa dilakukan juga dengan elemen vektor bernama.
Dirk Eddelbuettel
3
library (fortunes); fortune (106) Jika jawabannya adalah parse () Anda biasanya harus memikirkan kembali pertanyaannya. - Thomas Lumley R-help (Februari 2005)
Eduardo Leoni
Berikut adalah contoh di mana eval () dan parse () bisa berguna. Ini melibatkan paket Biokonduktor, misalnya hgu133a.db dan di mana Anda mencoba mendapatkan berbagai informasi tentang id probe. Misalnya: parameter library (hgu133a.db) <- '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
Seperti yang dikatakan Dirk, ini lebih baik dilakukan dengan elemen vektor bernama, atau `get (paste (state, parameter, sep = '.'))`
hadley
@Hadley, tidak tahu bahwa Anda bisa menggunakan get () seperti itu. Terima kasih.
andrewj
5

set.seed() mengatur status generator nomor acak.

Sebagai contoh:

> set.seed(123)
> rnorm(1)
[1] -0.5604756
> rnorm(1)
[1] -0.2301775
> set.seed(123)
> rnorm(1)
[1] -0.5604756
Christopher DuBois
sumber
sangat berguna dengan contoh-contoh yang menggunakan fungsi acak ... membantu membuat semua orang di halaman yang sama
JD Long
5

Bagi mereka yang menulis C untuk dipanggil dari R: .Internal(inspect(...))sangat berguna. Sebagai contoh:

> .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
Joshua Ulrich
sumber
4

d = '~ / Kode R / Perpustakaan /'

files = list.files (d, '. r $')

untuk (f dalam file) {if (! (f == 'mysource.r')) {print (paste ('Sourcing', f)) source (paste (d, f, sep = ''))}}

Saya menggunakan kode di atas untuk sumber semua file dalam direktori saat memulai dengan berbagai program utilitas yang saya gunakan dalam sesi interaktif saya dengan R. Saya yakin ada cara yang lebih baik tetapi saya merasa berguna untuk pekerjaan saya. Garis yang melakukan ini adalah sebagai berikut.

sumber ("~ / R Code / Library / mysource.r")

mcheema
sumber
6
Jangan lakukan itu. Tulis paket.
Dirk Eddelbuettel
Terima kasih. Saya telah melihat satu atau dua utas tentang roxygen dan tampaknya saya mungkin berada pada level di mana saya harus mencoba menulis paket penggunaan mandiri sederhana.
mcheema
3

Untuk melakukan operasi pada sejumlah variabel dalam bingkai data. Ini dicuri dari subset.data.frame.

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)
Ian Fellows
sumber
1
Ini tampak keren pada awalnya, tetapi kode semacam ini akan menyebabkan Anda mengalami masalah yang tidak ada habisnya dalam jangka panjang. Lebih baik bersikap eksplisit.
hadley
hum, saya telah menggunakan trik ini cukup banyak akhir-akhir ini. Bisakah Anda lebih spesifik tentang masalahnya yang tidak terbatas?
Ian Fellows
Mungkin hadley menyarankan untuk menggunakan paket plyr?
Christopher DuBois
3
Tidak, ini bukan saran terselubung untuk menggunakan plyr. Pada dasarnya masalah dengan kode Anda adalah bahwa kode itu malas secara semantik - alih-alih membuat pengguna secara eksplisit mengeja apa yang mereka inginkan, Anda melakukan "sihir" untuk menebak. Masalahnya adalah hal ini membuat fungsi menjadi sangat sulit untuk diprogram - yaitu sulit untuk menulis fungsi yang memanggil get.varstanpa melewati banyak rintangan.
hadley
3

Saya telah memposting ini sekali sebelumnya tetapi saya sering menggunakannya sehingga saya pikir saya akan mempostingnya lagi. Ini hanya sedikit fungsinya untuk mengembalikan nama dan nomor posisi dari data.frame. Tidak ada yang istimewa untuk memastikannya, tetapi saya hampir tidak pernah berhasil melewati sesi tanpa menggunakannya beberapa kali.

##creates an object from a data.frame listing the column names and location

namesind = fungsi (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

kpierce8.dll
sumber
4
Ini benar-benar satu kalimat:data.frame(VAR = names(df), COL = seq_along(df))
hadley
sangat elegan, mungkin saya akan mengubahnya ke ni <- function (df) {data.frame (VAR = names (df), COL = seq_along (df))}
kpierce8
1
Saya menggunakan: data.frame (colnames (the.df))
Tal Galili