Pandas 包含地理数据的数据框转换为数组需要很多时间
Pandas dataframe containing geographical data conversion to array takes a lot of time
我有一个这样的 pandas 数据框
lat lon value
10 10 1
这个数据框有 700 万个数据点
我想将其转换为数组,以便最终将它们转换为 net cdf 文件
我有两种方法
使用 gdal 将数据帧转换为点 shapefile,然后使用 qgis 将 shapefile 转换为栅格。这只需要 3-4 分钟(8 核 M1 处理器)但是有少量信息丢失
将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
。
我有一个这样的 pandas 数据框
lat lon value
10 10 1
这个数据框有 700 万个数据点
我想将其转换为数组,以便最终将它们转换为 net cdf 文件 我有两种方法
使用 gdal 将数据帧转换为点 shapefile,然后使用 qgis 将 shapefile 转换为栅格。这只需要 3-4 分钟(8 核 M1 处理器)但是有少量信息丢失
将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
。