Konwertuj dane.ramka kolumny od czynników do znaków

Mam ramkę danych. Nazwijmy go 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-

Chciałbym połączyć wiersze tej ramki danych (to będzie kolejne pytanie). Ale spójrz:

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

Bob'kolumny s są czynnikami. Na przykład:

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

Nie zaczynam tego rozumieć, ale myślę, że są to wskaźniki do poziomów czynników kolumn (dworu króla caractacusa) bob? Nie tego mi trzeba.

O dziwo mogę przejść przez kolumny bob przez hand, and do

bob$phenotype <- as.character(bob$phenotype)
Co działa dobrze. Po jakimś wpisaniu mogę uzyskać dane.ramka, której kolumny są znakami, a nie czynnikami. Więc moje pytanie brzmi: Jak mogę to zrobić automatycznie? Jak przekonwertować dane.ramka z kolumnami współczynników w dane.ramka z kolumnami znakowymi bez konieczności ręcznego przechodzenia przez każdą kolumnę?

Pytanie dodatkowe: dlaczego podejście ręczne działa?

 365
Author: GSee, 2010-05-17

18 answers

Śledzę Matta i Dirka. Jeśli chcesz odtworzyć istniejącą ramkę danych bez zmiany opcji global, możesz ją odtworzyć za pomocą instrukcji apply:

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

To przekonwertuje wszystkie zmienne do klasy "character" , jeśli chcesz konwertować tylko czynniki, patrz Rozwiązanie Marka poniżej .

Jak podkreśla @ hadley, poniżej jest bardziej zwięzła.

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

W obu przypadkach lapply wypisuje listę; jednak ze względu na magiczne właściwości R, użycie [] w drugim przypadku przechowuje dane.Klasa frame obiektu bob, eliminując w ten sposób konieczność konwersji z powrotem na dane.frame używając {[5] } z argumentem stringsAsFactors = FALSE.

 372
Author: Shane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:25

Aby zastąpić tylko czynniki:

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

W pakiecie dplyr w wersji 0.5.0 wprowadzono nową funkcję mutate_if :

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

...i w wersji 1.0.0 została zastąpiona przez across:

library(dplyr)
bob %>% mutate(across(where(is.factor), as.character)) -> bob

Pakiet purrr z RStudio daje inną alternatywę:

library(purrr)
bob %>% modify_if(is.factor, as.character) -> bob
 316
Author: Marek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-20 10:13:49

Opcja globalna

StringsAsFactors: Domyślne ustawienie argumentów danych.kadruj i czytaj.stolik.

Może to być coś, co chcesz ustawić na FALSE w plikach startowych (np. ~/.Rprofile). Zobacz help(options).

 39
Author: Dirk Eddelbuettel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-06 12:15:21

Jeśli rozumiesz, jak przechowywane są czynniki, możesz uniknąć korzystania z funkcji opartych na zastosowaniach w celu osiągnięcia tego celu. Co wcale nie oznacza, że zastosowane rozwiązania nie działają dobrze.

Czynniki są strukturyzowane jako wskaźniki numeryczne powiązane z listą 'poziomów'. Można to zobaczyć, jeśli przekonwertujesz Współczynnik na liczbę. Więc:

> 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

Liczby zwrócone w ostatnim wierszu odpowiadają poziomom czynnika.

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

Zauważ, że levels() zwraca tablicę znaków. Możesz użyć ten fakt, aby łatwo i zwięźle konwertować współczynniki na ciągi lub cyfry, jak to:

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

Działa to również dla wartości liczbowych, pod warunkiem, że zawiniesz swoje wyrażenie w 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
 23
Author: Kikapp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-19 05:02:54

Jeśli chcesz, aby nowa ramka danych bobc Gdzie każdy wektor czynnika W bobf został przekonwertowany na wektor znakowy, spróbuj tego:

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

Jeśli następnie chcesz przekonwertować go z powrotem, możesz utworzyć logiczny wektor, którego kolumny są czynnikami i użyć go do selektywnego zastosowania współczynnika

f <- sapply(bobf, class) == "factor"
bobc[,f] <- lapply(bobc[,f], factor)
 21
Author: scentoni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-05 07:37:05

Zazwyczaj wykonuję tę funkcję niezależnie od wszystkich moich projektów. Szybko i łatwo.

unfactorize <- function(df){
  for(i in which(sapply(df, class) == "factor")) df[[i]] = as.character(df[[i]])
  return(df)
}
 14
Author: by0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-10 22:25:09

Innym sposobem jest przekonwertowanie go za pomocą apply

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

I lepszy (poprzedni należy do klasy 'matrix')

bob2 <- as.data.frame(as.matrix(bob),stringsAsFactors=F)
 8
Author: George Dontas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-17 17:58:36

Aktualizacja: oto przykład czegoś, co nie działa. Myślałem, że tak, ale myślę, że opcja stringsAsFactors działa tylko na ciągach znaków - pozostawia czynniki same.

Spróbuj tego:

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

Ogólnie rzecz biorąc, gdy masz problemy z czynnikami, które powinny być postaciami, istnieje gdzieś ustawienie stringsAsFactors, które Ci pomoże (w tym ustawienie globalne).

 7
Author: Matt Parker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-17 17:07:27

Lub możesz spróbować transform:

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

Pamiętaj, aby umieścić każdy czynnik, który chcesz przekonwertować na postać.

Albo możesz zrobić coś takiego i zabić wszystkie szkodniki jednym ciosem: {]}

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)

To nie dobry pomysł, żeby wepchnąć dane w taki kod, mógłbym zrobić część sapply osobno( właściwie o wiele łatwiej to zrobić w ten sposób), ale rozumiesz o co chodzi... Nie sprawdziłem kodu, bo nie ma mnie w domu, więc mam nadzieję, że zadziała! =)

To podejście ma jednak minusy... następnie musisz przeorganizować kolumny, podczas gdy za pomocą transform możesz robić, co chcesz, ale kosztem "pisania kodu w stylu pieszym" ...

Więc tam... =)

 7
Author: aL3xa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-17 17:49:17

Na początku ramki danych Dołącz stringsAsFactors = FALSE, aby zignorować wszelkie nieporozumienia.

 6
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-16 15:21:54

Jeśli chcesz użyć data.table pakietu do operacji na danych.ramka wtedy problem nie występuje.

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

Jeśli masz kolumny współczynników w zbiorze danych i chcesz je przekonwertować na znak, możesz wykonać następujące czynności.

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" 
 4
Author: jangorecki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-09 20:55:52

To działa dla mnie-w końcu wymyśliłem jeden liner

df <- as.data.frame(lapply(df,function (y) if(class(y)=="factor" ) as.character(y) else y),stringsAsFactors=F)
 2
Author: user1617979,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-24 16:00:22

Ta funkcja robi sztuczkę

df <- stacomirtools::killfactor(df)
 2
Author: Cedric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-13 16:46:28

Może nowsza opcja?

library("tidyverse")

bob <- bob %>% group_by_if(is.factor, as.character)
 2
Author: rachelette,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-14 16:09:37

Powinieneś użyć convert w hablar co daje czytelną składnię zgodną ztidyverse:

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

Co daje:

  a     b    
  <chr> <chr>
1 1     5    
2 2     6    
3 3     7    
4 4     8   
 1
Author: davsjob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-10 21:25:45

Z dplyr-pakiet załadowany

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

Jeśli chcesz tylko zmienić kolumnę phenotype-konkretnie.

 1
Author: nexonvantec,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-10 12:16:38

Nowa funkcja "across" została wprowadzona w dplyr w wersji 1.0.0 . Nowa funkcja zastąpi zmienne zakresowe (_if, _at, _all). Oto oficjalna Dokumentacja

library(dplyr)
bob <- bob %>% 
       mutate(across(where(is.factor), as.character))
 1
Author: radhikesh93,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-13 13:37:55

To działa przekształcając wszystkie na znak, a następnie numeryczne na numeryczne:

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

Dostosowany z: Automatycznie pobieraj typy kolumn arkusza excel

 0
Author: Ferroao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-27 19:23:06