कॉलम क्लासेस को data.table में कन्वर्ट करें


118

मुझे data.table का उपयोग करने में समस्या है: मैं कॉलम कक्षाएं कैसे परिवर्तित करूं? यहाँ एक सरल उदाहरण है: data.frame के साथ मुझे इसे परिवर्तित करने में कोई समस्या नहीं है, data.table के साथ मुझे अभी नहीं पता है कि:

df <- data.frame(ID=c(rep("A", 5), rep("B",5)), Quarter=c(1:5, 1:5), value=rnorm(10))
#One way: http://stackoverflow.com/questions/2851015/r-convert-data-frame-columns-from-factors-to-characters
df <- data.frame(lapply(df, as.character), stringsAsFactors=FALSE)
#Another way
df[, "value"] <- as.numeric(df[, "value"])

library(data.table)
dt <- data.table(ID=c(rep("A", 5), rep("B",5)), Quarter=c(1:5, 1:5), value=rnorm(10))
dt <- data.table(lapply(dt, as.character), stringsAsFactors=FALSE) 
#Error in rep("", ncol(xi)) : invalid 'times' argument
#Produces error, does data.table not have the option stringsAsFactors?
dt[, "ID", with=FALSE] <- as.character(dt[, "ID", with=FALSE]) 
#Produces error: Error in `[<-.data.table`(`*tmp*`, , "ID", with = FALSE, value = "c(1, 1, 1, 1, 1, 2, 2, 2, 2, 2)") : 
#unused argument(s) (with = FALSE)

क्या मुझे यहाँ कुछ स्पष्ट याद आ रहा है?

मैथ्यू के पोस्ट के कारण अपडेट करें: मैंने पहले एक पुराने संस्करण का उपयोग किया था, लेकिन 1.6.6 (अब मैं जिस संस्करण का उपयोग करता हूं) को अपडेट करने के बाद भी मुझे एक त्रुटि मिलती है।

अद्यतन 2: मान लीजिए कि मैं कक्षा "कारक" के हर कॉलम को "वर्ण" कॉलम में परिवर्तित करना चाहता हूं, लेकिन पहले से नहीं जानता कि कौन सा कॉलम किस वर्ग का है। डेटा.फ्रेम के साथ, मैं निम्नलिखित कर सकता हूं:

classes <- as.character(sapply(df, class))
colClasses <- which(classes=="factor")
df[, colClasses] <- sapply(df[, colClasses], as.character)

क्या मैं data.table के साथ कुछ ऐसा कर सकता हूं?

अपडेट 3:

sessionInfo () आर संस्करण 2.13.1 (2011-07-08) प्लेटफार्म: x86_64-pc-mingw32 / x64 (64-बिट)

locale:
[1] C

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] data.table_1.6.6

loaded via a namespace (and not attached):
[1] tools_2.13.1

data.tableतरीकों में "[" ऑपरेटर तर्क अलग-अलग हैं, जैसे कि उनके लिएdata.frame
IRTFM

1
कृपया वास्तविक त्रुटि पेस्ट करने के बजाय #Produces error। वैसे भी +1। मुझे कोई त्रुटि नहीं है, आपके पास कौन सा संस्करण है? इस क्षेत्र में एक समस्या है, हालांकि, इसे पहले उठाया गया है, FR # 1224 और FR # 1493 को संबोधित करने के लिए उच्च प्राथमिकता है। एंड्री का जवाब सबसे अच्छा तरीका है, हालांकि।
मैट डॉवेल

माफ़ करना @MatthewDowle को याद करने के लिए कि मेरे प्रश्न में, मैंने अपनी पोस्ट अपडेट की।
क्रिस्टोफ़_जे

1
@Christoph_J धन्यवाद। क्या आप उस invalid times argumentत्रुटि के बारे में निश्चित हैं ? मेरे लिए ठीक काम करो। आपके पास कौन सा संस्करण है?
मैट डोले

मैंने sessionInfo () के साथ अपनी पोस्ट अपडेट की। हालाँकि, मैंने इसे आज अपनी कार्य मशीन पर जाँच लिया। कल, मेरी घरेलू मशीन (उबंटू) पर भी वही त्रुटि हुई। मैं आर को अपडेट करूंगा और देखूंगा कि क्या समस्या अभी भी है।
क्रिस्टोफ़_जे

जवाबों:


104

एकल कॉलम के लिए:

dtnew <- dt[, Quarter:=as.character(Quarter)]
str(dtnew)

Classes ‘data.table’ and 'data.frame':  10 obs. of  3 variables:
 $ ID     : Factor w/ 2 levels "A","B": 1 1 1 1 1 2 2 2 2 2
 $ Quarter: chr  "1" "2" "3" "4" ...
 $ value  : num  -0.838 0.146 -1.059 -1.197 0.282 ...

उपयोग करना lapplyऔर as.character:

dtnew <- dt[, lapply(.SD, as.character), by=ID]
str(dtnew)

Classes ‘data.table’ and 'data.frame':  10 obs. of  3 variables:
 $ ID     : Factor w/ 2 levels "A","B": 1 1 1 1 1 2 2 2 2 2
 $ Quarter: chr  "1" "2" "3" "4" ...
 $ value  : chr  "1.487145280568" "-0.827845218358881" "0.028977182770002" "1.35392750102305" ...

2
@Christoph_J कृपया उस समूह कमांड को दिखाएं जो आप (वास्तविक समस्या) से जूझ रहे हैं। सोचिए आप कुछ सरल याद कर रहे होंगे। आप कॉलम कक्षाओं को बदलने की कोशिश क्यों कर रहे हैं?
मैट डॉवेल

1
@Christoph_J यदि आप data.tables में हेराफेरी करने के लिए संघर्ष करते हैं, तो बस उन्हें अस्थायी रूप से डेटा.फ्रेम में परिवर्तित क्यों न करें, डेटा को साफ करें और फिर उन्हें data.tables में वापस कनवर्ट करें?
एंड्री

17
कॉलम के सबसेट (उन सभी के बजाय) के लिए ऐसा करने का मुहावरेदार तरीका क्या है? मैंने convcolsकॉलम के एक वर्ण वेक्टर को परिभाषित किया है । dt[,lapply(.SD,as.numeric),.SDcols=convcols]लगभग तुरंत है, जबकि dt[,convcols:=lapply(.SD,as.numeric),.SDcols=convcols]लगभग आर जमा देता है, इसलिए मैं अनुमान लगा रहा हूं कि मैं इसे गलत कर रहा हूं। साभार
फ्रैंक

4
@Frank नीचे जिनेओराम के जवाब के लिए मैट डोले की टिप्पणी देखें ( stackoverflow.com/questions/7813578/… ); यह मेरे लिए काफी मददगार और मुहावरेदार था [उद्धरण उद्धरण] दूसरा और आसान तरीका है set()उदाहरण के लिए for (col in names_factors) set(dt, j=col, value=as.factor(dt[[col]]))[समाप्ति उद्धरण]
swihart

4
आप by = ID विकल्प का उपयोग क्यों करते हैं?
स्कैन मार्क

48

इसे इस्तेमाल करे

DT <- data.table(X1 = c("a", "b"), X2 = c(1,2), X3 = c("hello", "you"))
changeCols <- colnames(DT)[which(as.vector(DT[,lapply(.SD, class)]) == "character")]

DT[,(changeCols):= lapply(.SD, as.factor), .SDcols = changeCols]

7
अब आप Filterस्तंभों की पहचान करने के लिए फ़ंक्शन का उपयोग कर सकते हैं , उदाहरण के लिए: changeCols<- names(Filter(is.character, DT))
डेविड लील

1
IMO यह बेहतर उत्तर है, जिस कारण से मैंने चुने हुए उत्तर में दिया।
जेम्स हिर्स्चोर्न

1
या अधिक संक्षेप में changeCols <- names(DT)[sapply(DT, is.character)]:।
सिंदरी_बलदुर

8

मैट डोले की टिप्पणी को जिनेओरामा के जवाब ( https://stackoverflow.com/a/20808945/4241780 ) पर उठाकर इसे और अधिक स्पष्ट (प्रोत्साहित करने के लिए) करने के लिए, आप उपयोग कर सकते हैं for(...)set(...)


library(data.table)

DT = data.table(a = LETTERS[c(3L,1:3)], b = 4:7, c = letters[1:4])
DT1 <- copy(DT)
names_factors <- c("a", "c")

for(col in names_factors)
  set(DT, j = col, value = as.factor(DT[[col]]))

sapply(DT, class)
#>         a         b         c 
#>  "factor" "integer"  "factor"

2020-02-12 को रेप्रेक्स पैकेज (v0.3.0) द्वारा बनाया गया

मैट की अन्य टिप्पणियों को https://stackoverflow.com/a/33000778/4241780 पर देखेंअधिक जानकारी के लिए ।

संपादित करें।

जैसा कि एस्पेन और help(set), द्वारा उल्लेख किया गया है , j"कॉलम नाम (अक्षर) या संख्या (एस) (पूर्णांक) को निर्दिष्ट किया जा सकता है जब कॉलम (एस) पहले से मौजूद हैं।" तो names_factors <- c(1L, 3L)भी चलेगा।


आप names_factorsयहाँ जोड़ना चाह सकते हैं । मुझे लगता है कि यह stackoverflow.com/a/20808945/1666063 से लिया गया है, इसलिए यह names_factors = c('fac1', 'fac2')इस मामले में है - जो स्तंभ नाम है। लेकिन यह उदाहरण 1 के लिए कॉलम नंबर भी हो सकता है; ncol (dt) जो सभी कॉलमों को परिवर्तित करेगा
एस्पार रिस्केडल

@EspenRiskedal धन्यवाद अच्छी बात है, मैंने इसे और अधिक स्पष्ट करने के लिए पोस्ट को संपादित किया है।
जिलिमन

2

यह एक बुरा तरीका है! मैं केवल इस उत्तर को छोड़ रहा हूँ जब यह अन्य अजीब समस्याओं को हल करता है। ये बेहतर तरीके शायद आंशिक रूप से नए data.table संस्करणों का परिणाम हैं ... इसलिए इस कठिन तरीके को दस्तावेज़ करने के लिए इसके लायक है। साथ ही, सिंटैक्स के लिए यह एक अच्छा वाक्यविन्यास उदाहरण है eval substitute

library(data.table)
dt <- data.table(ID = c(rep("A", 5), rep("B",5)), 
                 fac1 = c(1:5, 1:5), 
                 fac2 = c(1:5, 1:5) * 2, 
                 val1 = rnorm(10),
                 val2 = rnorm(10))

names_factors = c('fac1', 'fac2')
names_values = c('val1', 'val2')

for (col in names_factors){
  e = substitute(X := as.factor(X), list(X = as.symbol(col)))
  dt[ , eval(e)]
}
for (col in names_values){
  e = substitute(X := as.numeric(X), list(X = as.symbol(col)))
  dt[ , eval(e)]
}

str(dt)

जो आपको देता है

Classes ‘data.table’ and 'data.frame':  10 obs. of  5 variables:
 $ ID  : chr  "A" "A" "A" "A" ...
 $ fac1: Factor w/ 5 levels "1","2","3","4",..: 1 2 3 4 5 1 2 3 4 5
 $ fac2: Factor w/ 5 levels "2","4","6","8",..: 1 2 3 4 5 1 2 3 4 5
 $ val1: num  0.0459 2.0113 0.5186 -0.8348 -0.2185 ...
 $ val2: num  -0.0688 0.6544 0.267 -0.1322 -0.4893 ...
 - attr(*, ".internal.selfref")=<externalptr> 

42
एक और आसान और आसान तरीका है set()उदाहरण के लिएfor (col in names_factors) set(dt, j=col, value=as.factor(dt[[col]]))
मैट डाउले

1
मुझे लगता है कि मेरा उत्तर सभी संस्करणों के लिए, एक पंक्ति में इसे पूरा करता है। यकीन नहीं है, setहालांकि अधिक उपयुक्त है।
बेन रोलर्ट

1
for(...)set(...)यहाँ पर अधिक जानकारी : stackoverflow.com/a/33000778/403310
मैट डोवल

1
@skan अच्छा सवाल। यदि आप इसे पहले पूछा गया नहीं पाते हैं, तो कृपया एक नया प्रश्न पूछें। भविष्य में दूसरों की मदद करता है।
मैट डोले जुले

1
@ इस तरह से मैंने इसे कैसे किया: github.com/geneorama/geneorama/blob/master/R/…
genorama

0

मैंने कई तरीकों की कोशिश की।

# BY {dplyr}
data.table(ID      = c(rep("A", 5), rep("B",5)), 
           Quarter = c(1:5, 1:5), 
           value   = rnorm(10)) -> df1
df1 %<>% dplyr::mutate(ID      = as.factor(ID),
                       Quarter = as.character(Quarter))
# check classes
dplyr::glimpse(df1)
# Observations: 10
# Variables: 3
# $ ID      (fctr) A, A, A, A, A, B, B, B, B, B
# $ Quarter (chr) "1", "2", "3", "4", "5", "1", "2", "3", "4", "5"
# $ value   (dbl) -0.07676732, 0.25376110, 2.47192852, 0.84929175, -0.13567312,  -0.94224435, 0.80213218, -0.89652819...

, या अन्यथा

# from list to data.table using data.table::setDT
list(ID      = as.factor(c(rep("A", 5), rep("B",5))), 
     Quarter = as.character(c(1:5, 1:5)), 
     value   = rnorm(10)) %>% setDT(list.df) -> df2
class(df2)
# [1] "data.table" "data.frame"

0

मैं इस सामान को करने के लिए एक अधिक सामान्य और सुरक्षित तरीका प्रदान करता हूं,

".." <- function (x) 
{
  stopifnot(inherits(x, "character"))
  stopifnot(length(x) == 1)
  get(x, parent.frame(4))
}


set_colclass <- function(x, class){
  stopifnot(all(class %in% c("integer", "numeric", "double","factor","character")))
  for(i in intersect(names(class), names(x))){
    f <- get(paste0("as.", class[i]))
    x[, (..("i")):=..("f")(get(..("i")))]
  }
  invisible(x)
}

फ़ंक्शन ..यह सुनिश्चित करता है कि हमें डेटा के दायरे से बाहर एक चर मिल जाए; set_colclass आपके कोल के वर्ग सेट करेगा। आप इसे इस तरह से उपयोग कर सकते हैं:

dt <- data.table(i=1:3,f=3:1)
set_colclass(dt, c(i="character"))
class(dt$i)

-1

यदि आपके पास data.table में कॉलम नामों की एक सूची है, तो आप do की श्रेणी बदलना चाहते हैं:

convert_to_character <- c("Quarter", "value")

dt[, convert_to_character] <- dt[, lapply(.SD, as.character), .SDcols = convert_to_character]

यह उत्तर मूल रूप से नीचे @ नीरा के उत्तर का एक बुरा संस्करण है। बस dt[, c(convert_to_character) := lapply(.SD, as.character), .SDcols=convert_to_character]धीमी डेटा का उपयोग करने के बजाय संदर्भ द्वारा असाइन करें।
अलबेक

-3

प्रयत्न:

dt <- data.table(A = c(1:5), 
                 B= c(11:15))

x <- ncol(dt)

for(i in 1:x) 
{
     dt[[i]] <- as.character(dt[[i]])
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.