Bagaimana cara menghapus banyak nilai dari suatu vektor?

125

Saya memiliki vektor seperti: a = c(1:10)dan saya perlu menghapus beberapa nilai, seperti:2, 3, 5

Bagaimana cara menghapus angka-angka itu ( BUKAN posisi dalam vektor) di vektor?

saat ini saya loop vektor dan melakukan sesuatu seperti:

a[!a=NUMBER_TO_REMOVE]

Tapi saya pikir ada fungsi yang melakukannya secara otomatis.

Dail
sumber

Jawaban:

192

The %in%Operator memberitahu Anda yang unsur antara numers untuk menghapus:

> a <- sample (1 : 10)
> remove <- c (2, 3, 5)
> a
 [1] 10  5  2  7  1  6  3  4  8  9
> a %in% remove
 [1] FALSE  TRUE  TRUE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE
> a [! a %in% remove]
 [1] 10  7  1  6  4  8  9

Perhatikan bahwa ini akan secara diam-diam menghapus yang tidak dapat dibandingkan (hal-hal seperti NAatau Inf)juga (sementara itu akan menjaga nilai duplikat aselama mereka tidak terdaftar di remove).

  • Jika adapat berisi yang tak tertandingi, tetapi removetidak akan, kita bisa menggunakan match, mengatakan itu untuk kembali 0untuk yang tidak cocok dan tak tertandingi ( %in%adalah jalan pintas yang mudah untuk match):

    > a <- c (a, NA, Inf)
    > a
     [1]  10   5   2   7   1   6   3   4   8   9  NA Inf
    > match (a, remove, nomatch = 0L, incomparables = 0L)
     [1] 0 3 1 0 0 0 2 0 0 0 0 0
    > a [match (a, remove, nomatch = 0L, incomparables = 0L) == 0L]
    [1]  10   7   1   6   4   8   9  NA Inf

    incomparables = 0tidak diperlukan karena tidak ada bandingannya yang tidak akan cocok, tapi saya akan memasukkannya agar mudah dibaca.
    Ini, btw., Apa yang setdiffdilakukan secara internal (tetapi tanpa uniquemembuang duplikat ayang tidak ada di dalamnya remove).

  • Jika removemengandung yang tak tertandingi, Anda harus memeriksanya satu per satu, mis

    if (any (is.na (remove))) 
      a <- a [! is.na (a)]

    (Ini tidak membedakan NAdari NaNtetapi manual R anyways memperingatkan bahwa seseorang tidak boleh mengandalkan memiliki perbedaan di antara mereka)

    Untuk Inf/ -InfAnda harus memeriksa keduanya signdanis.finite

cbeleites tidak senang dengan SX
sumber
1
setdifflebih baik, karena melakukan segalanya dalam satu operasi, dan referensi vektor yang diubah hanya sekali.
Olexa
1
@Olexa: mengatur perbedaan tidak selalu sama dengan menghapus semua kejadian dari set angka yang diberikan dari vektor: itu akan menghapus duplikat ayang tidak ada removejuga. Jika itu bukan masalah, Anda juga bisa menggunakannya setdiff. setdiff, btw, menggunakan matchyang %in%merupakan jalan pintas.
cbeleites tidak senang dengan SX
97

Anda bisa menggunakannya setdiff.

Diberikan

a <- sample(1:10)
remove <- c(2, 3, 5)

Kemudian

> a
 [1] 10  8  9  1  3  4  6  7  2  5
> setdiff(a, remove)
[1] 10  8  9  1  4  6  7
Brian Diggs
sumber
1
sangat berguna ketika aadalah hasil dari fungsi lain sehingga Anda dapat melakukan hal-hal dalam satu baris, bukan 3 dan variabel temp
jf328
14
Ini akan menghasilkan hasil yang berbeda dari %in%solusi jika vektor input berisi duplikat (dalam hal setdiffini hanya akan mengembalikan set unik , yaitu tanpa duplikat)
talat
2
@docendodiscimus: fsetdiffdari data.tablepaket memiliki allbendera (bawaan F) yang memungkinkan untuk menjaga duplikat di vektor input.
Juergen
9

Anda dapat melakukannya sebagai berikut:

> x<-c(2, 4, 6, 9, 10) # the list
> y<-c(4, 9, 10) # values to be removed

> idx = which(x %in% y ) # Positions of the values of y in x
> idx
[1] 2 4 5
> x = x[-idx] # Remove those values using their position and "-" operator
> x
[1] 2 6

Segera

> x = x[ - which(x %in% y)]
ykpemre
sumber
1
apa yang Anda panggil daftar dalam contoh Anda adalah vektor, bukan?
patrick
Ya maksud saya vektor. Terima kasih atas komentarnya.
ykpemre
Tidak perlu di whichsini. Ini pada dasarnya sama dengan jawaban @cbeleites.
David Arenburg
ya itu mirip, tetapi berbeda dalam beberapa sudut pandang. whichmengembalikan indeks nilai TRUE. Jadi tanda minus dapat digunakan untuk mengatakan "indeks selain dari indeks ini". Juga whichlebih mudah dibaca karena lebih dekat dengan bahasa alami.
ykpemre
4

dari pada

x <- x[! x %in% c(2,3,5)]

menggunakan paket purrrdan magrittr, Anda dapat melakukan:

your_vector %<>% discard(~ .x %in% c(2,3,5))

ini memungkinkan untuk subsetmenggunakan nama vektor hanya sekali. Dan Anda bisa menggunakannya di pipa :)

krishan404
sumber
Bisakah Anda jelaskan pernyataan terakhir Anda tentang panjang nama variabel? Kenapa kamu tidak suka itu? Kenapa lebih baik dari cara lain? Atau, hapus paragraf itu karena tidak terkait dengan masalah / pertanyaan utama.
rodrigoap
2

Pertama kita dapat mendefinisikan operator baru,

"%ni%" = Negate( "%in%" )

Kemudian, seperti x tidak di hapus

x <- 1:10
remove <- c(2,3,5)
x <- x[ x %ni% remove ]

atau mengapa harus dihapus, langsung saja

x <- x[ x %ni% c(2,3,5)]
TheMI
sumber
3
Pertanyaannya secara spesifik mengatakan bahwa 2, 3 dan 5 bukan posisi dalam vektor.
blakeoft
1

MEMPERBARUI:

Semua jawaban di atas tidak akan berfungsi untuk nilai yang diulang, jawaban @ BenBolker menggunakan duplicated()predikat memecahkan ini:

full_vector[!full_vector %in% searched_vector | duplicated(full_vector)]

Jawaban Asli: di sini saya menulis sedikit fungsi untuk ini:

exclude_val<-function(full_vector,searched_vector){

      found=c()

      for(i in full_vector){  

        if(any(is.element(searched_vector,i))){
          searched_vector[(which(searched_vector==i))[1]]=NA
        }
        else{
          found=c(found,i)
        }
    }

    return(found)
}

jadi, katakan saja full_vector=c(1,2,3,4,1)dan searched_vector=c(1,2,3).

exclude_val(full_vector,searched_vector)akan kembali (4,1), namun jawaban di atas akan kembali dengan adil (4).

Özgür
sumber
1
bagaimana full_vector[!full_vector %in% searched_vector | duplicated(full_vector)]?
Ben Bolker
@ BenBolker ah saya tidak tahu bahwa predikat "duplikat": ((sekarang apa, haruskah saya menghapus jawaban saya atau mengubahnya hanya untuk menunjukkan milik Anda saja?
Özgür
@ BenBolker, solusi Anda salah; coba saja: full_vector = c(1,1,1,2,3); searched_vector = c(1,1,3);- yang menghasilkan 1, 1, 2alih-alih jawaban yang benar 1, 2.
fnl
Hanya untuk menambahkan kemungkinan, solusi yang benar untuk nilai yang diulang:removeif <- function(from, where) { for (i in where) if (i %in% from) {from = from[-match(i, from)]}; from}
fnl
1
q <- c(1,1,2,2,3,3,3,4,4,5,5,7,7)
rm <- q[11]
remove(rm)
q
q[13] = NaN
q
q %in% 7

Ini menetapkan 13 dalam vektor menjadi bukan angka (NAN) yang menunjukkan false remove (q [c (11,12,13)])) jika Anda mencoba ini, Anda akan melihat bahwa fungsi hapus tidak bekerja pada nomor vektor. Anda menghapus seluruh vektor tetapi mungkin bukan elemen tunggal.

Mahendra
sumber
1

Ada juga subsetyang kadang berguna:

a <- sample(1:10)
bad <- c(2, 3, 5)

> subset(a, !(a %in% bad))
[1]  9  7 10  6  8  1  4
Karolis Koncevičius
sumber