उप-स्तरित डेटा फ़्रेम में फ़ैक्टर स्तर गिराएं


543

मेरे पास एक डेटा फ्रेम है जिसमें a factor। जब मैं subsetकिसी अन्य अनुक्रमणिका फ़ंक्शन का उपयोग करके इस डेटाफ़्रेम का सबसेट बनाता हूं , तो एक नया डेटा फ़्रेम बनाया जाता है। हालाँकि, factorचर अपने सभी मूल स्तरों को बनाए रखता है, तब भी जब वे नए डेटाफ़्रेम में मौजूद नहीं होते हैं।

यह कारकों की साजिश रचने या फ़ंक्शंस का उपयोग करते समय समस्याओं का कारण बनता है जो कारक स्तरों पर भरोसा करते हैं।

नए डेटाफ्रेम में एक कारक से स्तरों को हटाने का सबसे रसीला तरीका क्या है?

यहाँ एक उदाहरण है:

df <- data.frame(letters=letters[1:5],
                    numbers=seq(1:5))

levels(df$letters)
## [1] "a" "b" "c" "d" "e"

subdf <- subset(df, numbers <= 3)
##   letters numbers
## 1       a       1
## 2       b       2
## 3       c       3    

# all levels are still there!
levels(subdf$letters)
## [1] "a" "b" "c" "d" "e"

जवाबों:


420

सब्मिट करने के बाद आपको अपने वेरिएबल पर फैक्टर () लागू करना होगा:

> subdf$letters
[1] a b c
Levels: a b c d e
subdf$letters <- factor(subdf$letters)
> subdf$letters
[1] a b c
Levels: a b c

संपादित करें

कारक पृष्ठ उदाहरण से:

factor(ff)      # drops the levels that do not occur

डेटाफ़्रेम में सभी कारक स्तंभों से स्तरों को छोड़ने के लिए, आप उपयोग कर सकते हैं:

subdf <- subset(df, numbers <= 3)
subdf[] <- lapply(subdf, function(x) if(is.factor(x)) factor(x) else x)

22
यह एक-बंद के लिए ठीक है, लेकिन बड़ी संख्या में स्तंभों के साथ एक डेटा.फ्रेम में, आपको प्रत्येक स्तंभ पर ऐसा करने को मिलता है जो एक कारक है ... जो ड्रॉप के लिए एक फ़ंक्शन की आवश्यकता की ओर जाता है। () गदाता से।
डिर्क एडल्डबुलेटेल

6
मैं देख रहा हूं ... लेकिन उप-निर्माता [] <- lapply (सबडाउन, फंक्शन (x) अगर (is.factor (x)) फैक्टर (x) और x) ... जैसा कुछ लिखने के लिए यूजर-पर्सपेक्टिव से तेज है drop.levels () बड़े डेटा सेट के साथ अधिक कुशल कम्प्यूटेशनल या बेहतर? (एक विशाल डेटा फ्रेम के लिए एक लूप में ऊपर की पंक्ति को फिर से लिखना होगा, मुझे लगता है।)
हैमेट्रिक्स

1
धन्यवाद स्टीफन और डिर्क - मैं इसे एक कारक के आधार के लिए अंगूठे दे रहा हूं, लेकिन उम्मीद है कि लोग कारकों के एक पूरे डेटा फ्रेम की सफाई पर आपके सुझावों के लिए इन टिप्पणियों को पढ़ेंगे।
मेड्रिसॉल

9
एक पक्ष-प्रभाव के रूप में फ़ंक्शन डेटा फ़्रेम को एक सूची में परिवर्तित करता है, इसलिए mydf <- droplevels(mydf)नीचे दिए गए रोमन लुसट्र्रिक और टॉमी ओ'डेल द्वारा सुझाए गए समाधान बेहतर है।
जोहान

1
इसके अलावा: इस विधि करता चर के आदेश को बनाए रखने।
वेबेलो

492

2.12 संस्करण आर के बाद से, एक droplevels()फ़ंक्शन है।

levels(droplevels(subdf$letters))

7
उपयोग करने पर इस पद्धति का एक फायदा यह factor()है कि मूल डेटाफ़्रेम को संशोधित करना या एक नया लगातार डेटाफ़्रेम बनाना आवश्यक नहीं है। मैं droplevelsएक सबसेट किए गए डेटाफ़्रेम के चारों ओर लपेट सकता हूं और इसे एक जाली फ़ंक्शन के डेटा तर्क के रूप में उपयोग कर सकता हूं , और समूहों को सही तरीके से नियंत्रित किया जाएगा।
मंगल

मैंने देखा है कि अगर मेरे पास मेरे कारक में एक NA स्तर है (एक वास्तविक NA स्तर), तो यह गिराए स्तर से गिरा दिया जाता है, भले ही NA मौजूद हो।
मीप

46

यदि आप यह व्यवहार नहीं चाहते हैं, तो कारकों का उपयोग न करें, इसके बजाय चरित्र वैक्टर का उपयोग करें। मुझे लगता है कि यह चीजों को बाद में पैच करने से ज्यादा मायने रखता है। के साथ अपने डेटा लोड करने से पहले निम्नलिखित का प्रयास करें read.tableया read.csv:

options(stringsAsFactors = FALSE)

नुकसान यह है कि आप वर्णानुक्रम में प्रतिबंधित हैं। (भूखंडों के लिए आपका मित्र है)


38

यह एक ज्ञात समस्या है, और एक संभव उपाय द्वारा प्रदान की जाती है drop.levels()में GData जहां अपने उदाहरण बन जाता है पैकेज

> drop.levels(subdf)
  letters numbers
1       a       1
2       b       2
3       c       3
> levels(drop.levels(subdf)$letters)
[1] "a" "b" "c"

Hmisc पैकेज dropUnusedLevelsमें फ़ंक्शन भी है । हालांकि, यह केवल सबसेट ऑपरेटर को बदलकर काम करता है और यहां लागू नहीं है।[

एक कोरोलरी के रूप में, प्रति-स्तंभ आधार पर एक सीधा दृष्टिकोण एक सरल है as.factor(as.character(data)):

> levels(subdf$letters)
[1] "a" "b" "c" "d" "e"
> subdf$letters <- as.factor(as.character(subdf$letters))
> levels(subdf$letters)
[1] "a" "b" "c"

5
reorderके पैरामीटर drop.levelsसमारोह उल्लेख के लायक है: यदि आप अपने कारकों में से मूल आदेश को बचाने के लिये किया है, के साथ उपयोग FALSEमूल्य।
दरोगासीग

बस ड्रॉप.वेल्स पैदावार के लिए gdata का उपयोग करना "gdata: read.xls 'XLS' (Excel 97-2004) फ़ाइलों के लिए समर्थन ENABLED।" "gdata: read.xls ()" "gdata: 'XLSX' (एक्सेल 2007+) फ़ाइलों का समर्थन करने के लिए आवश्यक पर्ल प्रतिवादियों को लोड करने में असमर्थ।" "gdata: फ़ंक्शन स्थापित करें 'installXLSXsupport ()'" "gdata: स्वचालित रूप से डाउनलोड और पर्ल को स्थापित करने के लिए"। आधार से बूंदों का उपयोग करें ( stackoverflow.com/a/17218028/9295807 )
व्रोकपाल

समय के साथ सामान होता है। आप नौ साल पहले लिखे एक उत्तर पर टिप्पणी कर रहे हैं । तो चलिए इसे एक संकेत के रूप में लेते हैं जो आमतौर पर आधार आर समाधानों को पसंद करते हैं क्योंकि वे कार्यक्षमता का उपयोग करने वाले हैं जो अभी से लगभग एन साल होने जा रहे हैं।
डिर्क एडल्डबुलेटेल

25

ऐसा ही करने का एक और तरीका लेकिन dplyr

library(dplyr)
subdf <- df %>% filter(numbers <= 3) %>% droplevels()
str(subdf)

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

भी काम करता है! अगेनिस के लिए धन्यवाद

subdf <- df %>% filter(numbers <= 3) %>% droplevels
levels(subdf$letters)

17

संपूर्णता की खातिर, अब पैकेज http://forcats.tidyverse.org/reference/fctn/google.htmlfct_drop में भी है ।forcats

यह droplevelsउस तरीके से भिन्न होता है जिस तरीके से यह व्यवहार करता है NA:

f <- factor(c("a", "b", NA), exclude = NULL)

droplevels(f)
# [1] a    b    <NA>
# Levels: a b <NA>

forcats::fct_drop(f)
# [1] a    b    <NA>
# Levels: a b

15

यहाँ एक और तरीका है, जो मुझे लगता है कि factor(..)दृष्टिकोण के बराबर है :

> df <- data.frame(let=letters[1:5], num=1:5)
> subdf <- df[df$num <= 3, ]

> subdf$let <- subdf$let[ , drop=TRUE]

> levels(subdf$let)
[1] "a" "b" "c"

हा, इन सभी वर्षों के बाद मुझे नहीं पता था `[.factor`कि एक विधि है जिसका एक dropतर्क है और आपने इसे 2009 में पोस्ट किया है ...
डेविड अर्गेनबर्ग

8

यह अप्रिय है। अन्य पैकेजों को लोड करने से बचने के लिए मैं आमतौर पर ऐसा करता हूं:

levels(subdf$letters)<-c("a","b","c",NA,NA)

जो आपको मिलता है:

> subdf$letters
[1] a b c
Levels: a b c

ध्यान दें कि नए स्तर पुराने स्तर में अपने सूचकांक में जो कुछ भी शामिल है, उसे प्रतिस्थापित करेंगे (सबफ़ोर्ड $ लेटर्स), इसलिए कुछ इस तरह है:

levels(subdf$letters)<-c(NA,"a","c",NA,"b")

काम नहीं करेगा।

यह स्पष्ट रूप से आदर्श नहीं है जब आपके पास बहुत सारे स्तर हैं, लेकिन कुछ के लिए, यह त्वरित और आसान है।


8

को देखते हुए droplevelsतरीकों आर स्रोत में कोड आप देख सकते हैं यह करने के लिए लपेटता factorकार्य करते हैं। इसका मतलब है कि आप मूल रूप से factorफ़ंक्शन के साथ कॉलम को फिर से बना सकते हैं ।
सभी कारक कॉलम से स्तरों को छोड़ने के डेटाटेबल तरीके के नीचे।

library(data.table)
dt = data.table(letters=factor(letters[1:5]), numbers=seq(1:5))
levels(dt$letters)
#[1] "a" "b" "c" "d" "e"
subdt = dt[numbers <= 3]
levels(subdt$letters)
#[1] "a" "b" "c" "d" "e"

upd.cols = sapply(subdt, is.factor)
subdt[, names(subdt)[upd.cols] := lapply(.SD, factor), .SDcols = upd.cols]
levels(subdt$letters)
#[1] "a" "b" "c"

1
मुझे लगता है कि data.tableरास्ता कुछ ऐसा होगाfor (j in names(DT)[sapply(DT, is.factor)]) set(DT, j = j, value = factor(DT[[j]]))
डेविड ऐरनबर्ग

1
@ डेविडविरेनबर्ग यहां बहुत बदलाव नहीं करते क्योंकि हम [.data.tableकेवल एक बार फोन करते हैं
jangorecki

7

यहाँ ऐसा करने का एक तरीका है

varFactor <- factor(letters[1:15])
varFactor <- varFactor[1:5]
varFactor <- varFactor[drop=T]

2
यह इस उत्तर का एक हिस्सा है जिसे 5 साल पहले पोस्ट किया गया था।
डेविड एरनबर्ग

6

मैंने ऐसा करने के लिए उपयोगिता कार्य लिखे। अब जब मुझे gdata के drop.levels के बारे में पता चला है, तो यह काफी हद तक समान दिखता है। यहाँ वे ( यहाँ से ):

present_levels <- function(x) intersect(levels(x), x)

trim_levels <- function(...) UseMethod("trim_levels")

trim_levels.factor <- function(x)  factor(x, levels=present_levels(x))

trim_levels.data.frame <- function(x) {
  for (n in names(x))
    if (is.factor(x[,n]))
      x[,n] = trim_levels(x[,n])
  x
}

4

बहुत दिलचस्प धागा, मुझे विशेष रूप से सिर्फ कारक के बारे में विचार करना पसंद था। मुझे पहले भी ऐसी ही समस्या थी और मैं सिर्फ चरित्र में परिवर्तित हुआ और फिर वापस फैक्टर में आ गया।

   df <- data.frame(letters=letters[1:5],numbers=seq(1:5))
   levels(df$letters)
   ## [1] "a" "b" "c" "d" "e"
   subdf <- df[df$numbers <= 3]
   subdf$letters<-factor(as.character(subdf$letters))

मेरा मतलब है, factor(as.chracter(...))काम करता है, लेकिन कुशलता से और कुशलता से कम factor(...)। अन्य उत्तरों की तुलना में कड़ाई से बदतर लगता है।
ग्रेगर थॉमस

1

RevoScaleR के rxDataStep का उपयोग करते समय दुर्भाग्य से कारक () काम नहीं करता है। मैं इसे दो चरणों में करता हूं: 1) अस्थायी बाहरी डेटा फ्रेम (.xdf) में चरित्र और स्टोर में कनवर्ट करें। 2) निश्चित बाहरी डेटा फ्रेम में फैक्टर और स्टोर में वापस कनवर्ट करें। यह किसी भी अप्रयुक्त कारक के स्तर को समाप्त करता है, सभी डेटा को मेमोरी में लोड किए बिना।

# Step 1) Converts to character, in temporary xdf file:
rxDataStep(inData = "input.xdf", outFile = "temp.xdf", transforms = list(VAR_X = as.character(VAR_X)), overwrite = T)
# Step 2) Converts back to factor:
rxDataStep(inData = "temp.xdf", outFile = "output.xdf", transforms = list(VAR_X = as.factor(VAR_X)), overwrite = T)

1

यहाँ उदाहरणों की कोशिश की है अगर सभी नहीं, लेकिन कोई भी मेरे मामले में काम करने लगता है। काफी समय तक संघर्ष करने के बाद मैंने इसे स्तंभ के रूप में बदलने के लिए फैक्टर कॉलम पर as.character () का उपयोग करने की कोशिश की है जो कि बस ठीक काम करने के लिए लगता है।

प्रदर्शन के मुद्दों के लिए निश्चित नहीं है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.