स्वचालित रूप से प्रत्येक कारक स्तर के लिए 1/0 संकेतक चर के संग्रह में एक आर कारक का विस्तार करना


108

मेरे पास एक आर डेटा फ्रेम है जिसमें एक कारक है जिसे मैं "विस्तार" करना चाहता हूं ताकि प्रत्येक कारक स्तर के लिए, एक नया डेटा फ्रेम में एक संबद्ध स्तंभ हो, जिसमें 1/0 संकेतक हो। जैसे, मान लो मेरे पास है:

df.original <-data.frame(eggs = c("foo", "foo", "bar", "bar"), ham = c(1,2,3,4))

मुझे चाहिए:

df.desired  <- data.frame(foo = c(1,1,0,0), bar=c(0,0,1,1), ham=c(1,2,3,4))

क्योंकि कुछ विश्लेषणों के लिए जिनके लिए आपको एक पूरी तरह से संख्यात्मक डेटा फ्रेम (उदाहरण के लिए, प्रमुख घटक विश्लेषण) की आवश्यकता होती है, मैंने सोचा कि इस सुविधा का निर्माण किया जाना चाहिए। ऐसा करने के लिए एक फ़ंक्शन लिखना बहुत कठिन नहीं होना चाहिए, लेकिन मैं कुछ का अनुमान लगा सकता हूं। स्तंभ नामों से संबंधित चुनौतियाँ और यदि कुछ पहले से मौजूद हैं, तो मैं इसका उपयोग करूँगा।

जवाबों:


131

model.matrixफ़ंक्शन का उपयोग करें :

model.matrix( ~ Species - 1, data=iris )

1
क्या मैं सिर्फ यह जोड़ सकता हूं कि यह विधि castमेरे लिए उपयोग करने की तुलना में बहुत तेज थी ।
मैट वेलर 15

3
@GregSnow मैंने ?formulaसाथ ही साथ दूसरे पैराग्राफ की भी समीक्षा की ?model.matrix, लेकिन यह अस्पष्ट था (मैट्रिक्स बीजगणित और मॉडल निर्माण में ज्ञान की गहराई की कमी हो सकती है)। अधिक खुदाई करने के बाद, मैं यह इकट्ठा करने में सक्षम हुआ हूं कि -1 सिर्फ "इंटरसेप्ट" कॉलम को शामिल नहीं करने के लिए निर्दिष्ट कर रहा है। यदि आप -1 से बाहर निकलते हैं, तो आपको आउटपुट में 1 का इंटरसेप्ट कॉलम दिखाई देगा जिसमें एक बाइनरी कॉलम बचेगा। आप यह देखने में सक्षम हैं कि छोड़े गए मानों में से कौन-से मान 1 पंक्तियों पर आधारित हैं जहाँ अन्य स्तंभों का मान 0 है। प्रलेखन लगता है कि वहाँ एक और अच्छा संसाधन है?
रयान चेस

1
@RyanChase, R / S के बारे में कई ऑनलाइन ट्यूटोरियल और किताबें हैं (कई जिनमें r-project.org वेबपेज पर संक्षिप्त विवरण हैं)। एस और आर की मेरी खुद की शिक्षा बल्कि उदार (और लंबी) रही है, इसलिए मैं इस बात पर राय देने के लिए सबसे अच्छा नहीं हूं कि शुरुआती किताबों / ट्यूटोरियल शुरुआती लोगों से कैसे अपील करते हैं। हालाँकि, मैं प्रयोग का प्रशंसक हूँ। एक ताजा आर सत्र में कुछ करने की कोशिश करना बहुत ज्ञानवर्धक हो सकता है और खतरनाक नहीं है (मेरे साथ जो सबसे बुरा हुआ है वह आर दुर्घटनाग्रस्त हो रहा है, और शायद ही कभी, जो आर में सुधार का कारण बनता है)। तब क्या हुआ था, यह समझने के लिए स्टैकओवरफ्लो एक अच्छा संसाधन है।
ग्रेग स्नो

7
और यदि आप सभी कारक कॉलम को बदलना चाहते हैं, तो आप उपयोग कर सकते हैं:model.matrix(~., data=iris)[,-1]
user890739

1
@ कोलिन, पूरी तरह से स्वचालित नहीं है, लेकिन आप उपयोग naresidकरने के बाद लापता मूल्यों को वापस लाने के लिए उपयोग कर सकते हैं na.exclude। एक त्वरित उदाहरण:tmp <- data.frame(x=factor(c('a','b','c',NA,'a'))); tmp2 <- na.exclude(tmp); tmp3 <- model.matrix( ~x-1, tmp2); tmp4 <- naresid(attr(tmp2,'na.action'), tmp3)
ग्रेग स्नो

17

यदि आपका डेटा फ़्रेम केवल कारकों से बना है (या आप उन सबवे चर के उपसमुच्चय पर काम कर रहे हैं जो सभी कारक हैं), तो आप पैकेज acm.disjonctifसे फ़ंक्शन का उपयोग भी कर सकते हैं ade4:

R> library(ade4)
R> df <-data.frame(eggs = c("foo", "foo", "bar", "bar"), ham = c("red","blue","green","red"))
R> acm.disjonctif(df)
  eggs.bar eggs.foo ham.blue ham.green ham.red
1        0        1        0         0       1
2        0        1        1         0       0
3        1        0        0         1       0
4        1        0        0         0       1

बिल्कुल वैसा नहीं जैसा आप वर्णन कर रहे हैं, लेकिन यह उपयोगी भी हो सकता है ...


धन्यवाद, इससे मुझे बहुत मदद मिली क्योंकि यह कम मेमोरी का उपयोग करता है फिर model.matrix!
सेरही

मुझे पसंद है जिस तरह से चर नाम हो जाते हैं; मैं नापसंद है कि वे भंडारण के भूखे सांख्यिक जब वे के रूप में वापस कर रहे हैं चाहिए (IMHO) सिर्फ Logicals हो।
dsz

9

reshape2पैकेज का उपयोग करने का एक त्वरित तरीका :

require(reshape2)

> dcast(df.original, ham ~ eggs, length)

Using ham as value column: use value_var to override.
  ham bar foo
1   1   0   1
2   2   0   1
3   3   1   0
4   4   1   0

ध्यान दें कि यह आपके द्वारा इच्छित स्तंभ नामों का सटीक निर्माण करता है।


अच्छा। लेकिन हैम के डुप्लिकेट का ख्याल रखें। कहते हैं, घ <- data.frame (अंडे = सी ("फू", "बार", "फू"), हैम = सी (1,2,1)); dcast (d, हैम ~ अंडे, लंबाई) foo = 2. बनाता है
kohske

@ कोह, सच है, लेकिन मैं मान रहा था कि hamएक अनूठी पंक्ति आईडी है। यदि hamकोई विशिष्ट आईडी नहीं है, तो किसी को कुछ अन्य विशिष्ट-आईडी का उपयोग करना चाहिए (या एक डमी एक बनाएं) और उसके स्थान पर उपयोग करें ham। एक बाइनरी इंडिकेटर के लिए एक श्रेणीगत लेबल को परिवर्तित करना केवल अद्वितीय आईडी के लिए समझ में आता है।
प्रसाद चालसानी

6

शायद डमी वैरिएबल भी वैसा ही है जैसा आप चाहते हैं। फिर, model.matrix उपयोगी है:

> with(df.original, data.frame(model.matrix(~eggs+0), ham))
  eggsbar eggsfoo ham
1       0       1   1
2       0       1   2
3       1       0   3
4       1       0   4

6

पैकेज class.indसे एक देर से प्रवेशnnet

library(nnet)
 with(df.original, data.frame(class.ind(eggs), ham))
  bar foo ham
1   0   1   1
2   0   1   2
3   1   0   3
4   1   0   4

4

बस इस पुराने धागे के पार आया और सोचा कि मैं एक फ़ंक्शन जोड़ूंगा, जो कारकों और / या संख्यात्मक डेटा से मिलकर डेटाफ़्रेम लेने के लिए ade4 का उपयोग करता है और डमी कोड के रूप में कारकों के साथ एक डेटाफ़्रेम देता है।

dummy <- function(df) {  

    NUM <- function(dataframe)dataframe[,sapply(dataframe,is.numeric)]
    FAC <- function(dataframe)dataframe[,sapply(dataframe,is.factor)]

    require(ade4)
    if (is.null(ncol(NUM(df)))) {
        DF <- data.frame(NUM(df), acm.disjonctif(FAC(df)))
        names(DF)[1] <- colnames(df)[which(sapply(df, is.numeric))]
    } else {
        DF <- data.frame(NUM(df), acm.disjonctif(FAC(df)))
    }
    return(DF)
} 

चलो यह कोशिश करते हैं।

df <-data.frame(eggs = c("foo", "foo", "bar", "bar"), 
            ham = c("red","blue","green","red"), x=rnorm(4))     
dummy(df)

df2 <-data.frame(eggs = c("foo", "foo", "bar", "bar"), 
            ham = c("red","blue","green","red"))  
dummy(df2)

3

यहाँ यह करने का एक और अधिक स्पष्ट तरीका है। मैं डमी बूलियन चर बनाने के लिए model.matrix का उपयोग करता हूं और फिर इसे मूल डेटाफ़्रेम में वापस मर्ज करता हूं।

df.original <-data.frame(eggs = c("foo", "foo", "bar", "bar"), ham = c(1,2,3,4))
df.original
#   eggs ham
# 1  foo   1
# 2  foo   2
# 3  bar   3
# 4  bar   4

# Create the dummy boolean variables using the model.matrix() function.
> mm <- model.matrix(~eggs-1, df.original)
> mm
#   eggsbar eggsfoo
# 1       0       1
# 2       0       1
# 3       1       0
# 4       1       0
# attr(,"assign")
# [1] 1 1
# attr(,"contrasts")
# attr(,"contrasts")$eggs
# [1] "contr.treatment"

# Remove the "eggs" prefix from the column names as the OP desired.
colnames(mm) <- gsub("eggs","",colnames(mm))
mm
#   bar foo
# 1   0   1
# 2   0   1
# 3   1   0
# 4   1   0
# attr(,"assign")
# [1] 1 1
# attr(,"contrasts")
# attr(,"contrasts")$eggs
# [1] "contr.treatment"

# Combine the matrix back with the original dataframe.
result <- cbind(df.original, mm)
result
#   eggs ham bar foo
# 1  foo   1   0   1
# 2  foo   2   0   1
# 3  bar   3   1   0
# 4  bar   4   1   0

# At this point, you can select out the columns that you want.

0

मुझे 'एक्सप्लोड' कारकों के लिए एक फ़ंक्शन की आवश्यकता थी जो थोड़ा अधिक लचीला है, और ade4 पैकेज से acm.disjonctif फ़ंक्शन के आधार पर बनाया गया है। यह आपको विस्फोटित मूल्यों को चुनने की अनुमति देता है, जो कि acm.disjonctif में 0 और 1 हैं। यह केवल उन कारकों को विस्फोट करता है जिनके कुछ 'स्तर' होते हैं। संख्यात्मक स्तंभ संरक्षित हैं।

# Function to explode factors that are considered to be categorical,
# i.e., they do not have too many levels.
# - data: The data.frame in which categorical variables will be exploded.
# - values: The exploded values for the value being unequal and equal to a level.
# - max_factor_level_fraction: Maximum number of levels as a fraction of column length. Set to 1 to explode all factors.
# Inspired by the acm.disjonctif function in the ade4 package.
explode_factors <- function(data, values = c(-0.8, 0.8), max_factor_level_fraction = 0.2) {
  exploders <- colnames(data)[sapply(data, function(col){
      is.factor(col) && nlevels(col) <= max_factor_level_fraction * length(col)
    })]
  if (length(exploders) > 0) {
    exploded <- lapply(exploders, function(exp){
        col <- data[, exp]
        n <- length(col)
        dummies <- matrix(values[1], n, length(levels(col)))
        dummies[(1:n) + n * (unclass(col) - 1)] <- values[2]
        colnames(dummies) <- paste(exp, levels(col), sep = '_')
        dummies
      })
    # Only keep numeric data.
    data <- data[sapply(data, is.numeric)]
    # Add exploded values.
    data <- cbind(data, exploded)
  }
  return(data)
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.