Data.frame sütunlarını faktörlerden karakterlere dönüştürme


352

Bir veri çerçevem ​​var. Hadi onu arayalım bob:

> head(bob)
                 phenotype                         exclusion
GSM399350 3- 4- 8- 25- 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399351 3- 4- 8- 25- 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399352 3- 4- 8- 25- 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399353 3- 4- 8- 25+ 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399354 3- 4- 8- 25+ 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399355 3- 4- 8- 25+ 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-

Bu veri çerçevesinin satırlarını birleştirmek istiyorum (bu başka bir soru olacak). Fakat bak:

> class(bob$phenotype)
[1] "factor"

Bobsütunları faktörlerdir. Yani mesela:

> as.character(head(bob))
[1] "c(3, 3, 3, 6, 6, 6)"       "c(3, 3, 3, 3, 3, 3)"      
[3] "c(29, 29, 29, 30, 30, 30)"

Bunu anlamaya başlamıyorum, ama sanırım bunlar, (kral caractacus mahkemesinin) sütunlarının faktörlerinin seviyelerine endeksler bobmi? İhtiyacım olan değil.

Garip bir şekilde bobel ile sütunları geçebilir ve

bob$phenotype <- as.character(bob$phenotype)

hangi iyi çalışıyor. Ve yazdıktan sonra, sütunları faktörlerden ziyade karakter olan bir data.frame alabilirim. Benim sorum şu: bunu otomatik olarak nasıl yapabilirim? Faktör sütunları olan bir data.frame'i, her sütunu elle geçmek zorunda kalmadan karakter sütunları içeren bir data.frame'e nasıl dönüştürebilirim?

Bonus soru: manuel yaklaşım neden işe yarıyor?


3
soruyu tekrarlanabilir hale getirirseniz iyi olur, bu yüzden yapısını ekleyin bob.
jangorecki

Yanıtlar:


362

Matt ve Dirk'i takip ediyorum. Varolan veri çerçevenizi genel seçeneği değiştirmeden yeniden oluşturmak istiyorsanız, bir uygula ifadesiyle yeniden oluşturabilirsiniz:

bob <- data.frame(lapply(bob, as.character), stringsAsFactors=FALSE)

Bu, tüm değişkenleri "karakter" sınıfına dönüştürür, yalnızca faktörleri dönüştürmek istiyorsanız, aşağıdaki Marek çözümüne bakın .

@Hadley'in belirttiği gibi, aşağıdakiler daha özlüdür.

bob[] <- lapply(bob, as.character)

Her iki durumda da lapplybir liste çıkarır; bununla birlikte, R'nin büyülü özellikleri nedeniyle [], ikinci durumda kullanımı bobnesnenin data.frame sınıfını korur ve böylece as.data.frameargümanla birlikte bir data.frame'e geri dönme ihtiyacını ortadan kaldırır stringsAsFactors = FALSE.


27
Shane, bu da sayısal sütunları karaktere dönüştürecek.
Dirk Eddelbuettel

@Dirk: Bu doğru, ancak burada bir sorun olup olmadığı belli değil. Açıkçası, işleri doğru bir şekilde oluşturmak en iyi çözümdür. Veri türlerini otomatik olarak bir veri çerçevesine dönüştürmenin kolay olduğunu düşünmüyorum . Bir seçenek yukarıdakileri kullanmak, ancak type.converther şeyi characterdöktükten sonra kullanmaktır , daha sonra tekrar tekrar factorsgeri almaktır character.
Shane

Bu, satır adlarını siliyor gibi görünüyor.
piccolbo

2
@piccolbo bob[] <- örnekte kullandınız bob <- mı? ilki data.frame'i tutar; ikincisi data.frame öğesini bir liste olarak değiştirir ve rownames bırakır. Cevabı güncelleyeceğim
David LeBauer

6
Adsız bir işlev kullanarak yalnızca faktör sütunlarını karaktere dönüştüren bir varyant: iris[] <- lapply(iris, function(x) if (is.factor(x)) as.character(x) else {x})
Stefan F

313

Yalnızca faktörleri değiştirmek için:

i <- sapply(bob, is.factor)
bob[i] <- lapply(bob[i], as.character)

0.5.0 sürümündekimutate_if dplyr paketinde yeni işlev tanıtıldı :

library(dplyr)
bob %>% mutate_if(is.factor, as.character) -> bob

RStudio'dan purrr paketi başka bir alternatif sunuyor:

library(purrr)
library(dplyr)
bob %>% map_if(is.factor, as.character) %>% as_tibble -> bob

Ne yazık ki benim için çalışmıyor. Neden bilmiyorum. Muhtemelen ülkelerim olduğu için mi?
Autumnsault

@mohawkjohn Sorun olmamalı. Hata veya sonuç beklediğiniz gibi değil mi?
Marek

2
Not: purrrSatır bir liste döndürür, bir değil data.frame!
RoyalTS

Bu aynı zamanda ibir vektörünüz varsa zaten işe yarar colnames().
verbamour

39

Global seçenek

stringsAsFactors: data.frame ve read.table bağımsız değişkenleri için varsayılan ayar.

FALSEbaşlangıç ​​dosyalarınızda ayarlamak istediğiniz bir şey olabilir (örn. ~ / .Rprofile). Lütfen bakın help(options).


5
Bu sorun, kodunuzu .Rprofile dosyasının eksik olduğu bir ortamda yürüttüğünüzde hatalar alacağınızdır!
waferthin

4
Ayarı .Rprofile yerine komut dosyalarının başında çağırmak eğilimindedir.
gregmacfarlane

22

Faktörlerin nasıl saklandığını anlarsanız, bunu gerçekleştirmek için uygulama tabanlı işlevleri kullanmaktan kaçınabilirsiniz. Bu, uygulanan çözümlerin iyi çalışmadığı anlamına gelmez.

Faktörler, bir 'düzeyler' listesine bağlı sayısal indeksler olarak yapılandırılır. Bir faktörü sayısal olarak dönüştürürseniz bu görülebilir. Yani:

> fact <- as.factor(c("a","b","a","d")
> fact
[1] a b a d
Levels: a b d

> as.numeric(fact)
[1] 1 2 1 3

Son satırda döndürülen sayılar, faktörün seviyelerine karşılık gelir.

> levels(fact)
[1] "a" "b" "d"

levels()Bir dizi karakter döndüren dikkat edin . Bu gerçeği, faktörleri dizelere veya nümeriklere kolayca ve kompakt bir şekilde dönüştürmek için kullanabilirsiniz:

> fact_character <- levels(fact)[as.numeric(fact)]
> fact_character
[1] "a" "b" "a" "d"

Bu, ifadenizi sarmanız koşuluyla sayısal değerler için de geçerlidir as.numeric().

> num_fact <- factor(c(1,2,3,6,5,4))
> num_fact
[1] 1 2 3 6 5 4
Levels: 1 2 3 4 5 6
> num_num <- as.numeric(levels(num_fact)[as.numeric(num_fact)])
> num_num
[1] 1 2 3 6 5 4

Bu cevap sorunu ele almaz, yani veri çerçevemdeki tüm faktör sütunlarını karaktere nasıl dönüştürürüm . as.character(f), hem okunabilirlik hem de verimlilik açısından daha iyidir levels(f)[as.numeric(f)]. Eğer zeki olmak istersen levels(f)[f]bunun yerine kullanabilirsiniz . Sayısal değerlere sahip bir faktörü dönüştürürken as.numeric(levels(f))[f], örneğin bir miktar fayda elde as.numeric(as.character(f))edeceğinizi unutmayın, ancak bunun nedeni yalnızca düzeyleri sayısal ve sonra altkümeye dönüştürmeniz gerektiğidir. as.character(f)olduğu gibi iyi.
De Novo

20

Yeni bir veri çerçevesi istiyorsanız her faktör vektör olan bir karakter vektör dönüştürülür, bu deneyin:bobcbobf

bobc <- rapply(bobf, as.character, classes="factor", how="replace")

Daha sonra geri dönüştürmek istiyorsanız, hangi sütunların faktör olduğu mantıksal bir vektör oluşturabilir ve bunu seçici olarak faktör uygulamak için kullanabilirsiniz

f <- sapply(bobf, class) == "factor"
bobc[,f] <- lapply(bobc[,f], factor)

2
Sadece gerekli olanı yapmak için +1 (yani tüm veri çerçevesini karaktere dönüştürmemek). Bu çözüm, karışık türler içeren bir data.frame'e dayanıklıdır.
Joshua Ulrich

3
Bu örnek, rapply için `Örnekler 'bölümünde olmalıdır, örneğin: stat.ethz.ch/R-manual/R-devel/library/base/html/rapply.html . Bunun nasıl talep edeceğini bilen var mı?
mpettis

Bir veri çerçevesiyle sonuçlanmak istiyorsanız, rapply'yi bir data.frame çağrısına sarın (FALSE argümanına ayarlanmış stringsAsFactors kullanarak)
Taylored Web Siteleri

13

Bu işlevi tipik olarak tüm projelerim dışında yapıyorum. Çabuk ve kolay.

unfactorize <- function(df){
  for(i in which(sapply(df, class) == "factor")) df[[i]] = as.character(df[[i]])
  return(df)
}

8

Başka bir yol, uygula'yı kullanarak dönüştürmektir.

bob2 <- apply(bob,2,as.character)

Ve daha iyi olanı (önceki sınıf 'matris')

bob2 <- as.data.frame(as.matrix(bob),stringsAsFactors=F)

@ Shane'nin yorumunu takip ederek: as.data.frame(lapply(...
data.frame

7

Güncelleme: İşte işe yaramayan bir şey örneği. Bunu düşündüm, ama stringsAsFactors seçeneğinin sadece karakter dizeleri üzerinde çalıştığını düşünüyorum - faktörleri yalnız bırakıyor.

Bunu dene:

bob2 <- data.frame(bob, stringsAsFactors = FALSE)

Genel olarak konuşursak, karakter olması gereken faktörlerle ilgili sorun yaşarsanız, size stringsAsFactorsyardımcı olacak bir ayar vardır (global bir ayar dahil).


1
Bu, işe bobbaşlamak için oluştururken ayarlar (ancak gerçekten sonra değil).
Shane

Sağ. Sadece bunun sorunu çözmediğini açıkça belirtmek istedik - ancak önlediğini belirttiğiniz için teşekkürler.
Matt Parker

7

Veya deneyebilirsiniz transform:

newbob <- transform(bob, phenotype = as.character(phenotype))

Sadece karaktere dönüştürmek istediğiniz her faktörü koyduğunuzdan emin olun.

Veya böyle bir şey yapabilir ve tüm zararlıları tek bir darbe ile öldürebilirsiniz:

newbob_char <- as.data.frame(lapply(bob[sapply(bob, is.factor)], as.character), stringsAsFactors = FALSE)
newbob_rest <- bob[!(sapply(bob, is.factor))]
newbob <- cbind(newbob_char, newbob_rest)

Bu gibi kod verileri kıpırdatmak için iyi bir fikir değil , yapabilirimsapply parçayı ayrı ayrı yapabilirim (aslında, böyle yapmak çok daha kolay), ama noktayı anlıyorsunuz ... Kodu kontrol etmedim, çünkü Evde değilim, umarım işe yarar! =)

Bununla birlikte, bu yaklaşımın bir dezavantajı vardır ... daha sonra sütunları yeniden düzenlemelisiniz, bununla birlikte transformistediğinizi yapabilirsiniz, ancak "yaya tarzı kod yazma" pahasına ...

Yani orada ... =)


6

Veri çerçevenizin başlangıcında, stringsAsFactors = FALSEtüm yanlış anlamaları yok saymayı içerir .


4

data.tableData.frame üzerindeki işlemler için paketi kullanırsanız , sorun mevcut değildir.

library(data.table)
dt = data.table(col1 = c("a","b","c"), col2 = 1:3)
sapply(dt, class)
#       col1        col2 
#"character"   "integer" 

Veri kümenizde zaten bir faktör sütununuz varsa ve bunları karaktere dönüştürmek istiyorsanız aşağıdakileri yapabilirsiniz.

library(data.table)
dt = data.table(col1 = factor(c("a","b","c")), col2 = 1:3)
sapply(dt, class)
#     col1      col2 
# "factor" "integer" 
upd.cols = sapply(dt, is.factor)
dt[, names(dt)[upd.cols] := lapply(.SD, as.character), .SDcols = upd.cols]
sapply(dt, class)
#       col1        col2 
#"character"   "integer" 

DT, Marek tarafından önerilen aptalca düzeltmeyi atlar: DF'yi düzeltmek ve DT'yi In [<-.data.table(*tmp*, sapply(bob, is.factor), : Coerced 'character' RHS to 'double' to match the column's type. Either change the target column to 'character' first (by creating a new 'character' vector length 1234 (nrows of entire table) and assign that; i.e. 'replace' column), or coerce RHS to 'double' (e.g. 1L, NA_[real|integer]_, as.*, etc) to make your intent clear and for speed. Or, set the column type correctly up front when you create the table and stick to it, please.yeniden oluşturmak daha kolaydır.
Matt Chambers

2

Bu benim için çalışıyor - sonunda bir astar buldum

df <- as.data.frame(lapply(df,function (y) if(class(y)=="factor" ) as.character(y) else y),stringsAsFactors=F)

2

Bu işlev hile yapar

df <- stacomirtools::killfactor(df)

2

Belki daha yeni bir seçenek?

library("tidyverse")

bob <- bob %>% group_by_if(is.factor, as.character)

1

Sen kullanmalıdır convertiçinde hablaruyumlu okunabilir sözdizimi veren tidyverseborular:

library(dplyr)
library(hablar)

df <- tibble(a = factor(c(1, 2, 3, 4)),
             b = factor(c(5, 6, 7, 8)))

df %>% convert(chr(a:b))

hangi size verir:

  a     b    
  <chr> <chr>
1 1     5    
2 2     6    
3 3     7    
4 4     8   

1

İle dplyr-package yüklü kullanımda

bob=bob%>%mutate_at("phenotype", as.character)

yalnızca phenotype-column'u özel olarak değiştirmek istiyorsanız .


0

Bu, önce tüm karakterleri, sonra da sayısal değerleri sayısal olarak dönüştürmeye çalışır:

makenumcols<-function(df){
  df<-as.data.frame(df)
  df[] <- lapply(df, as.character)
  cond <- apply(df, 2, function(x) {
    x <- x[!is.na(x)]
    all(suppressWarnings(!is.na(as.numeric(x))))
  })
  numeric_cols <- names(df)[cond]
  df[,numeric_cols] <- sapply(df[,numeric_cols], as.numeric)
  return(df)
}

Uyarlandığı yer: Excel sayfasının sütun türlerini otomatik olarak alın

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.