Pandas 包含地理数据的数据框转换为数组需要很多时间

Pandas dataframe containing geographical data conversion to array takes a lot of time

我有一个这样的 pandas 数据框

lat lon value
10   10  1

这个数据框有 700 万个数据点

我想将其转换为数组,以便最终将它们转换为 net cdf 文件 我有两种方法

  1. 使用 gdal 将数据帧转换为点 shapefile,然后使用 qgis 将 shapefile 转换为栅格。这只需要 3-4 分钟(8 核 M1 处理器)但是有少量信息丢失

  2. 将pandas'数据框转换为数组,并将数组写入.nc文件。根据我的估计,这将在 18 核英特尔 cpu 超级计算机上花费 120 小时。 (代码使用 joblib 并行化。)

代码看起来像这样

lati=np.round(np.linspace(np.min(df.lat),np.max(df.lat),lat_range+1),2)
loni=np.round(np.linspace(np.min(df.lon),np.max(df.lon),lon_range+1),2)
target_column = 'soil_moisture'
search_columns = ['lat','lon']
df_temp = df.set_index(search_columns)
def func(i,j):
    latitude= lati[i]
    longitude=loni[j]
    search_values = [latitude, longitude]
    value = df_temp.loc[tuple(search_values), target_column]
    return(value)

from joblib import Parallel, delayed
results= Parallel(n_jobs=-1, verbose=2)(delayed(func)(i, j) for i in range(lat_range+1) for j in range(lon_range+1)) 
m=np.reshape(results, (lat_range+1,lon_range+1))

我已经在虚拟数据集上测试了代码,它工作正常,但在原始数据集上,它需要很多时间。

编辑: 我的方法是错误的,最好的方法是将 pandas 数据帧转换为 xarray,然后再转换为 net cdf

 xr=df.set_index(['lat', 'lon']).to_xarray()
    xr.to_netcdf(path='./new.nc', mode='w')

这超级高效

没有数据样本,很难猜测您可以使用哪种方法。我做了2个案例的样本:

a) 您在 table 中的数据是有组织的,因此您可以使用 NumPy 的重塑

b) 你在 table 中的数据没有组织,所以你可以使用插值到一些规则的网格

#!/usr/bin/env ipython
import pandas as pd
import numpy as np
# -------------------------
# example with data at regular grid:
xx = np.linspace(0.,360,100);ddx = np.mean(np.diff(xx))
yy = np.linspace(-180.0,180.0,100);ddy = np.mean(np.diff(yy))
xm,ym = np.meshgrid(xx,yy);
zz = 50.0 + 10.0*np.random.random((np.size(yy),np.size(xx)));
data = {'lon':xm.flatten(),'lat':ym.flatten(),'data':zz.flatten()};
df = pd.DataFrame.from_dict(data);
# let us convert this data back to understandable form:
xo = np.unique(df['lon'].values);yo = np.unique(df['lat'].values);zo = df['data'].values;
zreg = np.reshape(zo,(np.size(yo),np.size(xo)));
print(zz == zreg);# is the original the same with the one from Pandas dataframe?
# =========================================================================================================
# ---------------------------------
# example with data randomly ordered, irregular space?
xcoords  = xm.flatten()+ddx/2*np.random.random(np.size(zz.flatten())) # original coords + some small noise (half the cell) 
ycoords  = ym.flatten()+ddy/2*np.random.random(np.size(zz.flatten())) # original coords + some small noise (half the cell)
points = np.concatenate((xcoords[:,np.newaxis],ycoords[:,np.newaxis],zz.flatten()[:,np.newaxis]),axis=1);
points =  points[points[:, 2].argsort()] # let us sort points by values
data = {'lon':points[:,0],'lat':points[:,1],'data':points[:,2]}; 
# -----------------------------------------------------------------
df = pd.DataFrame.from_dict(data);
xp = df['lon'].values;yp = df['lat'].values;zp = df['data'].values

from scipy.interpolate import griddata
zo = griddata((xp,yp),zp,(xm,ym),'nearest'); # I would make some interpolation to regular grid...
print(zz == zo);

当然,如果你有700万个点,那么你可能需要相当大的内存来保存数据。我能够用 2000x2000 和 3000x3000 点测试我的代码,但只能在具有大量内存的机器上进行。另一方面,我的旧笔记本电脑只能使用 1000x1000。无论如何,对于不规则的数据,插值有时会与原始值不同,但在我看来差异相对较小。

之后写netCDF真的很简单:

from netCDF4 import Dataset
with Dataset('test.nc','w','NETCDF3') as ncout:
    ncout.createDimension('lon',np.size(xx));
    ncout.createDimension('lat',np.size(yy));
    xvar = ncout.createVariable('lon','float32',('lon'));xvar[:] = xx
    yvar = ncout.createVariable('lat','float32',('lat'));yvar[:] = yy
    zvar = ncout.createVariable('data','float32',('lat','lon'));zvar[:] = zo

如果 df 就像您描述的那样,那么 df.set_index(['lat', 'lon']).to_xarray() 可能就可以了。

这里有一些可以在我的电脑上运行的行:

import pandas as pd

df = pd.DataFrame(data=[[10, 10, 0.1], [10, 15, 0.2], [15, 10, 0.3], [15, 15, 0.3]], 
                  columns=['lon', 'lat', 'soil_moisture'])
df.set_index(['lat', 'lon']).to_xarray()

结果不错xarray.Dataset