R डेटाफ़्रेम से `Inf` मानों की सफाई


101

आर में, मेरे पास एक ऑपरेशन है जो Infडेटाफ़्रेम बदलने पर कुछ मान बनाता है ।

मैं इन Infमूल्यों को चालू करना चाहूंगाNA मूल्यों । मेरे पास बड़े डेटा के लिए कोड धीमा है, क्या ऐसा करने का एक तेज़ तरीका है?

कहो कि मेरे पास निम्नलिखित डेटाफ़्रेम हैं:

dat <- data.frame(a=c(1, Inf), b=c(Inf, 3), d=c("a","b"))

निम्नलिखित एक ही मामले में काम करता है:

 dat[,1][is.infinite(dat[,1])] = NA

इसलिए मैंने इसे निम्नलिखित लूप के साथ सामान्यीकृत किया

cf_DFinf2NA <- function(x)
{
    for (i in 1:ncol(x)){
          x[,i][is.infinite(x[,i])] = NA
    }
    return(x)
}

लेकिन मुझे नहीं लगता कि यह वास्तव में आर की शक्ति का उपयोग कर रहा है।

जवाबों:


119

विकल्प 1

इस तथ्य का उपयोग करें कि एक data.frameकॉलम की एक सूची है, फिर do.callए को फिर से बनाने के लिए उपयोग करें data.frame

do.call(data.frame,lapply(DT, function(x) replace(x, is.infinite(x),NA)))

विकल्प 2 -- data.table

आप उपयोग कर सकते हैं data.tableऔर set। यह कुछ आंतरिक नकल से बचा जाता है।

DT <- data.table(dat)
invisible(lapply(names(DT),function(.name) set(DT, which(is.infinite(DT[[.name]])), j = .name,value =NA)))

या स्तंभ संख्याओं का उपयोग करना (संभवतः बहुत तेज़ हो तो बहुत सारे स्तंभ हैं):

for (j in 1:ncol(DT)) set(DT, which(is.infinite(DT[[j]])), j, NA)

समय

# some `big(ish)` data
dat <- data.frame(a = rep(c(1,Inf), 1e6), b = rep(c(Inf,2), 1e6), 
                  c = rep(c('a','b'),1e6),d = rep(c(1,Inf), 1e6),  
                  e = rep(c(Inf,2), 1e6))
# create data.table
library(data.table)
DT <- data.table(dat)

# replace (@mnel)
system.time(na_dat <- do.call(data.frame,lapply(dat, function(x) replace(x, is.infinite(x),NA))))
## user  system elapsed 
#  0.52    0.01    0.53 

# is.na (@dwin)
system.time(is.na(dat) <- sapply(dat, is.infinite))
# user  system elapsed 
# 32.96    0.07   33.12 

# modified is.na
system.time(is.na(dat) <- do.call(cbind,lapply(dat, is.infinite)))
#  user  system elapsed 
# 1.22    0.38    1.60 


# data.table (@mnel)
system.time(invisible(lapply(names(DT),function(.name) set(DT, which(is.infinite(DT[[.name]])), j = .name,value =NA))))
# user  system elapsed 
# 0.29    0.02    0.31 

data.tableसबसे तेज है। sapplyधीरे-धीरे चीजों का उपयोग करना ।


1
समय पर महान काम और संशोधन @mnel। काश, खातों में प्रतिनिधि को स्थानांतरित करने का एक एसओ तरीका होता। मुझे लगता है कि मैं बाहर जाऊंगा और आपके कुछ अन्य जवाबों को बढ़ाऊंगा।
IRTFM

do.call में त्रुटि (ट्रेन, lapply (ट्रेन, फ़ंक्शन (x) को प्रतिस्थापित करें (x, is.infinite (x)): 'क्या' एक चरित्र स्ट्रिंग या एक फ़ंक्शन होना चाहिए
हैक-आर

60

का उपयोग करें sapplyऔरis.na<-

> dat <- data.frame(a=c(1, Inf), b=c(Inf, 3), d=c("a","b"))
> is.na(dat) <- sapply(dat, is.infinite)
> dat
   a  b d
1  1 NA a
2 NA  3 b

या आप उपयोग कर सकते हैं (@mnel को क्रेडिट दे रहे हैं, जिसका यह संपादन है),

> is.na(dat) <- do.call(cbind,lapply(dat, is.infinite))

जो काफी तेज है।


5
"चाल" को साकार करने में था, is.na<-एक परिणाम को स्वीकार नहीं करेगा lapplyलेकिन एक को स्वीकार करेगा sapply
आईआरटीएफएम

मैंने कुछ समय जोड़े हैं। मुझे यकीन नहीं है कि is.na<-समाधान इतना धीमा क्यों है।
मंगल

प्रोफाइलिंग का एक सा, और मैंने आपके समाधान को बहुत तेज़ होने के लिए संपादित किया है।
एमएन

19

[<-की mapplyतुलना में थोड़ा तेज है sapply

> dat[mapply(is.infinite, dat)] <- NA

मेल के डेटा के साथ, समय है

> system.time(dat[mapply(is.infinite, dat)] <- NA)
#   user  system elapsed 
# 15.281   0.000  13.750 

11

यहाँ na_if () फ़ंक्शन का उपयोग करके एक dplyr / tidyverse समाधान है :

dat %>% mutate_if(is.numeric, list(~na_if(., Inf)))

ध्यान दें कि यह केवल NA के साथ सकारात्मक अनंत को बदलता है। यदि नकारात्मक अनंत मूल्यों को भी प्रतिस्थापित करने की आवश्यकता है, तो दोहराने की आवश्यकता है।

dat %>% mutate_if(is.numeric, list(~na_if(., Inf))) %>% 
  mutate_if(is.numeric, list(~na_if(., -Inf)))

5

हबलर पैकेज में इस समस्या का बहुत ही सरल समाधान है:

library(hablar)

dat %>% rationalize()

सभी Inf वाले डेटा फ़्रेम को NA में कनवर्ट किया जाता है।

उपरोक्त कुछ समाधानों की तुलना में समय। कोड: पुस्तकालय (हबलर) पुस्तकालय (data.table)

dat <- data.frame(a = rep(c(1,Inf), 1e6), b = rep(c(Inf,2), 1e6), 
                  c = rep(c('a','b'),1e6),d = rep(c(1,Inf), 1e6),  
                  e = rep(c(Inf,2), 1e6))
DT <- data.table(dat)

system.time(dat[mapply(is.infinite, dat)] <- NA)
system.time(dat[dat==Inf] <- NA)
system.time(invisible(lapply(names(DT),function(.name) set(DT, which(is.infinite(DT[[.name]])), j = .name,value =NA))))
system.time(rationalize(dat))

परिणाम:

> system.time(dat[mapply(is.infinite, dat)] <- NA)
   user  system elapsed 
  0.125   0.039   0.164 
> system.time(dat[dat==Inf] <- NA)
   user  system elapsed 
  0.095   0.010   0.108 
> system.time(invisible(lapply(names(DT),function(.name) set(DT, which(is.infinite(DT[[.name]])), j = .name,value =NA))))
   user  system elapsed 
  0.065   0.002   0.067 
> system.time(rationalize(dat))
   user  system elapsed 
  0.058   0.014   0.072 
> 

Data.table जैसा लगता हैबेलर से तेज है। लेकिन लंबे समय तक वाक्य रचना है।


कृपया समय दें?
रिकाडर्ड

@ricardo ने कुछ समय जोड़ा
davsjob

1

फेंग माई के पास नकारात्मक और सकारात्मक जानकारी प्राप्त करने के लिए ऊपर एक स्पष्ट उत्तर है:

dat %>% mutate_if(is.numeric, list(~na_if(., Inf))) %>% 
  mutate_if(is.numeric, list(~na_if(., -Inf)))

यह अच्छी तरह से काम करता है, लेकिन चेतावनी के एक शब्द को एब्स (स्वैप) में स्वैप नहीं करना है, दोनों लाइनों को एक बार में करने के लिए जैसा कि एक टिप्पणी में प्रस्तावित है। ऐसा लगेगा कि यह काम करता है, लेकिन डाटासेट में सभी नकारात्मक मूल्यों को सकारात्मक में बदल देता है! आप इसकी पुष्टि कर सकते हैं:

data(iris)
#The last line here is bad - it converts all negative values to positive
iris %>% 
  mutate_if(is.numeric, ~scale(.)) %>%
  mutate(infinities = Sepal.Length / 0) %>%
  mutate_if(is.numeric, list(~na_if(abs(.), Inf)))

एक पंक्ति के लिए, यह काम करता है:

  mutate_if(is.numeric, ~ifelse(abs(.) == Inf,NA,.))

1
अच्छी पकड़! मैंने इस टिप्पणी को मूल टिप्पणी पर जोड़ा है - मुझे लगता है कि नए उत्तर की तुलना में इस मुद्दे को हल करने के लिए यह एक बेहतर जगह है। आपको कहीं भी टिप्पणी करने के लिए आवश्यक 50 प्रतिष्ठा के लिए थोड़ा करीब लाने के लिए अपवोट के योग्य कुछ पोस्ट मिलीं।
ग्रेगर थॉमस

धन्यवाद! यदि मैं सक्षम होता तो मैं एक टिप्पणी छोड़ देता।
मार्क ई।

0

एक और समाधान:

    dat <- data.frame(a = rep(c(1,Inf), 1e6), b = rep(c(Inf,2), 1e6), 
                      c = rep(c('a','b'),1e6),d = rep(c(1,Inf), 1e6),  
                      e = rep(c(Inf,2), 1e6))
    system.time(dat[dat==Inf] <- NA)

#   user  system elapsed
#  0.316   0.024   0.340

MusTheDataGuy, आप मेरे उत्तर को क्यों संपादित करेंगे लेकिन अपना समाधान नहीं जोड़ेंगे? पहले से ही "एक और उत्तर जोड़ें" बटन है!
छात्र

-1

आप हेंड रिप्ले__ फ़ंक्शन का उपयोग भी कर सकते हैं: https://tidyr.tidyverse.org/reference/replace_na.html


1
यह एक बॉर्डरलाइन लिंक-ओनली उत्तर है । आपको यहाँ पर अधिक से अधिक जानकारी शामिल करने के लिए अपने उत्तर का विस्तार करना चाहिए, और केवल संदर्भ के लिए लिंक का उपयोग करना चाहिए।
अलविदा StackExchange
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.