Длинный ответ, TLDR жирным шрифтом
Вы можете просто скомпилировать и запустить оба, вместо того, чтобы пытаться теоретизировать и отгадывать, что делает код. Если есть сомнения, просто запустите его. Немного потрудившись, вы можете получить NumericHistogram.java
, который вы связали для компиляции без maven и просто с помощью вызова CLI javac
(просто удалите ссылки на hive
пакеты и связанные методы).
Я просто протестировал оба на массиве [0,1,...,98,99]
.
Java-версия (Java 10.0.2):
РЕДАКТИРОВАТЬ: Получил отзыв (по электронной почте), чтобы включить код Java. Вот оно (удалены строки документации и некоторые комментарии, а не все общедоступные методы):
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import java.util.Random;
public class NumericHistogram {
static class Coord implements Comparable {
double x;
double y;
public int compareTo(Object other) {
return Double.compare(x, ((Coord) other).x);
}
};
// Class variables
private int nbins;
private int nusedbins;
private ArrayList<Coord> bins;
private Random prng;
public NumericHistogram() {
nbins = 0;
nusedbins = 0;
bins = null;
// init the RNG for breaking ties in histogram merging. A fixed seed is specified here
// to aid testing, but can be eliminated to use a time-based seed (which would
// make the algorithm non-deterministic).
prng = new Random(31183);
}
public void reset() {
bins = null;
nbins = nusedbins = 0;
}
public int getUsedBins() {
return nusedbins;
}
public boolean isReady() {
return nbins != 0;
}
public Coord getBin(int b) {
return bins.get(b);
}
public void allocate(int num_bins) {
nbins = num_bins;
bins = new ArrayList<Coord>();
nusedbins = 0;
}
public void add(double v) {
int bin = 0;
for(int l=0, r=nusedbins; l < r; ) {
bin = (l+r)/2;
if (bins.get(bin).x > v) {
r = bin;
} else {
if (bins.get(bin).x < v) {
l = ++bin;
} else {
break; // break loop on equal comparator
}
}
}
if (bin < nusedbins && bins.get(bin).x == v) {
bins.get(bin).y++;
} else {
Coord newBin = new Coord();
newBin.x = v;
newBin.y = 1;
bins.add(bin, newBin);
// Trim the bins down to the correct number of bins.
if (++nusedbins > nbins) {
trim();
}
}
}
private void trim() {
while(nusedbins > nbins) {
// Find the closest pair of bins in terms of x coordinates. Break ties randomly.
double smallestdiff = bins.get(1).x - bins.get(0).x;
int smallestdiffloc = 0, smallestdiffcount = 1;
for(int i = 1; i < nusedbins-1; i++) {
double diff = bins.get(i+1).x - bins.get(i).x;
if(diff < smallestdiff) {
smallestdiff = diff;
smallestdiffloc = i;
smallestdiffcount = 1;
} else {
if(diff == smallestdiff && prng.nextDouble() <= (1.0/++smallestdiffcount) ) {
smallestdiffloc = i;
}
}
}
double d = bins.get(smallestdiffloc).y + bins.get(smallestdiffloc+1).y;
Coord smallestdiffbin = bins.get(smallestdiffloc);
smallestdiffbin.x *= smallestdiffbin.y / d;
smallestdiffbin.x += bins.get(smallestdiffloc+1).x / d * bins.get(smallestdiffloc+1).y;
smallestdiffbin.y = d;
// Shift the remaining bins left one position
bins.remove(smallestdiffloc+1);
nusedbins--;
}
}
public int getNumBins() {
return bins == null ? 0 : bins.size();
}
}
Я вставил это главное в класс NumericHistogram
(см. Выше):
public static void main(String[] args) {
NumericHistogram hist = new NumericHistogram();
hist.allocate(10);
for (int i = 0; i < 100; i++) {
hist.add(i);
}
ArrayList<Coord> bins = new ArrayList<Coord>();
for (int i = 0; i < 10; i++) {
bins.add(hist.getBin(i));
}
int index = 0;
for (Coord bin : bins) {
System.out.println(index + "th bin x: " + bin.x);
System.out.println(index + "th bin y: " + bin.y);
index++;
}
}
Этот вывод:
Matthews-MacBook-Pro:stackoverflow matt$ java NumericHistogram
0th bin x: 2.0
0th bin y: 5.0
1th bin x: 9.5
1th bin y: 10.0
2th bin x: 21.5
2th bin y: 14.0
3th bin x: 33.0
3th bin y: 9.0
4th bin x: 44.0
4th bin y: 13.0
5th bin x: 55.0
5th bin y: 9.0
6th bin x: 64.5
6th bin y: 10.0
7th bin x: 75.5
7th bin y: 12.0
8th bin x: 88.0
8th bin y: 13.0
9th bin x: 97.0
9th bin y: 5.0
Python версия:
Версия numpy
была немного другой. Вот сценарий:
import numpy as np
hist = np.histogram(np.arange(100)) # 10 is the default for num bins
print(hist)
Этот вывод:
(array([10, 10, 10, 10, 10, 10, 10, 10, 10, 10]), array([ 0. , 9.9, 19.8, 29.7, 39.6, 49.5, 59.4, 69.3, 79.2, 89.1, 99. ]))
Чтобы сравнить с java-версией, нам действительно нужно сжать их, что вы можете сделать так:
y_values, x_values = hist
i = 0
for x_val, y_val in zip(x_values, y_values):
print(str(i) + "th bin x: " + str(x_val))
print(str(i) + "th bin y: " + str(y_val))
i += 1
и вывод:
0th bin x: 0.0
0th bin y: 10
1th bin x: 9.9
1th bin y: 10
2th bin x: 19.8
2th bin y: 10
3th bin x: 29.700000000000003
3th bin y: 10
4th bin x: 39.6
4th bin y: 10
5th bin x: 49.5
5th bin y: 10
6th bin x: 59.400000000000006
6th bin y: 10
7th bin x: 69.3
7th bin y: 10
8th bin x: 79.2
8th bin y: 10
9th bin x: 89.10000000000001
9th bin y: 10
Сводка и приведение их в соответствие:
Они эквивалентны? Нет, они не эквивалентны. Они используют разные схемы разбиения для присвоения значений корзинам. Версия Java помещает элемент в «ближайший» контейнер с использованием правил округления, тогда как numpy
выполняет группировку диапазонов (т. Е. 0-9.9, 9.9-19.8, ..., 89.1-100). Кроме того, сгенерированные по умолчанию корзины также не одинаковы, что имеет смысл, поскольку схемы очень разные.
Могу ли я заставить их совпадать? Да, но вам нужно выяснить, как генерировать случайные числа точно , как Java в области Python, если вы хотите общую реализацию. . Я попытался скопировать реализацию и заставил ее работать, но я не могу получить случайные числа одинаковыми. Даже если вы используете numpy
вместо копирования логики в Python, вам все равно нужно будет генерировать случайные числа Java, чтобы они соответствовали в общем случае. Этот проект показался актуальным, но это только Java 6 RNG, а не более поздние версии Java: https://github.com/MostAwesomeDude/java-random. С риском сделать этот гигантский ответ еще дольше, вот код Python для копирования реализации Java:
""" Just a mindless copy for easy verification. Not good style or performant. """
import random
class Coord:
def __init__(self, x, y):
self.x = float(x)
self.y = float(y)
def __repr__(self): # debug
return "Coord(" + str(self.x) + ", " + str(self.y) + ")"
def __str__(self): # debug
return "Coord(" + str(self.x) + ", " + str(self.y) + ")"
class Random:
""" This class needs fixin. You'll have to do some work here to make it match your version of Java. """
def __init__(self, seed):
random.seed(seed)
def nextDouble(self):
return random.uniform(0, 1)
class NumericHistogram:
def __init__(self):
self.nbins = 0
self.nusedbins = 0
self.bins = None
self.prng = Random(31183) # This should behave the same as Java's RNG for your Java version.
def allocate(self, num_bins):
self.nbins = num_bins
self.bins = []
self.nusedbins = 0
def add(self, v):
bin = 0
l = 0
r = self.nusedbins
while(l < r):
bin = (l+r)//2
if self.bins[bin].x > v:
r = bin
else:
if self.bins[bin].x < v:
l = bin + 1; bin += 1
else:
break
if bin < self.nusedbins and self.bins[bin].x == v:
self.bins[bin].y += 1
else:
newBin = Coord(x=v, y=1)
if bin == len(self.bins):
self.bins.append(newBin)
else:
self.bins[bin] == newBin
self.nusedbins += 1
if (self.nusedbins > self.nbins):
self.trim()
def trim(self):
while self.nusedbins > self.nbins:
smallestdiff = self.bins[1].x - self.bins[0].x
smallestdiffloc = 0
smallestdiffcount = 1
for i in range(1, self.nusedbins-1):
diff = self.bins[i+1].x - self.bins[i].x
if diff < smallestdiff:
smallestdiff = diff
smallestdiffloc = i
smallestdiffcount = 1
else:
smallestdiffcount += 1
if diff == smallestdiff and self.prng.nextDouble() <= (1.0/smallestdiffcount):
smallestdiffloc = i
d = self.bins[smallestdiffloc].y + self.bins[smallestdiffloc+1].y
smallestdiffbin = self.bins[smallestdiffloc]
smallestdiffbin.x *= smallestdiffbin.y / d
smallestdiffbin.x += self.bins[smallestdiffloc+1].x / d * self.bins[smallestdiffloc+1].y
smallestdiffbin.y = d
self.bins.pop(smallestdiffloc+1)
self.nusedbins -= 1
И "главное":
hist = NumericHistogram()
hist.allocate(10)
for i in range(100):
hist.add(i)
for ind, bin in enumerate(hist.bins):
print(str(ind) + "th bin x: " + str(bin.x))
print(str(ind) + "th bin y: " + str(bin.y))
это выводит:
0th bin x: 4.0
0th bin y: 9.0
1th bin x: 13.0
1th bin y: 9.0
2th bin x: 24.0
2th bin y: 13.0
3th bin x: 35.0
3th bin y: 9.0
4th bin x: 46.5
4th bin y: 14.0
5th bin x: 57.5
5th bin y: 8.0
6th bin x: 66.0
6th bin y: 9.0
7th bin x: 76.49999999999999
7th bin y: 12.0
8th bin x: 88.99999999999999
8th bin y: 13.0
9th bin x: 97.5
9th bin y: 4.0
Так что вроде как близко, но без бананов. Разница заключается в RNG (насколько я могу судить). Я не очень много знаю о Java Random
или RNG в целом: так что, возможно, было бы лучше просто опубликовать другой вопрос здесь на SO о том, как генерировать случайные числа точно как Java [insert-your-java-version-here].
HTH и поможет вам начать в правильном направлении.