একটি সাবসেটেড ডেটা ফ্রেমে ফ্যাক্টর স্তরগুলি ড্রপ করুন


543

আমার একটিতে একটি ডেটা ফ্রেম রয়েছে 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
এটি এক-অফের জন্য ঠিক আছে, তবে বিপুল সংখ্যক কলাম সহ একটি ডেটা ফ্রেমে আপনি প্রতিটি কলামে এটি করতে পারেন যা একটি ফ্যাক্টর ... ড্রপ.লেভেলস () এর মতো কোনও ক্রিয়াকলাপের প্রয়োজনীয়তার দিকে পরিচালিত করে gdata থেকে।
ডর্ক এডেলবুয়েটেল

6
আমি দেখছি ... তবে ব্যবহারকারীর দৃষ্টিকোণ থেকে এটি সাবডিএফ [] <- ল্যাপলি (সাবডিএফ, ফাংশন (এক্স)) (যদি.ফ্যাক্টর (এক্স)) ফ্যাক্টর (এক্স) অন্য এক্স) এর মতো কিছু লিখতে দ্রুত ... ড্রপ.লেভেলস () কম্পিউটারের তুলনায় আরও বেশি দক্ষ বা বড় ডেটা সেটগুলির সাথে আরও ভাল? (একটি বিশাল ডেটা ফ্রেমের জন্য একটি লুপের জন্য উপরের লাইনটি আবার লিখতে হবে, আমার ধারণা))
হ্যাটমেট্রিক্স

1
ধন্যবাদ স্টিফেন এবং ডার্ক - আমি এই একটিকে একটি ফ্যাক্টরের সিএসের জন্য থাম্বস দিচ্ছি, তবে আশা করি লোকেরা একটি সম্পূর্ণ ডেটা ফ্রেম পরিষ্কার করার বিষয়ে আপনার পরামর্শের জন্য এই মন্তব্যগুলি পড়বেন।
মেডিশ্রাকল

9
পার্শ্ব-প্রতিক্রিয়া হিসাবে ফাংশনটি ডেটা ফ্রেমকে একটি তালিকায় রূপান্তর করে, সুতরাং mydf <- droplevels(mydf)নীচে রোমান লুইট্রিক এবং টমি ওডেল প্রস্তাবিত সমাধানটি পছন্দনীয়।
জোহান

1
এছাড়াও: এই পদ্ধতি আছে ভেরিয়েবলের ক্রম সংরক্ষণ।
ওয়েবেলো

492

আর সংস্করণ ২.১২ থেকে যেহেতু একটি droplevels()ফাংশন রয়েছে।

levels(droplevels(subdf$letters))

7
ব্যবহারের মাধ্যমে এই পদ্ধতির একটি সুবিধা factor()হ'ল মূল ডেটাফ্রেমটি সংশোধন করা বা একটি নতুন ধ্রুবক ডেটাফ্রেম তৈরি করা প্রয়োজন হয় না। আমি droplevelsএকটি সাবসেটেড ডেটাফ্রেম চারপাশে মোড়ানো করতে পারি এবং এটি একটি জাল ফাংশনটির ডেটা আর্গুমেন্ট হিসাবে ব্যবহার করতে পারি এবং গোষ্ঠীগুলি সঠিকভাবে পরিচালনা করা হবে।
মঙ্গল

আমি লক্ষ করেছি যে আমার ফ্যাক্টারে যদি একটি এনএ স্তর থাকে (একটি আসল এনএ স্তর) তবে এটি এনএএস উপস্থিত থাকলেও এটি বাদ পড়ে যায় by
মিপ

46

আপনি যদি এই আচরণটি না চান তবে কারণগুলি ব্যবহার করবেন না, পরিবর্তে অক্ষর ভেক্টর ব্যবহার করুন। আমি মনে করি এটি পরে জিনিসগুলি প্যাচিংয়ের চেয়ে আরও বেশি অর্থবোধ করে। read.tableবা আপনার ডেটা লোড করার আগে নিম্নলিখিত চেষ্টা করুন read.csv:

options(stringsAsFactors = FALSE)

অসুবিধাটি হ'ল আপনি বর্ণানুক্রমিক ক্রম সীমাবদ্ধ। (পুনরায় ক্রম আপনার প্লট জন্য বন্ধু)


38

এটি একটি পরিচিত সমস্যা এবং একটি সম্ভাব্য প্রতিকার gdata প্যাকেজের মাধ্যমে সরবরাহ করা drop.levels()হয়েছে যেখানে আপনার উদাহরণ হয়ে যায়

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

রয়েছে dropUnusedLevelsফাংশন Hmisc প্যাকেজ। তবে এটি কেবলমাত্র সাবসেট অপারেটর পরিবর্তন করেই কাজ করে[ এবং এটি এখানে প্রযোজ্য নয়।

রূপান্তর হিসাবে, প্রতি-কলামের ভিত্তিতে সরাসরি পন্থা একটি সহজ 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মান।
daroczig

কেবল ড্রপ.লেভেলের ফলস্বরূপ জিডিটা ব্যবহার করে "জিডিটা: রিড.এক্সলস 'এক্সএলএস' (এক্সেল 97-2004) ফাইল সক্ষম করে support "জিডিটা: রিড.এক্সলস () দ্বারা প্রয়োজনীয় পার্ল লিবারি লোড করতে অক্ষম" "জিডিটা: 'এক্সএলএসএক্স' (এক্সেল 2007+) ফাইলগুলি সমর্থন করার জন্য।" "জিডিটা: পার্লটি স্বয়ংক্রিয়ভাবে ডাউনলোড এবং ইনস্টল করতে" "এক্সডএক্সএলএসএক্সসপোর্ট ()" "জিডিটা: ফাংশনটি চালান"। BaseR ব্যবহারের droplevels ( stackoverflow.com/a/17218028/9295807 )
Vrokipal

সময়ের সাথে সাথে স্টাফ হয়। আপনি হয় একটি উত্তর আমি নয় বছর আগে লিখেছিলেন মন্তব্য। সুতরাং আসুন সাধারণত এটি বেস আর সমাধানগুলিকে পছন্দ করার ইঙ্গিত হিসাবে গ্রহণ করি কারণ সেগুলি হ'ল কার্যকারিতা ব্যবহার করে যা এখন থেকে প্রায় N বছর হতে চলেছে ।
ডার্ক এডেলবুয়েটেল

25

একই কাজ করার অন্য একটি উপায় dplyr

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

সম্পাদনা:

এছাড়াও কাজ! এজেন্সি ধন্যবাদ

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

17

সম্পূর্ণতার অনুরোধে জন্য, এখন সেখানে হয় fct_dropমধ্যে forcatsপ্যাকেজ http://forcats.tidyverse.org/reference/fct_drop.html

এটি 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ফাংশন সহ কলামটি পুনরায় তৈরি করতে পারেন ।
সমস্ত ফ্যাক্টর কলামগুলি থেকে স্তরগুলি ড্রপ করার উপাত্তের নীচে t

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.tablefor (j in names(DT)[sapply(DT, is.factor)]) set(DT, j = j, value = factor(DT[[j]]))
উপায়টি

1
@ ডেভিড আরেনবুর্গ এখানে [.data.tableকেবল একবার কল করার কারণে এটি এখানে খুব বেশি পরিবর্তন হয় না
জঙ্গোরেকি

7

এখানে এটি করার একটি উপায়

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

2
এটি এই উত্তরটির একটি দ্বি যা 5 বছর আগে পোস্ট করা হয়েছিল।
ডেভিড আরেনবার্গ

6

এটি করার জন্য আমি ইউটিলিটি ফাংশন লিখেছি। এখন যেহেতু আমি জিডাটার ড্রপ.লেভেলগুলি সম্পর্কে জানি, এটি দেখতে বেশ সাদৃশ্যপূর্ণ। তারা এখানে ( এখানে থেকে ):

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 () ব্যবহার করার চেষ্টা করেছি ফ্যাক্টর কলামে করেছি যাতে এটি স্ট্রিংগুলির সাথে একটি পরিবর্তন করতে পারে যা মনে হয় ঠিক কাজ করে।

পারফরম্যান্স সমস্যার জন্য নিশ্চিত নয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.