2016-12-19 1 views
3

오히려 하나는 갖고 있지 않지만 매우 흥미로운 문제가 있습니다. 나는 내가, here 그것은 확인을 작동하는 데 사용되는 솔루션을 다음 그래서 여러 종료에 숫자를 반올림 할 필요가 나는 data.frame으로, 심지어을 공정하게 data.table다중으로 반올림하여 data.table의 필터

library(data.table) 
options(digits = 20) # to see number representation 
mround <- function (number, multiple) { 
    return(multiple * round(number/multiple)) 
} 
DT = data.table(a = mround(112.3, 0.1), b = "B") 
DT[a == 112.3,] # works as expected, i.e returns one row 
DT[a == 112.3 & b == 'B', ] # doesn't work 

와 버그를 발견 할 때까지 첫 번째 필터가 작동하지 않습니다. 어떤 생각을 고치는 방법?

+0

당신을 사용 할 수 있습니다 문제가 명확하게 정의되어 있지 않습니다. 출력물을 기대하는 것을 추가해야합니다. 두 줄 모두 나를 위해 빈 데이터를 반환합니다. – lmo

+0

첫 번째 문장은'data.table'에서 제게 적합하지 않으며'data.table' 또는'data.frame'과 관련이 없지만 [부동 소수점 정밀도] (https : // cran. r-project.org/doc/FAQ/R-FAQ.html#Why-doesn_0027t-R-think-these-numbers-are-equal_003f). 'DT [(a - 112.3) <1]을 보라.위의 링크를 보거나'.Machine $ double.eps^0.5'를'all.equal'과 같이 사용하려면 오차 범위 0.000001을 사용하십시오. – Tensibai

+0

FWIW, round는'digits' 매개 변수를 취하고 round (112.3,1)로 충분해야하며 실제 문제는 피해야합니다.) – Tensibai

답변

3

floating point precision의 문제입니다. DT[abs(a - 112.3)<1.e-6 & b == 'B',]을 참조하십시오. 오차 범위 0.000001을 사용하면 올바른 결과를 얻을 수 있습니다.

정확도를 높이려면 .Machine$double.eps^0.5all.equal과 같이 사용할 수 있습니다.

일반 정보는 0과 1) 자세한 내용 사이의 정밀 드리프트를 해결하기 위해 해결하기 위해 here

한 가지 방법을 수레의 평등을 비교할 수 없지만 기계 정밀도에 충분히 가까운 값의 차이를 비교 결코하는 것입니다 당신은 예를 들어 여기에 2를 사용 할 수 있습니다 (귀하의 요구에 적응,

mround <- function (number, multiple, digits=nchar(strsplit(as.character(multiple),".",fixed=TRUE)[[1]][2])) { 

    round(multiple * round(number/multiple),digits) 
} 

내가 기본 유효 숫자로 전달 된 여러에서 필요한 숫자를 얻기 위해 "복잡한"방법을 사용 : 문제에 함수를 리팩토링 할 수 또는 호출 할 때 정밀도를 강제).
불필요한 return을 제거하여 인터프리터가 함수 호출의 끝에서 이미 호출 된 함수를 찾도록했습니다.

당신의 출력이 충분히 정확해야한다 이런 식으로,하지만 당신은 여전히 ​​코너 케이스해야합니다 :

> mround(112.37,0.2) 
[1] 112.40000000000001 

당신이 (데이비드 Arenburg의 제공) 사용할 수 있습니다, 조인에서 수레를 사용하려면 :

setNumericRounding(1) 
DT[.(112.3, 'B'), nomatch = 0L, on = .(a, b)] 
+0

에 동의 할 수있는 함수가 필요하기 때문에 동의하지만,이 열을 조인에 사용하고 싶습니다. 합류하기 위해 아무 것도 사용하지 않는다고 상상할 수 없습니다. – kismsu

+0

@kismsu 나는 당신이 의미하는 것을 얻지 못한다. .. 어떻게 그것이 문제가 되느냐? (다른 질문 소리) – Tensibai

+0

@kismsu 나는 DT1 [DT2, on =. ((xa-ia <.Machine $ double.eps^0.5)]'해야합니까 (시험 안 함) – Tensibai

4

그냥 @Tens의 멋진 답변에 추가하십시오. 일어나고있는 것 같다 무엇

당신은 당신이 사용하고 오래된 data.table 버전있다
  • (이미 언급 한 바와 같이) 부동 소수점 문제가
  • 차 지수는 동안 발로하는 세 가지
    • 있습니다 당신은 당신의 설정을 사용하여

    인식하지

    library(data.table) 
    options(digits = 20) # to see number representation 
    
    mround <- function (number, multiple) { 
        return(multiple * round(number/multiple)) 
    } 
    
    DT = data.table(a = mround(112.3, 0.1), b = "B") 
    

    따라서 주소에 위의 사항을 적용하십시오. 당신은 부동 소수점 및 인용을 가지고 있기 때문에 ?setNumericRounding

    가입 또는 '숫자'형식의 열을 그룹화 할 때 (예 : 0.6) 정확하게,베이스 (2)를 사용하여이 예기치 않은 동작에 이르게 일부 부동 소수점 숫자를 표현 할 수

    컴퓨터; 즉'

    더블이 자동 예상대로 그래서 기수 알고리즘이 작동 할 수레를 둥글게 setNumericRounding을 구현하기 위해 data.table DEVS를했다.

    이전 v1.9.8에, setNumericRounding(2)는 기본 (따라서 첫 번째 예 작동),하지만 기본이를 위해 setNumericRounding(0) 다시 설정 v1.9.8 이후 GH (IIRC)에 불일치에 대한 사용자의 불평, 후 data.frame 동작과 일치해야합니다 (here 참조). 따라서 data.table을 최신 버전으로 업데이트하면 data.tabledata.frame이 두 예제 모두에서 동일하게 작동하며 두 예제 모두 실패합니다.

    그래서 당신이 "도대체 기수 알고리즘은 여기 무엇이든 함께 할 수있다"물어볼 것입니다

    setNumericRounding(1) 
    DT[a == 112.3] 
    #      a b 
    # 1: 112.30000000000001 B 
    

    setNumericRounding(0) 
    DT[a == 112.3] 
    ## Empty data.table (0 rows) of 2 cols: a,b 
    

    비교. 여기서 우리는 위의 세 번째 요점 인 보조 색인 (this을 읽어주세요)에 도달했습니다. 실제로 당신이

    options(datatable.verbose = TRUE) 
    DT[a == 112.3] # works as expected, i.e returns one row 
    # Creating new index 'a' <~~~~ 
    # forder took 0 sec 
    # Starting bmerge ...done in 0 secs 
    #      a b 
    # 1: 112.30000000000001 B 
    

    위에 당신이 코드를 실행하면 어떻게되는지 볼 수 있습니다 것은 순서 보조 지표로 확인 새로운 보조 인덱스는 ==를 실행 한

    indices(DT) 
    #[1] "a" 
    

    에게, data.table 세트 a을 수 있습니다 (v1.9.4에서 소개되었으므로, here 참조). 즉, 이전 v1.9.4처럼 일반적인 벡터 스캔 대신 a에서 바이너리 조인을 수행했습니다 (보조 노트로 options(datatable.auto.index = FALSE)을 사용하여이 기능을 비활성화 할 수 있습니다.이 경우 아무런 예제도 setNumericRounding(1)과 함께 작동하지 않습니다) 명시 적 setkey 또는 on 인수를 사용하여 키)

    를 지정하지 않는 한

    DT[a == 112.30000 & b == 'B'] 
    

    작동하지 않는 이유도 설명 할 것이다 아마. 여기서 두 번째 열로 하위 설정하고 보조 색인이나 이진 조인은 == & == (아직)과 같은 표현식에 대해 자동으로 시작되지 않으므로 일반 벡터 스캔을 수행하고 setNumericRounding(1)

    으로 시작하지 않았습니다.

    비록 수동으로 키를 설정하고 (나는 @Tens 응답에서 주석처럼)은 예를 들어, 작동하게, 당신은

    setNumericRounding(1) # make sure autoroundings turned on 
    DT[.(112.3, 'B'), nomatch = 0L, on = .(a, b)] 
    # Calculated ad hoc index in 0 secs 
    # Starting bmerge ...done in 0 secs 
    #  a b 
    # 1: 112.3 B 
    

    을 수행 할 수 있습니다 또는 옛날 방식

    setkey(DT, a, b) 
    DT[.(112.3, 'B'), nomatch = 0L] 
    # Starting bmerge ...done in 0 secs 
    #  a b 
    # 1: 112.3 B 
    
  • +0

    요약 해 주셔서 감사합니다. 실제로 임시 색인에 대해 언급하지는 않았지만이 기능을 잊어 버렸습니다. – kismsu