Dies ist die beste Lösung, die ich tun konnte:
#standardSQL
CREATE TEMP FUNCTION distance(lat1 FLOAT64, lat2 FLOAT64, lon1 FLOAT64, lon2 FLOAT64) AS((
WITH data AS(
SELECT POW(SIN((ACOS(-1)/180 * (lat1 -lat2))/2), 2) + COS(ACOS(-1)/180 * (lat1)) * COS(ACOS(-1)/180 * (lat2)) * POW(SIN((ACOS(-1)/180 * (lon1 -lon2))/2), 2) a
)
SELECT 6371 * 2 * ATAN2(SQRT((SELECT a FROM data)), SQRT(1 - (SELECT a FROM data)))
));
WITH temperature_data AS(
SELECT
CONCAT(year, mo, da) date,
temp,
b.lat lat,
b.lon lon
FROM `bigquery-public-data.noaa_gsod.gsod2016` a
JOIN `bigquery-public-data.noaa_gsod.stations` b
ON a.stn = b.usaf AND a.wban = b.wban
WHERE concat(year, mo, da) BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(PARSE_DATE('%Y%m%d', '20160725'), INTERVAL 7 DAY)) AND '20160725'
)
SELECT
date,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 20, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 20, temp, NULL)) AS std_temp) data_20km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 50, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 50, temp, NULL)) AS std_temp) data_50km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 100, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 100, temp, NULL)) AS std_temp) data_100km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 200, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 200, temp, NULL)) AS std_temp) data_200km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 500, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 500, temp, NULL)) AS std_temp) data_500km
FROM temperature_data t
WHERE
distance(t.lat, 10.1, t.lon, 10.2) < 2000
GROUP BY date
ORDER BY date
Ich werde versuchen zu erklären, zusammen mit Ihren Fragen:
Wie kann ich 7 Tage eines bestimmten Datums erhalten?
Innerhalb der Abfrage temperature_data
, bemerken es WHERE
Klausel hat die Bedingung:
WHERE concat(year, mo, da) BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(PARSE_DATE('%Y%m%d', '20160725'), INTERVAL 7 DAY)) AND '20160725'
Hier werden die letzten 7 Tage von einem bestimmten Zeitpunkt ausgewählt werden. Sie können das Datum auswählen, das Sie analysieren möchten, indem Sie einfach den Wert '20160725' ändern.
Können max und min lat/lon direkt über die Abfrage berechnet werden?
Ja. Ich stelle mir vor, du meinst damit, wenn es möglich ist, räumliche Punkte innerhalb eines bestimmten Bereichs auszuwählen (zum Beispiel 20 km). Eine Möglichkeit, dies zu tun ist, die eine temporäre Funktion Abstände zwischen einem gewünschten Punkt und den Stationspunkten zu berechnen, die in der Abfrage ausgedrückt wird durch:
CREATE TEMP FUNCTION distance(lat1 FLOAT64, lat2 FLOAT64, lon1 FLOAT64, lon2 FLOAT64) AS((
WITH data AS(
SELECT POW(SIN((ACOS(-1)/180 * (lat1 -lat2))/2), 2) + COS(ACOS(-1)/180 * (lat1)) * COS(ACOS(-1)/180 * (lat2)) * POW(SIN((ACOS(-1)/180 * (lon1 -lon2))/2), 2) a
)
SELECT 6371 * 2 * ATAN2(SQRT((SELECT a FROM data)), SQRT(1 - (SELECT a FROM data)))
));
Sie sich um und testen Sie diese Funktion zum Beispiel spielen können:
SELECT distance(50, 60, 30, 10) # result is ~ 1680km
Diese Funktion wird hier verwendet:
WHERE
distance(t.lat, 10.1, t.lon, 10.2) < 2000
zum ausfiltern von mehr als 2000 km Punkte weiter weg von (10.1 °, 10.2 °). In Ihrer Abfrage können Sie anstelle von (10,1 °, 10,2 °) einen anderen Eingabewert wählen.
Sehr oft findet es keine Daten, da der Radius von 20km wahrscheinlich zu klein ist, um eine Station zu finden. Wie kann ich die Abfrage auf ändern, um die nächstgelegenen Stationen zu finden, wenn sie nicht innerhalb von 20 km gefunden werden können?
Eine mögliche Lösung wird auf einmal für mehrere unterschiedliche Abstände abfragt:
SELECT
date,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 20, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 20, temp, NULL)) AS std_temp) data_20km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 50, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 50, temp, NULL)) AS std_temp) data_50km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 100, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 100, temp, NULL)) AS std_temp) data_100km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 200, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 200, temp, NULL)) AS std_temp) data_200km,
STRUCT(AVG(IF(distance(t.lat, 10.1, t.lon, 10.2) < 500, temp, NULL)) AS avg_temp, STDDEV_SAMP(IF(distance(t.lat, 10.1, t.lon, 10.2) < 500, temp, NULL)) AS std_temp) data_500km
FROM temperature_data t
WHERE
distance(t.lat, 10.1, t.lon, 10.2) < 2000
GROUP BY date
Hinweis, dass diese Abfragestation Punkte Extrahieren zwischen dem Eingangspunkt (10,1 °, 10,2 °) bis zu 2000 km entfernt. Und dann wird ein Filter verwendet, um Punkte innerhalb der Bereiche 20km, 50km, 100km, 200km und 500km auszuwählen.
Sie können diese Werte ändern, wie Sie es für richtig halten. Wenn Sie die Durchschnittstemperatur von einem anderen Punkt (40 °, 30 °) erhalten möchten, ändern Sie einfach die Werte (10.1, 10.2) auf (40, 30) und Sie können loslegen. Wenn Sie unterschiedliche Abstände von diesem Punkt wünschen, können Sie die Ausdrücke IF(distance(t.lat, 10.1, t.lon, 10.2) < 200
beispielsweise in einen Bereich ändern, der Ihren Anforderungen besser entspricht.
Beachten Sie, dass die WHERE
Klausel hat die Bedingung:
distance(t.lat, 10.1, t.lon, 10.2) < 2000
So wird diese alle Stationen Ausfiltern weiter weg von dem Punkt (10.1, 10.2) von mehr als 2000 km. Sie können diesen Wert auch ändern, wie Sie es für richtig halten.
Abschließender Hinweis zu diesem: Ich brachte auch die STDDEV_SAMP
, die die standard deviation of a sampling ist. Dies kann sowohl für Sie als auch für eine Vorstellung davon nützlich sein, wie sehr sich der Durchschnitt um den Mittelwert herum ausbreitet (korrigiert durch den Effekt der Sampling-Datengröße). Der Durchschnitt an sich ist nicht so wertvoll, wenn wir nicht wissen, wie nahe wir dem richtigen Wert sind.
Gibt es bessere, kostenlose, historische Wetterdaten, die ich bekommen kann?
Weiß nicht. Hoffentlich wird dieser öffentliche Datensatz für Sie gut genug sein.
Bitte zeigen Sie einige Daten, die Ihre Frage klären; Ich folge es nicht vollständig. –
welcher Teil ist nicht klar? Wenn Sie die obige Abfrage ausführen, erhalten Sie Daten von mehreren Stationen. Sie sollten nach Tagen und Monaten gruppiert werden. Außerdem zeigt die Abfrage nur Daten für einen bestimmten Monat an. Aber ich möchte lieber die letzte Woche eines bestimmten Datums haben. – Chris
Keine direkte Antwort, aber das [Beispiel im Migrationsleitfaden] (https://cloud.google.com/bigquery/docs/reference/standard-sql/migrating-from-legacy-sql#correlated_subqueries) könnte nützlich sein. –