Powiedzmy, że chcesz skalować zakres [min,max]
do [a,b]
. Szukasz (ciągłej) funkcji, która spełni Twoje oczekiwania
f(min) = a
f(max) = b
W twoim przypadku a
byłoby 1 i b
wynosiłoby 30, ale zacznijmy od czegoś prostszego i spróbuj zmapować [min,max]
do zakresu [0,1]
.
Włączenie min
funkcji i wyjście 0 można osiągnąć za pomocą
f(x) = x - min ===> f(min) = min - min = 0
Tak więc prawie tego chcemy. Ale wstawienie max
dałoby nam, max - min
kiedy naprawdę chcemy 1. Musimy to skalować:
x - min max - min
f(x) = --------- ===> f(min) = 0; f(max) = --------- = 1
max - min max - min
czego chcemy. Musimy więc wykonać tłumaczenie i skalowanie. Teraz, jeśli zamiast tego chcemy uzyskać dowolne wartości a
i b
, potrzebujemy czegoś nieco bardziej skomplikowanego:
(b-a)(x - min)
f(x) = -------------- + a
max - min
Możesz sprawdzić, czy wprowadzenie min
na x
teraz daje a
, a wprowadzenie max
daje b
.
Można również zauważyć, że (b-a)/(max-min)
jest to czynnik skalujący między rozmiarem nowego zakresu a rozmiarem pierwotnego zakresu. Tak naprawdę jesteśmy pierwszym tłumaczenia x
przez -min
skalowanie go do odpowiedniego czynnika, a następnie tłumaczenia to kopie zapasowe do nowej wartością minimalną a
.
Mam nadzieję że to pomoże.
max != min
przeciwnym razie wyniki funkcji nie zostaną określone :)min
jest negatywne imax
jest pozytywne, czy oba muszą być pozytywne?Oto kilka skryptów JavaScript ułatwiających kopiowanie i wklejanie (jest to irytująca odpowiedź):
Zastosowano w ten sposób, skalując zakres 10-50 do zakresu między 0-100.
Edytować:
Wiem, że odpowiedziałem na to dawno temu, ale oto czystsza funkcja, której teraz używam:
Zastosowano tak:
źródło
[1, 1, 1]
,[100, 100, 100]
albo nawet[50.5, 50.5, 50.5]
. Możesz włożyć do sprawy:if (max-min == 0) return this.map(num => (scaledMin+scaledMax)/2);
Dla wygody oto algorytm Irritate w formie Java. Dodaj sprawdzanie błędów, obsługę wyjątków i popraw w razie potrzeby.
Próbnik:
źródło
Oto jak to rozumiem:
Jaki procent
x
mieści się w zakresieZałóżmy, że masz zakres od
0
do100
. Biorąc pod uwagę dowolną liczbę z tego zakresu, w jakim „procencie” z tego zakresu się znajduje? To powinno być dość proste,0
byłoby0%
,50
byłoby50%
i100
będzie100%
.A co jeśli twój zasięg miałby to
20
zrobić100
? Nie możemy zastosować tej samej logiki jak powyżej (podzielić przez 100), ponieważ:nie daje nam
0
(20
powinno być0%
teraz). Powinno to być łatwe do naprawienia, wystarczy zrobić licznik0
dla przypadku20
. Możemy to zrobić, odejmując:Jednak to już nie działa,
100
ponieważ:nie daje nam
100%
. Ponownie możemy to naprawić, odejmując również od mianownika:Bardziej uogólnionym równaniem służącym do ustalenia, jaki%
x
mieści się w zakresie, byłoby:Skaluj zakres do innego zakresu
Teraz, gdy wiemy, jaki procent liczby mieści się w zakresie, możemy zastosować go, aby odwzorować liczbę na inny zakres. Przejdźmy przez przykład.
Gdybyśmy mieli liczbę ze starego zakresu, jaka byłaby liczba z nowego zakresu? Powiedzmy, że liczba jest
400
. Najpierw dowiedz się, jaki procent400
mieści się w starym zakresie. Możemy zastosować powyższe równanie.Tak więc
400
leży w25%
starym zakresie. Musimy tylko dowiedzieć się, jaka jest liczba25%
z nowego zakresu. Pomyśl o tym, co50%
o[0, 20]
to. Byłoby10
dobrze? Jak doszedłeś do tej odpowiedzi? Cóż, możemy po prostu zrobić:Ale co z
[10, 20]
? Musimy już wszystko zmienić10
. na przykład:bardziej ogólną formułą byłoby:
Do pierwotnego przykład tego, co
25%
z[10, 20]
to:Tak więc
400
w zakresie[200, 1000]
zostanie zmapowane do12.5
zakresu[10, 20]
TLDR
Aby zmapować
x
ze starego zakresu na nowy zakres:źródło
Natknąłem się na to rozwiązanie, ale tak naprawdę nie spełnia moich potrzeb. Więc trochę zagłębiłem się w kodzie źródłowym d3. Osobiście poleciłbym to zrobić tak, jak robi to d3.scale.
Tutaj skalujesz domenę do zakresu. Zaletą jest to, że możesz przerzucić znaki do swojego zakresu docelowego. Jest to przydatne, ponieważ oś y na ekranie komputera przesuwa się z góry na dół, więc duże wartości mają małe y.
A oto test, w którym możesz zobaczyć, co mam na myśli
źródło
Wziąłem odpowiedź Irritate i ponownie ją przeredagowałem, aby zminimalizować kroki obliczeniowe dla kolejnych obliczeń poprzez faktorowanie jej na najmniejszą stałą. Motywacją jest umożliwienie trenowania skalera na jednym zestawie danych, a następnie uruchomienie nowych danych (dla algo ML). W efekcie jest to bardzo podobne do użycia MinMaxScaler SciKit dla Pythona w użyciu.
Tak więc
x' = (b-a)(x-min)/(max-min) + a
(gdzie b! = A) staje się,x' = x(b-a)/(max-min) + min(-b+a)/(max-min) + a
co można zredukować do postaci dwóch stałychx' = x*Part1 + Part2
.Oto implementacja C # z dwoma konstruktorami: jednym do trenowania, a drugim do przeładowywania przeszkolonej instancji (np. W celu wspierania trwałości).
źródło
Na podstawie odpowiedzi Charlesa Claytona dołączyłem niektóre poprawki JSDoc, ES6 i włączyłem sugestie z komentarzy w pierwotnej odpowiedzi.
źródło