निकटतम 10 (या 100 या X) पर गोल कैसे करें?


93

मैं डेटा प्लॉट करने के लिए एक फ़ंक्शन लिख रहा हूं। मैं उस y- अक्ष के लिए एक अच्छा दौर संख्या निर्दिष्ट करना चाहूंगा maxजो कि अधिकतम डेटासेट से अधिक है।

विशेष रूप से, मैं एक ऐसा कार्य करना चाहूंगा fooजो निम्नलिखित कार्य करे :

foo(4) == 5
foo(6.1) == 10 #maybe 7 would be better
foo(30.1) == 40
foo(100.1) == 110 

मैंने जहां तक ​​पाया है

foo <- function(x) ceiling(max(x)/10)*10

निकटतम 10 के लिए गोलाई के लिए, लेकिन यह मनमाना गोलाई अंतराल के लिए काम नहीं करता है।

आर में ऐसा करने का एक बेहतर तरीका है?


साजिश रचते समय R डिफ़ॉल्ट व्यवहार प्रत्येक दिशा में डेटा की सीमा से परे प्लॉट की सीमा ~ 4% है। यदि यह आपके लिए संतोषजनक नहीं है तो शायद कुछ ऐसा लिखें जो उच्च या निम्न% द्वारा बाहर जाए?
२१:३

@joran जानकारी के लिए धन्यवाद, लेकिन मैं कई भूखंडों को चाहता हूं कि सभी में एक ही धुरी की सीमाएं और टिक हैं और मुझे यकीन नहीं है कि यह कैसे मदद करता है।
अबे

1
खैर, मैं यहाँ अंधेरे में टटोलने का काम कर रहा हूँ, क्योंकि मुझे सारी पृष्ठभूमि का पता नहीं है। यदि आप सिर्फ एक और पैरामीटर X जोड़ते हैं और 10 के X दोनों के साथ बदल देते हैं, तो आपका फू निकटतम X तक पहुंच जाएगा। या आप इसका उपयोग कर सकते हैं।
२१:५० पर जोरन

15
क्या आप ढूंढ रहे हैं ?pretty?
हैडली

क्यों foo(4)==5और क्या नहीं है 10?
जेम्स

जवाबों:


64

यदि आप केवल 10 की निकटतम शक्ति तक चक्कर लगाना चाहते हैं, तो बस परिभाषित करें:

roundUp <- function(x) 10^ceiling(log10(x))

यह वास्तव में भी काम करता है जब x एक वेक्टर होता है:

> roundUp(c(0.0023, 3.99, 10, 1003))
[1] 1e-02 1e+01 1e+01 1e+04

.. लेकिन अगर आप "अच्छा" नंबर लेना चाहते हैं, तो आपको सबसे पहले यह परिभाषित करना होगा कि "अच्छा" नंबर क्या है। निम्नलिखित हमें 1 से 10 तक के अच्छे मानों के साथ वेक्टर के रूप में "अच्छा" परिभाषित करने देता है। डिफ़ॉल्ट को सम संख्या 5 पर सेट किया गया है।

roundUpNice <- function(x, nice=c(1,2,4,5,6,8,10)) {
    if(length(x) != 1) stop("'x' must be of length 1")
    10^floor(log10(x)) * nice[[which(x <= 10^floor(log10(x)) * nice)[[1]]]]
}

ऊपर काम नहीं करता है जब x एक वेक्टर है - अभी शाम को बहुत देर हो चुकी है :)

> roundUpNice(0.0322)
[1] 0.04
> roundUpNice(3.22)
[1] 4
> roundUpNice(32.2)
[1] 40
> roundUpNice(42.2)
[1] 50
> roundUpNice(422.2)
[1] 500

[[संपादित करें]]

यदि प्रश्न यह है कि किसी निर्दिष्ट निकटतम मान (जैसे 10 या 100) पर कैसे गोल किया जाए, तो जेम्स उत्तर सबसे उपयुक्त लगता है। मेरा संस्करण आपको किसी भी मूल्य को लेने देता है और स्वचालित रूप से इसे यथोचित "अच्छा" मान देता है। ऊपर "अच्छा" वेक्टर के कुछ अन्य अच्छे विकल्प हैं:1:10, c(1,5,10), seq(1, 10, 0.1)

यदि आपके पास अपने भूखंड में मूल्यों की एक सीमा है, उदाहरण के लिए [3996.225, 40001.893]तो स्वचालित तरीके को सीमा के आकार और संख्याओं के परिमाण दोनों को ध्यान में रखना चाहिए। और जैसा कि हैडली ने उल्लेख किया , pretty()फ़ंक्शन वही हो सकता है जो आप चाहते हैं।


1
Vectorize(roundUpNice)वैसे भी काफी तेज है =) +1 वैसे भी।
mbq

मैं सोच रहा था कि क्या मूल परिणाम कम होने पर अंतिम परिणाम के लिए राउंडअप फ़ंक्शन को संपादित करने का एक तरीका है? उदाहरण के लिए 101-500 के बीच एक संख्या 500 के लिए राउंडअप और 501-999 की संख्या राउंडअप से 1000 तक होगी? 1000 के चक्कर लगाने के बजाय?
हेलन।

बस अच्छा वेक्टर बदलें:roundUpNice(501, nice=c(5, 10)) # 1000
टॉमी

1
जब आप अपने कार्य में लघुगणक के साथ काम करते हैं, तो मेरे पास 2 मामले होते हैं, एक जहां पीछे डालने से पहले लॉग में x < 0होता - xहै -। मैं उस स्थिति के लिए एक अपवाद भी x = 0
जोड़ूंगा

सुंदर समारोह ने मेरी जरूरतों के लिए बहुत अच्छा काम किया (एक ग्राफ एक्स एक्स पर एक सुंदर सीमा निर्धारित करने के लिए)
जून

132

plyrपुस्तकालय एक समारोह है round_anyकि सुंदर गोलाई के सभी प्रकार करने के लिए सामान्य है। उदाहरण के लिए

library(plyr)
round_any(132.1, 10)               # returns 130
round_any(132.1, 10, f = ceiling)  # returns 140
round_any(132.1, 5, f = ceiling)   # returns 135

एक dplyrप्रतिस्थापन के लिए, देखें: stackoverflow.com/a/46489816/435093
slhck

46

R में राउंड फंक्शन यदि ऋणात्मक है तो अंक पैरामीटर को विशेष अर्थ प्रदान करता है।

गोल (x, अंक = 0)

ऋणात्मक संख्याओं को गोल करने का अर्थ है, दस की शक्ति के लिए गोलाई, इसलिए उदाहरण के लिए गोल (x, अंक = -2) निकटतम सौ के लिए गोल।

इसका मतलब यह है कि निम्न जैसा कोई कार्य आपके लिए पूछ रहा है उसके बहुत करीब हो जाता है

foo <- function(x)
{
    round(x+5,-1)
}

आउटपुट निम्न जैसा दिखता है

foo(4)
[1] 10
foo(6.1)
[1] 10
foo(30.1)
[1] 40
foo(100.1)
[1] 110

2
बहुत बढ़िया! आपके उत्तर को सही के रूप में चिह्नित किया जाना चाहिए!
एलेसांद्रो जैकपसन

+1। हालाँकि, मेरे उत्तर में @Alessandro फ़ंक्शन बहुत अधिक बहुमुखी हैं: आप किसी भी संख्या को किसी भी अंतराल पर या नीचे राउंड कर सकते हैं।
theforestecologist

@forestecologist संकेत के लिए धन्यवाद! एक व्यक्तिगत स्वाद के रूप में, मैं आमतौर पर एक कस्टम के बजाय एक भाषा में निर्मित समाधान पसंद करता हूं।
एलेसांद्रो जैकॉपसन

27

कैसा रहेगा:

roundUp <- function(x,to=10)
{
  to*(x%/%to + as.logical(x%%to))
}

जो देता है:

> roundUp(c(4,6.1,30.1,100.1))
[1]  10  10  40 110
> roundUp(4,5)
[1] 5
> roundUp(12,7)
[1] 14

1
@daroczig सवाल थोड़ा भ्रमित करने वाला है, मैंने इसे "मनमानी एक्स" आवश्यकता पर ध्यान केंद्रित करते हुए लिखा है, लेकिन स्पष्ट रूप से सभी अपेक्षित मूल्यों को "निकटतम एक्स के एक एकल राउंड" समाधान द्वारा उत्पादित नहीं किया जा सकता है। ऐसा लगता है कि ओपी एक अक्ष के लिए मूल्यों का उत्पादन करना चाहता है, इसलिए prettyसंभवतः सबसे अच्छा विकल्प है।
जेम्स

1
स्पष्ट रूप से इस पार्टी में देर हो गई, लेकिन to * ceiling(x / to)क्लीनर नहीं होगा?
जारेड

25

यदि आप राउंड के तर्क-वितर्क () के लिए एक ऋणात्मक संख्या जोड़ते हैं, तो R इसे 10, 100 आदि के गुणकों पर गोल करेगा।

    round(9, digits = -1) 
    [1] 10    
    round(89, digits = -1) 
    [1] 90
    round(89, digits = -2) 
    [1] 100

17

किसी भी अंतराल के ऊपर / नीचे किसी भी संख्या को गोल करें

आप मॉडुलो ऑपरेटर का उपयोग करके आसानी से एक विशिष्ट अंतराल पर संख्याओं को गोल कर सकते हैं %%

कार्यक्रम:

round.choose <- function(x, roundTo, dir = 1) {
  if(dir == 1) {  ##ROUND UP
    x + (roundTo - x %% roundTo)
  } else {
    if(dir == 0) {  ##ROUND DOWN
      x - (x %% roundTo)
    }
  }
}

उदाहरण:

> round.choose(17,5,1)   #round 17 UP to the next 5th
[1] 20
> round.choose(17,5,0)   #round 17 DOWN to the next 5th
[1] 15
> round.choose(17,2,1)   #round 17 UP to the next even number
[1] 18
> round.choose(17,2,0)   #round 17 DOWN to the next even number
[1] 16

यह काम किस प्रकार करता है:

मॉडुलो ऑपरेटर %%2 द्वारा पहली संख्या को विभाजित करने के शेष को निर्धारित करता है। इस अंतराल को आपकी रुचि की संख्या में जोड़ना या घटाना अनिवार्य रूप से आपके चयन के अंतराल पर संख्या को 'गोल' कर सकता है।

> 7 + (5 - 7 %% 5)       #round UP to the nearest 5
[1] 10
> 7 + (10 - 7 %% 10)     #round UP to the nearest 10
[1] 10
> 7 + (2 - 7 %% 2)       #round UP to the nearest even number
[1] 8
> 7 + (100 - 7 %% 100)   #round UP to the nearest 100
[1] 100
> 7 + (4 - 7 %% 4)       #round UP to the nearest interval of 4
[1] 8
> 7 + (4.5 - 7 %% 4.5)   #round UP to the nearest interval of 4.5
[1] 9

> 7 - (7 %% 5)           #round DOWN to the nearest 5
[1] 5
> 7 - (7 %% 10)          #round DOWN to the nearest 10
[1] 0
> 7 - (7 %% 2)           #round DOWN to the nearest even number
[1] 6

अपडेट करें:

सुविधाजनक 2-तर्क संस्करण:

rounder <- function(x,y) {
  if(y >= 0) { x + (y - x %% y)}
  else { x - (x %% abs(y))}
}

सकारात्मक yमूल्य roundUp, जबकि नकारात्मक yमूल्य roundDown:

 # rounder(7, -4.5) = 4.5, while rounder(7, 4.5) = 9.

या फिर ....

मानक राउंडिंग नियमों के आधार पर स्वचालित रूप से UP या DOWN के लिए फ़ंक्शन

Round <- function(x,y) {
  if((y - x %% y) <= x %% y) { x + (y - x %% y)}
  else { x - (x %% y)}
}

यदि राउंडिंग मान के बाद के उदाहरणों के बीच xमान >आधा है , तो स्वचालित रूप से गोल हो जाता है y:

# Round(1.3,1) = 1 while Round(1.6,1) = 2
# Round(1.024,0.05) = 1 while Round(1.03,0.05) = 1.05

मुझे पूछा गया कि Roundएक्सेल में VBA में कैसे Function ROUND(x,y) 'Function that automatically rounds UP or DOWN based on standard rounding rules. 'Automatically rounds up if the "x" value is > halfway between subsequent instances of the rounding value "y": If (y - (Evaluate("Mod(" & x & "," & y & ")"))) <= (Evaluate("Mod(" & x & "," & y & ")")) Then Ans = x + (y - (Evaluate("Mod(" & x & "," & y & ")"))) Else Ans = x - (Evaluate("Mod(" & x & "," & y & ")")) End If ROUND = Ans End Function
बदला जाए

@ ऐब मुझे यकीन नहीं था कि आपके कहने के बाद मैंने 4 साल पोस्ट करने के बाद कभी मेरा जवाब दिया या नहीं, लेकिन मुझे लगता है कि आपको मेरा जवाब काफी सुरुचिपूर्ण और बहुत ही शानदार लग सकता है। आशा करता हूँ की ये काम करेगा!
theforestecologist

7

एक मनमाना संख्या , जैसे 10, की बहुलता तक गोलाई के बारे में , यहाँ जेम्स के उत्तर का एक सरल विकल्प है।

यह किसी भी वास्तविक संख्या को गोल करने के लिए काम करता है ( from) और किसी भी वास्तविक सकारात्मक संख्या के लिए ( to):

> RoundUp <- function(from,to) ceiling(from/to)*to

उदाहरण:

> RoundUp(-11,10)
[1] -10
> RoundUp(-0.1,10)
[1] 0
> RoundUp(0,10)
[1] 0
> RoundUp(8.9,10)
[1] 10
> RoundUp(135,10)
[1] 140

> RoundUp(from=c(1.3,2.4,5.6),to=1.1)  
[1] 2.2 3.3 6.6

2

मुझे लगता है कि आपका कोड बस एक छोटे से संशोधन के साथ महान काम करता है:

foo <- function(x, round=10) ceiling(max(x+10^-9)/round + 1/round)*round

और आपके उदाहरण चलते हैं:

> foo(4, round=1) == 5
[1] TRUE
> foo(6.1) == 10            #maybe 7 would be better
[1] TRUE
> foo(6.1, round=1) == 7    # you got 7
[1] TRUE
> foo(30.1) == 40
[1] TRUE
> foo(100.1) == 110
[1] TRUE
> # ALL in one:
> foo(c(4, 6.1, 30.1, 100))
[1] 110
> foo(c(4, 6.1, 30.1, 100), round=10)
[1] 110
> foo(c(4, 6.1, 30.1, 100), round=2.3)
[1] 101.2

मैंने आपके कार्य को दो तरह से बदल दिया:

  • दूसरा तर्क जोड़ा (आपके निर्दिष्ट X के लिए )
  • यदि आप एक बड़ी संख्या चाहते हैं =1e-09, max(x)तो एक छोटा मान ( , संशोधित करने के लिए स्वतंत्र महसूस करें) जोड़ा गया

1

यदि आप हमेशा किसी संख्या को निकटतम X तक चक्कर लगाना चाहते हैं , तो आप ceilingफ़ंक्शन का उपयोग कर सकते हैं :

#Round 354 up to the nearest 100:
> X=100
> ceiling(354/X)*X
[1] 400

#Round 47 up to the nearest 30:
> Y=30
> ceiling(47/Y)*Y
[1] 60

इसी तरह, यदि आप हमेशा राउंड डाउन करना चाहते हैं, तो floorफ़ंक्शन का उपयोग करें । यदि आप केवल निकटतम Z के लिए राउंड अप या डाउन करना चाहते हैं, तो roundइसके बजाय उपयोग करें ।

> Z=5
> round(367.8/Z)*Z
[1] 370
> round(367.2/Z)*Z
[1] 365

0

आपको टॉमी के उत्तर का उन्नत संस्करण मिलेगा जो कई मामलों को ध्यान में रखता है:

  • निम्न या उच्चतर सीमा के बीच चयन करना
  • नकारात्मक और शून्य मूल्यों को ध्यान में रखते हुए
  • दो अलग-अलग अच्छे पैमाने पर यदि आप चाहते हैं कि फ़ंक्शन अलग-अलग छोटे और बड़े संख्याओं में गोल हो। उदाहरण: 4 को 0 पर गोल किया जाएगा, जबकि 400 को 400 पर गोल किया जाएगा।

कोड के नीचे:

round.up.nice <- function(x, lower_bound = TRUE, nice_small=c(0,5,10), nice_big=c(1,2,3,4,5,6,7,8,9,10)) {
  if (abs(x) > 100) {
    nice = nice_big
  } else {
    nice = nice_small
  }
  if (lower_bound == TRUE) {
    if (x > 0) {
      return(10^floor(log10(x)) * nice[[max(which(x >= 10^floor(log10(x)) * nice))[[1]]]])
    } else if (x < 0) {
      return(- 10^floor(log10(-x)) * nice[[min(which(-x <= 10^floor(log10(-x)) * nice))[[1]]]])
    } else {
      return(0)
    }
  } else {
    if (x > 0) {
      return(10^floor(log10(x)) * nice[[min(which(x <= 10^floor(log10(x)) * nice))[[1]]]])
    } else if (x < 0) {
      return(- 10^floor(log10(-x)) * nice[[max(which(-x >= 10^floor(log10(-x)) * nice))[[1]]]])
    } else {
      return(0)
    }
  }
}

इसका डिफ़ॉल्ट आउटपुट एक राउंड डाउन है:> round.up.nice(.01) [1] 0 > round.up.nice(4.5) [1] 0 > round.up.nice(56) [1] 50
जेसी

मुझे लगता है कि समस्या का एक हिस्सा यह है nice_bigऔर nice_smallपीछे की ओर परिभाषित किया गया है, (यदि हम उन्हें फ़ंक्शन में फ्लिप करते हैं, तो round.up.nice(4.5)बन जाता है 4), लेकिन यह अभी भी गोल है।
जेस्सी

0

मैंने किसी भी बाहरी पुस्तकालय या गुप्त सुविधाओं का उपयोग किए बिना यह कोशिश की और यह काम करता है!

आशा है कि यह किसी की मदद करता है।

ceil <- function(val, multiple){
  div = val/multiple
  int_div = as.integer(div)
  return (int_div * multiple + ceiling(div - int_div) * multiple)
}

> ceil(2.1, 2.2)
[1] 2.2
> ceil(3, 2.2)
[1] 4.4
> ceil(5, 10)
[1] 10
> ceil(0, 10)
[1] 0
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.