Avatar billede encorez Juniormester
08. november 2018 - 22:32 Der er 6 kommentarer

Average af datapunkter inden for en tidsramme

Hej

Jeg har et datasæt med bl.a. timestamp (dato - tid) og en værdi.

Jeg har brug for en funktion hvor jeg løber datasættet igennem og for hvert eneste punkt skal udregnes gennemsnitsværdien af datapunkter for de seneste 2 timer for eksempel. Tidsrammen skal være variabel.

Mine datapunkter kommer ikke nødvendigvis med samme interval, og derfor bliver det lidt kringlet.

Er der nogen der har godt forslag til at løse den opgave bedst mulig?

Og da jeg ikke er java-haj, så vil et kode-eksempel eller semi-kode være meget behjælpelig.

Tusind tak på forhånd
Avatar billede arne_v Ekspert
08. november 2018 - 23:20 #1
Til inspiration:


import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.function.BiConsumer;

public class DataAnalysis {
    public static class DataPoint {
        private Timestamp timestamp;
        private double value;
        public DataPoint(Timestamp timestamp, double value) {
            this.timestamp = timestamp;
            this.value = value;
        }
        public DataPoint(long epochtime, double value) {
            this(new Timestamp(epochtime), value);
        }
        public Timestamp getTimestamp() {
            return timestamp;
        }
        public double getValue() {
            return value;
        }
    }
    public static class DataSet {
        private List<DataPoint> datapoints = new ArrayList<>();
        public void add(DataPoint dp) {
            datapoints.add(dp);
        }
        public int size() {
            return datapoints.size();
        }
        public DataPoint get(int ix) {
            return datapoints.get(ix);
        }
    }
    public static class DataAnalyzer {
        private DataSet dataset;
        private int interval;
        public DataAnalyzer(DataSet dataset, int interval) {
            this.dataset = dataset;
            this.interval = interval;
        }
        public void process(BiConsumer<DataPoint, Double> f) {
            int ix0 = 0;
            for(int ix = 0; ix < dataset.size(); ix++) {
                while(dataset.get(ix0).getTimestamp().getTime() < dataset.get(ix).getTimestamp().getTime() - interval) ix0++;
                double avg = 0;
                for(int i = ix0; i <= ix; i++) {
                    avg += dataset.get(i).getValue();
                }
                avg /= (ix - ix0 + 1);
                f.accept(dataset.get(ix), avg);
            }
        }
       
    }
    public static void main(String[] args) {
        long now = (new Date()).getTime();
        DataSet ds = new DataSet();
        ds.add(new DataPoint(now - 5000, 1.0));
        ds.add(new DataPoint(now - 3000, 4.0));
        ds.add(new DataPoint(now - 2000, 9.0));
        ds.add(new DataPoint(now - 1000, 16.0));
        ds.add(new DataPoint(now -    0, 25.0));
        DataAnalyzer da = new DataAnalyzer(ds, 1500);
        da.process((dp,avg) -> System.out.println(dp.getValue() + " " + avg));
    }
}
Avatar billede encorez Juniormester
10. november 2018 - 18:55 #2
Hej

Tusind tak for det her eksempel :)

Jeg har siddet og kigget på det flere gange for at forstå hvad der sker visse steder for det er lidt komplekst et par steder :)

Jeg går ud fra at tidspunktet skal være et timestamp, så jeg skal konvertere min datetime (YYYY-MM-DD HH:MM:SS) til et timestamp ikke sandt?

Når du i eksemplet angiver "1500", så er det i sekunder ikke sandt?

Men der er en ekstra vigtig ting jeg glemte i første omgang, beklager. Mit datasæt går fra mandag kl 8.00 -> fredag kl 16.00, en arbejdsuge kan man sige.
Men når jeg regner mit gennemsnit ud, så skal weekend-tidsrummet ikke regnes med som "tid". Funktionen skal altså tro at mandag kl 8, kommer LIGE efter fredag kl 16.
F.eks. mandag kl 9, skal jeg bruge gennemsittet for de sidste 4 timers datapunkter, så skal den medtage datapunkter fra fredag 13 -> mandag kl 9; altså fredag 13-16 og mandag 8-9 = 4 timer i alt.

Jeg ved det er kringlet. Er det for komplekst at indbygge?
Avatar billede arne_v Ekspert
10. november 2018 - 19:03 #3
De 1000, 1500, 2000 etc. er millisekunder.

java.sql.DateTime er lige saa god som java.sql.Timestamp.
Avatar billede arne_v Ekspert
10. november 2018 - 19:03 #4
mandag fredag reglen er mere tricky, men alt kan jo kodes med lidt omhu.
Avatar billede arne_v Ekspert
15. november 2018 - 04:11 #5
Der er ikke nogen java.sql.DateTime - database DATETIME mappes til java.sql.Timestamp, saa den del er OK.
Avatar billede arne_v Ekspert
15. november 2018 - 04:16 #6
Det andet problem maa skulle loeses ved at aendre:

while(dataset.get(ix0).getTimestamp().getTime() < dataset.get(ix).getTimestamp().getTime() - interval) ix0++;

til:

while(dataset.get(ix0).getTimestamp().getTime() < dataset.get(ix).getTimestamp().getTime() - interval - extra(dataset.get(ix), interval)) ix0++;

hvor extra returnerer antal millisekunder der skal skippes.

0 normalt
64*60*60*1000 for weekend
63*60*60*1000 og 65*60*60*1000 for weekender hvor der aendres til/fra sommertid
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester