Bir faktörü bilgi kaybı olmadan integer \ numeric'e nasıl dönüştürebilirim?


599

Bir faktörü sayısal veya tamsayıya dönüştürdüğümde, değerleri sayı olarak değil, temel düzey kodlarını alıyorum.

f <- factor(sample(runif(5), 20, replace = TRUE))
##  [1] 0.0248644019011408 0.0248644019011408 0.179684827337041 
##  [4] 0.0284090070053935 0.363644931698218  0.363644931698218 
##  [7] 0.179684827337041  0.249704354675487  0.249704354675487 
## [10] 0.0248644019011408 0.249704354675487  0.0284090070053935
## [13] 0.179684827337041  0.0248644019011408 0.179684827337041 
## [16] 0.363644931698218  0.249704354675487  0.363644931698218 
## [19] 0.179684827337041  0.0284090070053935
## 5 Levels: 0.0248644019011408 0.0284090070053935 ... 0.363644931698218

as.numeric(f)
##  [1] 1 1 3 2 5 5 3 4 4 1 4 2 3 1 3 5 4 5 3 2

as.integer(f)
##  [1] 1 1 3 2 5 5 3 4 4 1 4 2 3 1 3 5 4 5 3 2

pasteGerçek değerleri almak için başvurmak zorundayım :

as.numeric(paste(f))
##  [1] 0.02486440 0.02486440 0.17968483 0.02840901 0.36364493 0.36364493
##  [7] 0.17968483 0.24970435 0.24970435 0.02486440 0.24970435 0.02840901
## [13] 0.17968483 0.02486440 0.17968483 0.36364493 0.24970435 0.36364493
## [19] 0.17968483 0.02840901

Bir faktörü sayısal hale dönüştürmenin daha iyi bir yolu var mı?


6
Bir faktörün seviyeleri yine de karakter veri türü ( attributes(f)) olarak saklanır , bu yüzden yanlış bir şey olduğunu sanmıyorum as.numeric(paste(f)). Belki de (belirli bağlamda) ilk etapta neden bir faktör elde ettiğinizi düşünmek ve bunu durdurmaya çalışmak daha iyi olur. Örneğin, decargüman read.tabledoğru ayarlandı mı?
CJB

Bir veri çerçevesi kullanıyorsanız, hablar'dan convert kullanabilirsiniz. df %>% convert(num(column)). Veya bir faktör vektörünüz varsa kullanabilirsinizas_reliable_num(factor_vector)
davsjob

Yanıtlar:


711

Aşağıdakilerin Uyarı bölümüne bakın ?factor:

Özellikle, as.numericbir faktöre uygulanan anlamsızdır ve örtük zorlama ile meydana gelebilir. Bir faktörü fyaklaşık olarak orijinal sayısal değerlerine dönüştürmek için as.numeric(levels(f))[f]önerilir ve biraz daha verimlidir as.numeric(as.character(f)).

R hakkındaki SSS de benzer tavsiyelerde bulunuyor .


Neden as.numeric(levels(f))[f]daha etkilidir as.numeric(as.character(f))?

as.numeric(as.character(f))etkin olduğundan, değerler yerine as.numeric(levels(f)[f])sayısal length(x)değerler üzerinde dönüşüm gerçekleştiriyorsunuz nlevels(x). Hız farkı, az seviyeli uzun vektörler için en belirgin olacaktır. Değerler çoğunlukla benzersizse, hızda çok fazla fark olmayacaktır. Ancak dönüşümü yaparsanız, bu işlemin kodunuzdaki darboğaz olması olası değildir, bu yüzden çok fazla endişelenmeyin.


Bazı zamanlamalar

library(microbenchmark)
microbenchmark(
  as.numeric(levels(f))[f],
  as.numeric(levels(f)[f]),
  as.numeric(as.character(f)),
  paste0(x),
  paste(x),
  times = 1e5
)
## Unit: microseconds
##                         expr   min    lq      mean median     uq      max neval
##     as.numeric(levels(f))[f] 3.982 5.120  6.088624  5.405  5.974 1981.418 1e+05
##     as.numeric(levels(f)[f]) 5.973 7.111  8.352032  7.396  8.250 4256.380 1e+05
##  as.numeric(as.character(f)) 6.827 8.249  9.628264  8.534  9.671 1983.694 1e+05
##                    paste0(x) 7.964 9.387 11.026351  9.956 10.810 2911.257 1e+05
##                     paste(x) 7.965 9.387 11.127308  9.956 11.093 2419.458 1e+05

4
Zamanlamalar için şu cevaba bakınız: stackoverflow.com/questions/6979625/…
Ari B. Friedman

3
Çözümünüz için çok teşekkürler. As.numeric (düzey (f)) [f] 'nin neden daha kesin ve daha hızlı olduğunu sorabilir miyim? Teşekkürler.
Sam

7
@Sam as.character (f), as.numeric (level (f)) [f] olarak tanımlanan işlev.character.factor () işlevini bulmak için "ilkel arama" gerektirir.
Jonathan

12
as.numeric (düzey (f)) [f] VEYA as.numeric (as.character (f)) olarak uygulandığında, bir uyarı mesajı var: Uyarı mesajı: Zorlama ile getirilen NA'lar. Sorunun nerede olabileceğini biliyor musunuz? teşekkür ederim !
maycca

@maycca bu sorunun üstesinden geldin mi?
user08041991

91

R, faktörleri dönüştürmek için bir dizi (belgelenmemiş) kolaylık fonksiyonuna sahiptir:

  • as.character.factor
  • as.data.frame.factor
  • as.Date.factor
  • as.list.factor
  • as.vector.factor
  • ...

Ama can sıkıcı bir şekilde, faktör -> sayısal dönüşüm . Joshua Ulrich'in cevabının bir uzantısı olarak, bu ihmali kendi deyimsel işlevinizin tanımıyla aşmayı öneriyorum:

as.numeric.factor <- function(x) {as.numeric(levels(x))[x]}

betiğinizin başında ya da daha iyi dosyanızda saklayabilirsiniz .Rprofile.


14
Faktör-tamsayı (veya sayısal) dönüşümünü işleyecek hiçbir şey yoktur, çünkü as.integer(factor)temel tamsayı kodlarını döndürmesi beklenir ((örnekler bölümünde gösterildiği gibi ?factor). Bu işlevi genel ortamınızda tanımlamak muhtemelen doğru olabilir, ancak gerçekten bir S3 yöntemi olarak kaydederseniz sorunlara neden olabilirsiniz.
Joshua Ulrich

1
Bu iyi bir nokta ve katılıyorum: faktör-> sayısal dönüşümün tam olarak yeniden tanımlanması muhtemelen birçok şeyi karıştırır. Kendimi hantal factor->numericdönüşümü yazarken buldumAslında R'nin bir eksikliği olduğunu fark etmeden önce çok : bazı kolaylık işlevi mevcut olmalı ... Bunu çağırmak as.numeric.factorbana mantıklı, ama YMMV.
Jealie

4
Kendinizi bunu yaparken bulursanız çok fazla yaparsanız, o zaman hep birlikte önlemek için akıntıya karşı bir şeyler yapmalısınız.
Joshua Ulrich

2
as.numeric.factor NA döndürüyor?
JO.

@jO .: v=NA;as.numeric.factor(v)veya gibi bir şey kullandığınız durumlarda v='something';as.numeric.factor(v), aksi takdirde bir yerlerde garip bir şey olur.
Jealie

33

En kolay yol varhandleunfactor paketinden fonksiyon kullanmak olabilir

unfactor(your_factor_variable)

Bu örnek hızlı bir başlangıç ​​olabilir:

x <- rep(c("a", "b", "c"), 20)
y <- rep(c(1, 1, 0), 20)

class(x)  # -> "character"
class(y)  # -> "numeric"

x <- factor(x)
y <- factor(y)

class(x)  # -> "factor"
class(y)  # -> "factor"

library(varhandle)
x <- unfactor(x)
y <- unfactor(y)

class(x)  # -> "character"
class(y)  # -> "numeric"

unfactorKarakter veri türüne fonksiyonu dönüştürür birinci ve ardından dönüştürür sayısal için geri. Tip unfactorkonsolunda ve fonksiyonun ortasında görebilirsiniz. Bu nedenle, askerin sahip olduklarından gerçekten daha iyi bir çözüm sunmuyor.
CJB

Bununla birlikte, bir faktörün seviyeleri yine de karakter tipindedir, bu nedenle bu yaklaşımla hiçbir şey kaybolmaz.
CJB

unfactorFonksiyon sayısal dönüştürülür edilemez şeyler ilgilenir. Örnekleri kontrol edinhelp("unfactor")
Mehrad Mahmoudian

2
@Selrac Bu işlevin varhandle paketinde mevcut olduğunu belirttim , yani paketi ( library("varhandle")) önce yüklemelisiniz ( cevabımın ilk satırında belirttiğim gibi!)
Mehrad Mahmoudian

1
@Gregor hafif bir bağımlılık eklemek genellikle zarar vermez ve elbette en verimli yolu arıyorsanız, kodunuzu yazmak daha hızlı performans gösterebilir. Ayrıca yorumunuzda görebileceğiniz gibi ayrıca koymak sonra ancak bu önemsiz değil as.numeric()ve as.character()) kodunuzu öbek bir karakter matris içine faktörün düzey endeksi açmaktır neyi, bu yüzden de ne olacak ve; bir yanlış sırada bir zamanlar faktörünüzün belirli düzeyine atanmış bazı sayılar içeren bir karakter vektörüdür. Bu paketteki işlevler bu karışıklıkları önlemek için var
Mehrad Mahmoudian

23

Not: Bu özel cevap değil numerics için sayısal değerli faktörleri dönüştürmek için, onların karşılık gelen seviye numaralarına kategorik faktörlerin dönüştürmek içindir.


Bu yazıdaki her cevap benim için sonuç üretemedi, NA'lar üretiliyordu.

y2<-factor(c("A","B","C","D","A")); 
as.numeric(levels(y2))[y2] 
[1] NA NA NA NA NA Warning message: NAs introduced by coercion

Benim için işe yarayan şey bu -

as.integer(y2)
# [1] 1 2 3 4 1

Bir faktörünüz olduğundan emin misiniz? Bu örneğe bakın. y<-factor(c("5","15","20","2")); unclass(y) %>% as.numeric5,15,20,2 değil, 4,1,3,2 döndürür. Bu yanlış bilgi gibi görünüyor.
MrFlick

Tamam, bu bugün yapmaya çalıştığım şeye benziyor: - y2 <-faktor (c ("A", "B", "C", "D", "A")); as.numeric (level (y2)) [y2] [1] NA NA NA NA NA Uyarı mesajı: Zorlama ile getirilen NA'lar, sınıf (% y2)>> olarak%> as.numeric bana ihtiyacım olan sonuçları verdi.
Hint

4
Tamam, yukarıda sorulan soru bu değil. Bu soruda faktör seviyelerinin tümü "sayısal" dır. Sizin durumunuzda, as.numeric(y)iyi çalıştı, gerek yok unclass(). Fakat yine de, bu sorunun konusu bu değildi. Bu cevap burada uygun değil.
MrFlick

3
Umarım benim gibi acele eden birine yardım eder ve sadece başlığı okur!
Indi

1
Tamsayıları faktör olarak temsil eden karakterleriniz varsa, bunu tavsiye ederim. benim için çalışan tek kişi bu.
aimme

9

Mümkün sadece faktör etiketleri orijinal değerleri eşleştiğinde durumda. Bir örnekle açıklayacağım.

Verilerin vektör olduğunu varsayalım x:

x <- c(20, 10, 30, 20, 10, 40, 10, 40)

Şimdi dört etiketli bir faktör oluşturacağım:

f <- factor(x, levels = c(10, 20, 30, 40), labels = c("A", "B", "C", "D"))

1) xtip çift ile, ftip tamsayı ile. Bu kaçınılmaz ilk bilgi kaybıdır. Faktörler her zaman tamsayı olarak saklanır.

> typeof(x)
[1] "double"
> typeof(f)
[1] "integer"

2) Yalnızca mevcut olan orijinal değerlere (10, 20, 30, 40) geri dönmek mümkün değildir f. Bunun fyalnızca 1, 2, 3, 4 ve iki tam sayı değerlerini (etiket listesi ("A", "B", "C", "D") ve sınıf özelliği "faktör" değerini içerdiğini görebiliriz . Başka bir şey yok.

> str(f)
 Factor w/ 4 levels "A","B","C","D": 2 1 3 2 1 4 1 4
> attributes(f)
$levels
[1] "A" "B" "C" "D"

$class
[1] "factor"

Orijinal değerlere geri dönmek için faktörü oluştururken kullanılan düzeylerin değerlerini bilmeliyiz. Bu durumda c(10, 20, 30, 40). Orijinal seviyeleri bilersek (doğru sırada), orijinal değerlerine geri dönebiliriz.

> orig_levels <- c(10, 20, 30, 40)
> x1 <- orig_levels[f]
> all.equal(x, x1)
[1] TRUE

Ve bu yalnızca etiketlerin orijinal verilerdeki tüm olası değerler için tanımlanması durumunda işe yarar.

Bu yüzden orijinal değerlere ihtiyacınız olacaksa, bunları saklamanız gerekir. Aksi takdirde, sadece bir faktörden onlara geri dönmek mümkün olmayacaktır.


2

hablar::convertVeri çerçeveniz varsa kullanabilirsiniz . Sözdizimi kolaydır:

Örnek df

library(hablar)
library(dplyr)

df <- dplyr::tibble(a = as.factor(c("7", "3")),
                    b = as.factor(c("1.5", "6.3")))

Çözüm

df %>% 
  convert(num(a, b))

sana verir:

# A tibble: 2 x 2
      a     b
  <dbl> <dbl>
1    7.  1.50
2    3.  6.30

Veya bir sütunun tamsayı ve bir sayısal olmasını istiyorsanız:

df %>% 
  convert(int(a),
          num(b))

sonuç:

# A tibble: 2 x 2
      a     b
  <int> <dbl>
1     7  1.50
2     3  6.30

0

Çözüm n.nümerik (düzey (f)) [f] artık R 4.0 ile çalışmıyor gibi görünüyor.

Alternatif çözüm:

factor2number <- function(x){
    data.frame(levels(x), 1:length(levels(x)), row.names = 1)[x, 1]
}

factor2number(yourFactor)

-1

Okuyabildiğim birçok cevaptan, verilen tek yol, değişkenlerin sayısını faktör sayısına göre genişletmekti. Eğer "köpek" ve "kedi" seviyeleri ile değişken bir "evcil hayvan" varsa, sonunda pet_dog ve pet_cat ile sonuçlanır.

Benim durumumda, faktör değişkenini sayısal düzeye çevirerek, birçok seviyeye sahip birçok değişkene uygulanabilecek şekilde aynı sayıda değişkenle kalmak istedim, böylece cat = 1 ve dog = 0.

Lütfen aşağıdaki ilgili çözümü bulun:

crime <- data.frame(city = c("SF", "SF", "NYC"),
                    year = c(1990, 2000, 1990),
                    crime = 1:3)

indx <- sapply(crime, is.factor)

crime[indx] <- lapply(crime[indx], function(x){ 
  listOri <- unique(x)
  listMod <- seq_along(listOri)
  res <- factor(x, levels=listOri)
  res <- as.numeric(res)
  return(res)
}
)

-2

Geç oyuna, kaza buldum trimws()kutu dönüştürmek factor(3:5)için c("3","4","5"). Sonra arayabilirsiniz as.numeric(). Yani:

as.numeric(trimws(x_factor_var))

3
Kullandığınız öneriyoruz bir nedeni var mı trimwsüzerinde as.characterkabul edilen cevapta açıklandığı gibi? Görünüşe göre aslında kaldırmanız gereken boşluk yoksa trimws, aynı sonucu döndürmek için bir sürü gereksiz düzenli ifade çalışması yapacak.
MrFlick

as.numeric (düzey (f)) [f] yeni başlayanlar için biraz kafa karıştırıcı ve hatırlanması zor olabilir. trimws hiçbir zarar vermez.
Jerry T
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.