Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Uśrednianie danych i kodowanie do formatu JSON
Forum PHP.pl > Forum > PHP
zbysiusp
Witam!

Proszę o pomoc w rozwiązaniu następującego problemu. Do bazy MySQL zapisuję co 1 minutę wynik pomiaru wilgotności powietrza. Za pomocą skryptu php pobieram dowolną ilość danych np. 17 i koduję je do formatu JSON. Skrypt, który napisałem działa bardzo dobrze.
  1. <?php
  2.  
  3. $wynik_data = mysql_query("SELECT czas_datetime FROM tab_czujniki_2 ORDER BY czas_datetime DESC LIMIT 1");
  4.  
  5. if(mysql_num_rows($wynik_data) > 0) {
  6. $r = mysql_fetch_assoc($wynik_data);
  7. $datan = $r['czas_datetime'];
  8. $daten = new DateTime($data);
  9. $daten->modify('-15 min');
  10. $minus_data = $daten->format("Y-m-d H:i:00");
  11. }
  12.  
  13. $sth = mysql_query("SELECT czas_unix, wilgotnosc FROM tab_czujniki_2 WHERE czas_datetime >= '$minus_data' ORDER BY czas_datetime ASC") or die('Błąd zapytania');
  14.  
  15. $rows = array();
  16. $rows['name'] = 'Wilgotnosc';
  17. while($r = mysql_fetch_array($sth)){
  18.  
  19. $rows['data'][] = array(1000*($r['czas_unix']),$r['wilgotnosc']);
  20. }
  21.  
  22. $result = array();
  23. array_push($result,$rows);
  24. print json_encode($result, JSON_NUMERIC_CHECK)
  25.  
  26. ?>

skrypt

Chciałbym jednak zmienić jego działanie, ale nie bardzo wiem jak podejść do tematu.
Założenia algorytmu:

1. Pobieram z bazy MySQL dowolną ilość rekordów np. 17: (czas1, wil1), (czas2, wil2), (czas3, wil3), (czas4, wil4), (czas5, wil5), ..., (czas17, wil17).
2. Z każdych pięciu, kolejnych rekordów obliczam średnią wilgotność: (wil1+wil2+wil3+wil4+wil5)/5 itd. Z 17 rekordów powstaną więc 3 średnie.
3. Średnie mają być wyliczane tak długo jak będzie 5 lub więcej rekordów. Z 17 rekordów pozostaną więc 2 rekordy niepoddane uśrednianiu.
4. Każdej średniej ma zostać przypisany czas rekordu środkowego w każdej piątce np. średniej z pierwszej piątki przypisany zostanie czas3.
5. Teraz wyliczone średnie z przypisanym czasem koduję do formatu JSON jak w przedstawionym wyżej skrypcie.

Dziękuję i pozdrawiam
Pyton_000
Tak na szybko, reszte sobie ogarnij sam.

  1. <?php
  2.  
  3. $data = [
  4. [234523452, 50],
  5. [234523453, 52],
  6. [234523454, 53],
  7. [234523455, 54],
  8. [234523456, 55],
  9. [234523457, 56],
  10. [234523458, 57],
  11. [234523461, 58],
  12. [234523462, 59],
  13. [234523463, 60],
  14. [234523472, 62],
  15. [234523482, 64],
  16. [234523542, 65],
  17. [234523452, 66],
  18. [234523452, 67],
  19. [234523452, 66],
  20. [234523452, 50],
  21. ];
  22.  
  23. $sets = array_chunk($data, 5);
  24.  
  25. foreach($sets as $key => $set) {
  26. if(count($set) !== 5) {
  27. continue;
  28. }
  29. $sets[$key][3][1] = array_sum(array_column($set[1]))/5;
  30. }
  31.  
  32. var_dump($sets);
zbysiusp
Bardzo dziękuję.

Napisz proszę, czy mogę wykorzystać dane wczytywane w sposób jak w moim skrypcie, tzn.
czy: $data w Twoim kodzie jest tożsame z moim $rows i czy obróbkę danych (dzielenie na paczki po 5 itd.) mam zawrzeć w już istniejącej pętli while?
  1. $sth = mysql_query("SELECT czas_unix, wilgotnosc FROM tab_czujniki_2 WHERE czas_datetime >= '$minus_data' ORDER BY czas_datetime ASC") or die('Błąd zapytania');
  2.  
  3. $rows = array();
  4.  
  5. while($r = mysql_fetch_array($sth)){
  6.  
  7. $rows[] = array(1000*($r['czas_unix']),$r['wilgotnosc']);
  8.  
  9. }
  10.  
  11. $result = array();

Pozdrawiam
Pyton_000
Nie. Podstaw po prostu swoją gotowa tablice zamiast $data i nie. Nie w pętli. Poza nią
zbysiusp
Witam!

Dziękuję @Pyton_000 za kod i pomoc. Nie mogę jednak ogarnąć jego działania. Spodziewam się w wyniku działa tego skryptu 3 średnich z przypisanym czasem unix:

52.8 -> 234523454 (pierwsza paczka 5 wartości),
58.0 -> 234523461 (druga paczka 5 wartości),
64,8 ->234523542 (trzecia paczka 5 wartości)

W wyniku działania skryptu otrzymuję błąd: array_column wymaga dwóch parametrów, a i wyliczonych średnich nie widzę.
skrypt
  1. <?php
  2.  
  3. $data = [
  4. [234523452, 50],
  5. [234523453, 52],
  6. [234523454, 53],
  7. [234523455, 54],
  8. [234523456, 55],
  9.  
  10. [234523457, 56],
  11. [234523458, 57],
  12. [234523461, 58],
  13. [234523462, 59],
  14. [234523463, 60],
  15.  
  16. [234523472, 62],
  17. [234523482, 64],
  18. [234523542, 65],
  19. [234523452, 66],
  20. [234523452, 67],
  21.  
  22. [234523452, 66],
  23. [234523452, 50],
  24. ];
  25.  
  26. $sets = array_chunk($data, 5);
  27.  
  28. foreach($sets as $key => $set) {
  29. if(count($set) !== 5) {
  30. continue;
  31. }
  32. $sets[$key][3][1] = array_sum(array_column($set[1]))/5;
  33. }
  34.  
  35. var_dump($sets);
  36.  
  37. ?>

Bardzo proszę o wyjaśnienie.
bostaf
Hej zbysiusp,

Pyton_000 napisał Ci na szybko przykład z logiką, niekoniecznie gotowe rozwiązanie. Jeśli widzisz błąd to po pierwsze powinieneś luknąć do manuala i zobaczyć o co biega.
No ale masz tu gotowca, z wyjaśnieniem:
Zamień wiersz 32 z Twojego listingu na takie coś:

  1. $wynik[$key]['srednia'] = (float) array_sum(array_column($sets[$key], 1))/5;
  2. $wynik[$key]['czas'] = $sets[$key][2][0];


no i w 35 zamiast var_dump daj
  1. print json_encode($wynik, JSON_NUMERIC_CHECK);


Co tu się dzieje?
1. array_chunk($data, 5) dzieli tablicę $data na kilka mniejszych, z których każda zawiera 5 elementów
2. array_column zwraca tablicę wartości z jednej kolumny tablicy. Tu był ten błąd z brakującym drugim parametrem funkcji - ten drugi parametr to nazwa kolumny.
3. array_sum sumuje wartości z tablicy, które potem dzielisz przez 5 żeby otrzymać średnią wilgotność

Co może być niejasne na pierwszy rzut oka, to indeksowanie tablicy po array_chunk. Najlepiej zrób var_dump($sets) w wierszu 27 i przeanalizuj wynik - od razu Ci się wszystko poukłada w logiczną całość.
zbysiusp
Witaj, bostaf

Bardzo serdecznie dziękuję za gotowy przykład i wyjaśnienia. Dzięki Tobie i Koledze Pyton_000 zrobiłem duży krok w zgłębianiu tajemnic PHP. Zrobiłem podobnie z danymi LIVE z bazy danych i działa jak oczekiwałem. Pozostaje jeszcze przywrócenie formatu JSON jak w skrypcie z pierwszego postu. Jest prawie dobrze, ale nie mogę poradzić sobie z wstawieniem tablicy tablic: 'data'

aktualny wynik działania skryptu

  1. $sth = mysql_query("SELECT czas_unix, wilgotnosc FROM tab_czujniki_2 WHERE czas_datetime >= '$minus_data' ORDER BY czas_datetime ASC") or die('Błąd zapytania');
  2.  
  3. $rows = array();
  4. //$rows['name'] = 'Wilgotnosc';
  5. while($r = mysql_fetch_array($sth)){
  6.  
  7. $rows[] = array(1000*($r['czas_unix']),$r['wilgotnosc']);
  8. }
  9.  
  10. $sets = array_chunk($rows, 5);
  11.  
  12. foreach($sets as $key => $set) {
  13. if(count($set) !== 5) {
  14. continue;
  15. }
  16.  
  17. $wynik['name'] = 'Wilgotnosc';
  18. $wynik[$key][] = $sets[$key][2][0];
  19. $wynik[$key][] = (float) array_sum(array_column($sets[$key], 1))/5;
  20. }
  21.  
  22. print json_encode($wynik, JSON_NUMERIC_CHECK);



Pozdrawiam serdecznie
zbysiusp
bostaf
Bo te dane - średnia i czas, muszą trafić do klucza "data". Zamiast 18 i 19, chyba coś w ten deseń:
  1. $wynik2['data'][$key] = array(
  2. $sets[$key][2][0],
  3. (float) array_sum(array_column($sets[$key], 1))/5
  4. );

zbysiusp
Witaj,

Bardzo serdecznie dziękuję za kolejną, konkretną i trafną odpowiedź! Dodałem jedynie linię sumującą $wynik1 i $wynik2 i dopiero ich sumę zakodowałem do formatu JSON. Wynik działania skryptu jest zgodny w 100% z moim oczekiwaniem.
  1. $wynik1['name'] = 'Wilgotnosc';
  2.  
  3. $wynik2['data'][$key] = array(
  4. $sets[$key][2][0],
  5. (float) array_sum(array_column($sets[$key], 1))/5);
  6. }
  7.  
  8. $wynik3[] = $wynik1 + $wynik2;
  9.  
  10. print json_encode($wynik3, JSON_NUMERIC_CHECK);


Pozdrawiam serdecznie
zbysiusp
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.