CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - Wczytanie danych według zadanej kompresji czasu
Strona 1 z 2

Wczytanie danych według zadanej kompresji czasu

Nowy postNapisane: środa, 30 stycznia 2013, 19:51
przez Corvis
Witam,

Mam dane w takim formacie:

    2012.11.28 16:51:33 129135

Poszukuję sposobu wczytanie danych do programu według zadanej kompresji czasu ( 1sekunda lub 1 minuta lub 5 minut lub 1 godzina itp )

Tutaj przykład na kompresję jedno sekundową: (dane pochodza z excela jest to zwykła csv ze średnikiem jako separatorem)

Dane przed kompresją

    2012.11.28 16:51:33 129135
    2012.11.28 16:51:35 129134
    2012.11.28 16:51:35 129132
    2012.11.28 16:51:35 129132
    2012.11.28 16:51:37 129133
    2012.11.28 16:51:37 129139
    2012.11.28 16:51:37 129143
    2012.11.28 16:51:38 129138
    2012.11.28 16:51:38 129134
    2012.11.28 16:51:38 129132
    2012.11.28 16:51:38 129131
    2012.11.28 16:51:38 129129
    2012.11.28 16:51:39 129125
    2012.11.28 16:51:39 129124
    2012.11.28 16:51:39 129122
    2012.11.28 16:51:40 129123
    2012.11.28 16:51:40 129121
    2012.11.28 16:51:41 129122
    2012.11.28 16:51:41 129121
    2012.11.28 16:51:41 129122

Dane po kompresji

    2012.11.28 16:51:33 129135
    2012.11.28 16:51:35 129132
    2012.11.28 16:51:37 129143
    2012.11.28 16:51:38 129129
    2012.11.28 16:51:39 129122
    2012.11.28 16:51:40 129121
    2012.11.28 16:51:41 129122

Ma ktoś na to jakiś ciekawy pomysł ???

Przykładowy plik z danymi w załączniku.

Z góry dzięki za jakieś sugestie.

pzdr,

Re: Wczytanie danych według zadanej kompresji czasu

Nowy postNapisane: środa, 30 stycznia 2013, 19:56
przez Cyfrowy Baron
Chyba nie zrozumiałem :roll:
Czy chcesz wczytać dane z pliku tak, żeby pominąć powtarzające się wiersze?

Żeby pobrać ten Twój plik, to trzeba się zalogować na google, a jak ktoś nie ma konta, to musi je założyć. Po jaką cholerę tak to skomplikowałeś skoro można zamieścić plik na forum uprzednio spakowawszy go do np. ZIP?!

Re: Wczytanie danych według zadanej kompresji czasu

Nowy postNapisane: środa, 30 stycznia 2013, 20:13
przez Corvis
Bo wpierw pisało na forum, że można 20 mb, potem, że 2 mb a potem, że 256 kb to się wkurzyłem i wrzuciłem na google, ale już poprawiłem.

Chce wyeliminować dane które powtarzają się w wybranej jednostce kompresji - w przykładzie jest to 1 sekunda. Zostają ostatnie wartości w każdej sekundzie danych.

Re: Wczytanie danych według zadanej kompresji czasu

Nowy postNapisane: środa, 30 stycznia 2013, 20:51
przez Corvis
KOD cpp:     UKRYJ  
void __fastcall TForm1::Button1Click(TObject *Sender)
{
        this->Memo1->Clear();
        this->Memo2->Clear();

        TStringList *lst = new TStringList();
        lst->LoadFromFile("Kompresja2.csv");
        Memo1->Lines->Assign(lst);
        Application->ProcessMessages();

        unsigned short H  = 0;
        unsigned short M  = 0;
        unsigned short S  = 0;
        unsigned short MS = 0;

        int LastM = -1;

        TDateTime poprzedniaData;
        TDateTime biezacaData;

        int jednostkaCzasuKompresji             = 0;
        int Odniesienie                         = 0;
        int RodzajKompresji                     = 1; // 0 - Minutowa, 1 - Godzinowa, 2 - Sekundowa
        int CHECK                               = 0;
        int poprzedniaJednostkaCzasuKompresji = 0;

        LockWindowUpdate(Memo2->Handle);

        for(int i = 0; i < lst->Count; ++i) {

                poprzedniaData  = biezacaData;
                biezacaData             = StrToDateTimeDef(lst->Strings[i],biezacaData); // Bieżący rekord
                DecodeTime(biezacaData,H,M,S,MS);

                if(RodzajKompresji == 1) {
                        jednostkaCzasuKompresji = H;
                } else if(RodzajKompresji == 0) {
                        jednostkaCzasuKompresji = M;
                } else if(RodzajKompresji == 2) {
                        jednostkaCzasuKompresji = S;
                }

                if(i == 0) {
                        poprzedniaData  = biezacaData;
                        Odniesienie     = jednostkaCzasuKompresji;
                }

                if(RodzajKompresji == 1) {
                        if(jednostkaCzasuKompresji==0) {
                                jednostkaCzasuKompresji = 24;
                        }
                }

                CHECK = Odniesienie - jednostkaCzasuKompresji;

                if(CHECK < 0) {
                        CHECK = -CHECK;
                }

                if(CHECK >= 1 && poprzedniaData.DateString() != "1899-12-30") {
                        Odniesienie = jednostkaCzasuKompresji;
                        Memo2->Lines->Add(poprzedniaData.DateTimeString() + " "  + String(i));
                }
        }

        LockWindowUpdate(0);

        this->Caption = String(Memo1->Lines->Count) + " " + String(Memo2->Lines->Count);

        delete lst;
}
 


Takie coś wymyśliłem na szybko - dane testowe to 1 kulumna samych dat ( DateTime)

Ma ktoś może lepszy pomysł ??

Problem będę miał też jak będę miał ustawioną kompresję danych a dane zaczną napływać ONLINE ...

Re: Wczytanie danych według zadanej kompresji czasu

Nowy postNapisane: środa, 30 stycznia 2013, 22:34
przez Darek_C++
Możesz wczytać dane do pamięciowej bazy danych SQLite :memory: do kolumny http://www.sqlite.org/datatype3.html obsługującej Date and Time Datatype Następnie odpowiednimi zapytaniami SQL związanymi z czasem je grupować wybierać od - do... itd... Operacje na pamięciowej bazie danych są bardzo szybkie, wiec śmiało możesz je wykonywać w czasie rzeczywistym w miarę napływania danych. http://www.sqlite.org/lang_datefunc.html

SQLite w C++ obsługuje się w miarę przyjemnie.



PS NIe mam pojęcia co rozumiesz pod pojęciem kompresja - chodzi Ci o interwał czasu ?

Re: Wczytanie danych według zadanej kompresji czasu

Nowy postNapisane: środa, 30 stycznia 2013, 22:47
przez Cyfrowy Baron
Corvis napisał(a):Takie coś wymyśliłem na szybko - dane testowe to 1 kulumna samych dat ( DateTime)


Zastanawiam się po co tak kombinujesz, przecież nie ma potrzeby dzielenia tych linii na jednostki czasu, skoro usuwasz powtarzające się linie. Wystarczy potraktować każą linię jak tekst, posortować i usunąć powtarzające się elementy.

Re: Wczytanie danych według zadanej kompresji czasu

Nowy postNapisane: środa, 30 stycznia 2013, 22:52
przez Corvis
    2012.11.28 16:51:38 129138
    2012.11.28 16:51:38 129134
    2012.11.28 16:51:38 129132
    2012.11.28 16:51:38 129131
    2012.11.28 16:51:38 129129

a gdzie tu powtarzające się dane ? ;) W jednej sekundzie przyszło aż 5 różnych wartości ja muszę wybrać ostatnią.

Re: Wczytanie danych według zadanej kompresji czasu

Nowy postNapisane: środa, 30 stycznia 2013, 23:48
przez Darek_C++
Wiec jak już pisałem bez problemu osiągniesz to ładując dane do pamięciowej bazy z jedną tabelą o dwóch kolumnach + odpowiednie zapytanie SQL z Group By i Order BY.

Re: Wczytanie danych według zadanej kompresji czasu

Nowy postNapisane: czwartek, 31 stycznia 2013, 05:56
przez Cyfrowy Baron
Corvis napisał(a):a gdzie tu powtarzające się dane ?


Zmianie ulega tylko końcówka, czyli 6 ostatnich znaków. Czyli wystarczy porównywać pierwszy człon a z listy wybrać ostatni. Wciąż nie widzę potrzeby rozbijania tego na jednostki czasu, skoro jedynym kryterium decydującym o wybraniu elementu z listy jest kolejność, czyli ostatnia powtarzająca się wartość.

Re: Wczytanie danych według zadanej kompresji czasu

Nowy postNapisane: czwartek, 31 stycznia 2013, 07:38
przez Corvis
Darek_C++ napisał(a):Wiec jak już pisałem bez problemu osiągniesz to ładując dane do pamięciowej bazy z jedną tabelą o dwóch kolumnach + odpowiednie zapytanie SQL z Group By i Order BY.


Nie ma takiej opcji bo ten program działa też ONLINE. Baza mi tu nie potrzebna, można to zrobić prościej. Jak sobie wyobrażasz wczytanie pliku z 5 lat z 6 milionami wierszy ?? Wpierw do bazy potem SQL-em filtracja i potem do bufora do programu ??

Cyfrowy Baron napisał(a):Zmianie ulega tylko końcówka, czyli 6 ostatnich znaków. Czyli wystarczy porównywać pierwszy człon a z listy wybrać ostatni. Wciąż nie widzę potrzeby rozbijania tego na jednostki czasu, skoro jedynym kryterium decydującym o wybraniu elementu z listy jest kolejność, czyli ostatnia powtarzająca się wartość.


A jak to zadziała jak chce dane kompresować nie po 1 sek tylko po 1 godzinie ? musisz się odnieść do czegoś ( dlatego ta jednostka czasu ) - kolejność danych też ma znaczenie nie mogę ich sobie sortować dowolnie.

Re: Wczytanie danych według zadanej kompresji czasu

Nowy postNapisane: czwartek, 31 stycznia 2013, 09:46
przez Darek_C++
Corvis napisał(a):Nie ma takiej opcji bo ten program działa też ONLINE. Baza mi tu nie potrzebna, można to zrobić prościej.
To nie ma znaczenia jak działa.
Corvis napisał(a):Jak sobie wyobrażasz wczytanie pliku z 5 lat z 6 milionami wierszy ?? Wpierw do bazy potem SQL-em filtracja i potem do bufora do programu ??
Tak samo jak z wczytaniem 1000 wierszy. Poza tym nie jest to typowa baza "zapisywana" tylko baza obsługiwana w pamięci RAM- baza jest tylko z nazwy, a to jest wielka różnica. W tym wypadku silnik bazodanowy sqlite działający na pamięciowej bazie miał by na celu przygotowanie danych tak samo jak byś wczytał do jakiegoś kontenera z STL itd...
Corvis napisał(a):A jak to zadziała jak chce dane kompresować nie po 1 sek tylko po 1 godzinie ? musisz się odnieść do czegoś ( dlatego ta jednostka czasu ) - kolejność danych też ma znaczenie nie mogę ich sobie sortować dowolnie.
... Czyli to co chcesz z robić... wystarczą do tego dwie kolumny jedna na daty druga na dane liczbowe. Inaczej rzecz ujmując pamięciową bazę danych traktujesz jako kontener na dane i z niego / niej za pomocą komend SQL wybierasz dane jakie potrzebujesz.

Re: Wczytanie danych według zadanej kompresji czasu

Nowy postNapisane: czwartek, 31 stycznia 2013, 10:04
przez Corvis
Wieczorem zrobię testy na 200 mb plikach zobaczymy - ale moim zdaniem będzie to o wiele wolniejsze.

Re: Wczytanie danych według zadanej kompresji czasu

Nowy postNapisane: czwartek, 31 stycznia 2013, 16:16
przez Cyfrowy Baron
Corvis napisał(a):ale moim zdaniem będzie to o wiele wolniejsze.


Jak może być wolniejsze, skoro w tym co ty proponujesz oprócz porównania dochodzi jeszcze konwersja tekstu na datę i czas. Pracuj nie na klasie TStringList, lecz na THashedStringList - obsługa identyczna.

Re: Wczytanie danych według zadanej kompresji czasu

Nowy postNapisane: czwartek, 31 stycznia 2013, 16:28
przez Corvis
Podałem tylko jeden z formatów danych który obsługuje mój program. Wszystkich formatów jest o wiele więcej.

Robiąc tablę w bazie danych np.

    |Id|DataGodzina | Wartość |

Mając takie formaty:

    DataGodzina;Wartosc
    Data;Godzina;Wartość

oraz możliwe formaty daty:

    DDMMYY, YYMMDD, DD-MM-YY, YY-MM-DD, YY.MM.DD

+ to samo dla godziny. Wynika to z różnego formatu danych jakie zrzucają serwery. I tak przy odczycie danych czy to do bazy czy pliku muszę to konwertować do jednego formatu:

    2012.11.28 16:51:38;129138

Ps. Baronie ja podałem na szybko program który mi się przyśnił jak można to zrobić. Do odczytu danych w swoim programie używam algorytmu z postu Szybki Parser CSV

Re: Wczytanie danych według zadanej kompresji czasu

Nowy postNapisane: czwartek, 31 stycznia 2013, 18:20
przez Cyfrowy Baron
Ja zrobiłbym to tak:

KOD cpp:     UKRYJ  
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 String sFile = ExtractFilePath( ParamStr(0) ) + "danepelne.csv";

 THashedStringList *hslFull = new THashedStringList();
 hslFull->LoadFromFile( sFile  );
 hslFull->Sort();

 for(int i = hslFull->Count - 1; i > 0; i--)
 {
  String sValue1 = hslFull->Strings[i];
  String sFirst  = sValue1.SubString(1,  LastDelimiter(",", sValue1) - 1);

  String sValue2 = hslFull->Strings[i - 1];
  String sSecond = sValue2.SubString(1,  LastDelimiter(",", sValue2) - 1);

  if( SameText(sFirst, sSecond) ) hslFull->Delete( i - 1 );
 }

 hslFull->SaveToFile("Result.csv");

 delete hslFull;
}


U mnie kod dla Twojego pliku 1.9 MB wykonywał się 0,5 sekundy. To niestety oznacza, że plik 200 MB będzie się wykonywał blisko 2 minuty. Ale sprawdź...