python - гео биннинг - усреднение значений в пределах географической границы - PullRequest
4 голосов
/ 17 февраля 2020

С данными, подобными приведенным ниже, - фиксирует измерения в различных близких местах.

Lat Long    val
35.611053   139.628525  -72.82
35.61105336 139.6285236 -78.04
35.61105373 139.6285223 -72.99
35.61105409 139.6285209 -69.04
35.61105445 139.6285195 -65.4
35.61105482 139.6285182 -66.68
35.61105518 139.6285168 -65.82
35.61105555 139.6285155 -64.47
35.61105591 139.6285141 -71.26
35.61105627 139.6285127 -68.36
35.61105664 139.6285114 -74.48
35.611057   139.62851   -74.27
35.61105736 139.62851   -77.97
35.61105773 139.62851   -68.66
35.61105809 139.62851   -70.21
35.61105845 139.62851   -76.05
35.61105882 139.62851   -88.83
35.61105918 139.62851   -73.17
35.61105955 139.62851   -67.63
35.61105991 139.62851   -71.85
35.61106027 139.62851   -77.42
35.61106064 139.62851   -71.08
35.611061   139.62851   -79.27

Необходимо выполнить операцию разбивки этих данных, то есть получить среднее значение всех значений в val каждые 0,1x0. 1 метр Один из подходов может состоять в том, чтобы найти ребра (например, NW, SW, NE и SE) и разделить их на набор сеток 0,1x0,1 метра и значений поиска в каждой сетке, а также вычислить среднее значение и приписать широту / долготу в центре. сетки, так что у нас есть результаты, как показано ниже.

Lat Long    Mean_val    Sample_count

Хотя предлагаемый подход может быть наивным, хотел бы также знать, может ли быть подход, основанный на pandas

1 Ответ

1 голос
/ 23 февраля 2020

Простое решение для усреднения данных по площади 0,1 м * 0,1 м

Для этого необходимо преобразовать координаты широты и долготы в координаты x, y.

Здесь я использую модуль utm:

x,y,_,_ = utm.from_latlon(latitude, longitude) 

После этого вы можете создать новый столбец, который будет представлять вашу координату x, y в дециметрах:

def apply_fun (raw):
    x,y,_,_ = utm.from_latlon(raw['Lat'],raw['Long']) 
    return str(np.round(x*10))+"|"+str(np.round(y*10))

Затем добавьте его в свой фрейм данных:

x = df.apply(lambda row : apply_fun(row),axis=1)
df.insert(3,'Group',x)

, и вы примените функцию группировки:

gdf = df.groupby(['Group']).agg({"Lat":["mean"],"Long":["mean","count"],"val":["mean"]})
gdf = gdf.reset_index().drop(columns=['Group'],level=0)
gdf.columns = [' '.join(col) for col in gdf.columns]

И все готово! :)

Обобщение предыдущего решения

Чтобы сгруппировать данные по k1 метрам * k2 метра, просто измените эту функцию:

def apply_fun (raw):
    x,y,_,_ = utm.from_latlon(raw['Lat'],raw['Long']) 
    return str(np.round(x/k1))+"|"+str(np.round(y/k2)) 

Критика предыдущего решения

Как я уже говорил ранее, чтобы решить эту проблему, мы должны преобразовать координаты lat, long в координаты x, y.

В предыдущем решении я преобразовал координаты lat, long в utm. Система utm представляет собой картографическую проекцию c, которая делит Землю на 120 областей: 60 на север и 60 на юг. Поэтому, когда мы делаем:

x,y,area_number,NS = utm.from_latlon(raw['Lat'],raw['Long'])

(x,y) - наша позиция в области (area_number,NS). Мы можем заключить, что наше решение работает тогда и только тогда, когда наши датчики находятся в одной и той же области UTM.

Мы также можем выполнить это преобразование, используя преобразования ECEF, которые непосредственно преобразуют широту, длину в координаты x, y. Я не знаю точности этих методов, и поскольку нас просят о точности с точностью до десятой доли метра, я предпочитаю выбирать преобразование utm, которое выглядит более точным.

Если вы хотите использовать метод ECEF, сделанный так:

import pyproj
def gps_to_ecef_pyproj(lat, lon, alt):
    ecef = pyproj.Proj(proj='geocent', ellps='WGS84', datum='WGS84')
    lla = pyproj.Proj(proj='latlong', ellps='WGS84', datum='WGS84')
    x, y, z = pyproj.transform(lla, ecef, lon, lat, alt, radians=False)

    return x, y, z

x,y,z = gps_to_ecef_pyproj(raw['Lat'],raw['Long'],0)

(я беру код отсюда: https://gis.stackexchange.com/questions/230160/converting-wgs84-to-ecef-in-python)

...