我想在python中比较两个不同间距的数据集。我总是希望找到最接近的(最近邻居)匹配并重新调整数据,请参阅此示例:
数据集A:
ALTITUDE[m] VALUE
1. a1
2. a2
3. a3
4. a4
数据集B:
ALTITUDE[m] VALUE
0.7 b1
0.9 b2
1.7 b3
2. b4
2.4 b5
2.9 b6
3.1 b7
3.2 b8
3.9 b9
4.1 b10
ai
和bi
包含双倍数字,但也包含nan
个字段。
我想将数据集B转换为数据集A的高度网格,但由于数据集A包含的海拔高度低于数据集B,因此我想对它们进行平均。
ALTITUDE[m] VALUE
1. median(b1,b2)
2. median(b3,b4,b5)
3. median(b6,b7,b8)
4. median(b9,b10)
即。已找到并平均最近的海拔高度。
相反,如果我想将数据集A与数据集B的网格匹配,则数据集A应该如下所示(最近邻居):
ALTITUDE[m] VALUE
0.7 a1
0.9 a1
1.7 a2
2. a2
2.4 a2
2.9 a3
3.1 a3
3.2 a3
3.9 a4
4.1 a4
也许这甚至有一个名字(我想这是一个常见的问题),但我不知道它,因此无法搜索它。我相信有一种有效的方法可以做到这一点,除了我自己编写的明显的解决方案(但我担心它不会有效,我会引入很多错误)。
最好使用numpy。
编辑:感谢您对所有四位贡献者的意见。我学到了一点而且我很抱歉没有问清楚。我自己在理解这个问题的过程中。你的答案指向我使用interp1d
,answer允许我为我滥用它。我将很快发布结果。我只接受一个答案,但任何人都会这样做。
答案 0 :(得分:2)
两个假设: 1:您不是在寻找最近的邻居,而是在某个范围内的所有高度。所以,让我们说a1你想要所有的bn都在a1的0.5之内(根据你的例子给你b1和b2)。我会将“最近邻居”定义为不同的东西。
2:你的中位数并不算纳(根据某些IEEE惯例,numpy将它们视为无穷大,但这对我来说似乎很奇怪)。根据你的建议,我们使用scipy.stats的nanmedian。
我会做以下事情:
from numpy import *
from pylab import *
A_Alt = array([1,2,3,4])
A_Val = array([.33, .5, .6, .8])
B_Alt = array([.7, 0.9, 1.7, 2., 2.4, 2.9, 3.1, 3.2, 3.9, 4.1])
B_Val = array([.3, NaN, .8, .6, .7, .4, .3, NaN, .99, 1.3])
range = .5
B_Agrid = [nanmedian(B_Val[abs(B_Alt - k)<range]).item() for k in A_Alt]
A_Bgrid = [nanmedian(A_Val[abs(A_Alt - k)<range]).item() for k in B_Alt]
我们发现A_Alt中B_Alt与k的距离小于指定范围的所有指数。然后我们取这些B_Val的中位数。 A_Bgrid的结果与请求的结果相同。
==编辑==
关于你最近邻居的不同假设: 让我们将最近的邻居作为具有最小绝对高度差的条目(或在条带情况下的条目),而不将nan作为值。注:这些结果与您的示例不符,因为b1因b2更接近而不是a1的最近邻居。
在此假设下,以下代码应该有效:
from numpy import *
from pylab import *
from scipy.stats import nanmedian
A_Alt = array([1,2,3,4])
A_Val = array([.33, .5, .6, .8])
B_Alt = array([.7, 0.9, 1.7, 2., 2.4, 2.9, 3.1, 3.2, 3.9, 4.1])
B_Val = array([.3, NaN, .8, .6, .7, .4, .3, NaN, .99, 1.3])
def ReGridMedian(AltIn, ValIn, AltOut):
part = isfinite(ValIn)
q = [abs(AltIn[part]-k) for k in AltOut]
q = [nonzero(abs(k - min(k))<3*finfo(k.dtype).eps) for k in q]
q = [ValIn[part][k] for k in q]
return [median(k) for k in q]
B_Agrid = ReGridMedian(B_Alt, B_Val, A_Alt)
A_Bgrid = ReGridMedian(A_Alt, A_Val, B_Alt)
我在一起攻击了一些东西,它检查两个值在机器精度内是否相同,但我认为有更好的方法。在任何情况下,我们首先过滤所有非nan的值,然后找到最接近的匹配,然后检查重复的最小值,然后得到这些值的中值。
====
这是否涵盖您的问题,还是我的假设不正确?
答案 1 :(得分:1)
查看 numpy.interp
:
<击> http://docs.scipy.org/doc/numpy/reference/generated/numpy.interp.html 击>
(编辑:numpy.interp
仅提供线性插值,显然不是OP正在寻找的内容。而是使用像interp1d
这样的scipy方法{{1 }})
http://docs.scipy.org/doc/scipy/reference/interpolate.html
您想要做的是使用一个数据集的高度点来插值另一个数据集的值。使用numpy方法或其中一种scipy插值方法可以非常轻松地完成此操作。
答案 2 :(得分:1)
这不是您正在寻找的答案,但这是我的50c答案......
A = {1:'a1',2:'a2',3:'a3',4:'a4'} B = {0.7:'b1',0.9:'b2',1.7:'b3',2:'b4', 2.4:'b5'} C = {} # result # find altitude in A that is the closest to altitude in B def findAltitude( altB,A): toto = [ ((alt-altB)**2,alt) for alt in A.keys() ] toto.sort() return toto[0][1] #iter on each altitude of B for altB,valueB in B.iteritems(): altC = findAltitude( altB,A) if altC in C: C[altC].append(valueB) else: C[altC] = [valueB,] # then do the median operation #for altC,valueC in C.iteritems(): # C[altC] = map( median, valueC ) # where median is your median function print C
它根本不是最好的解决方案(特别是如果你有很多价值),但只能写得最快......
实际上,这取决于数据的存储方式。 Dictionnary不是最佳选择。
使用你的高度被分类的事实更有趣/更聪明。 您应该提供有关数据存储方式的更多详细信息(数组有numpy?)
====编辑====
我仍然不知道你的数据是怎样的,但是让我们根据你的海拔高度进行排序来尝试更“聪明”的东西。
from numpy import *
from pylab import *
from scipy.stats import nanmedian
# add val into C at the end of C or in the last place (depending if alt already exists in C or not)
def addto(C,val,alt):
if C and C[-1][0]==alt:
C[-1][1].append(valB)
else:
C.append( (alt,[valB,] ))
# values
A_Alt = array([1,2,3,4])
A_Val = array([.33, .5, .6, .8])
B_Alt = array([.7, 0.9, 1.7, 2., 2.4, 2.9, 3.1, 3.2, 3.9, 4.1])
B_Val = array([.3, NaN, .8, .6, .7, .4, .3, NaN, .99, 1.3])
#intermediate list of tuple (altitude, list_of_values)
C= []
#iterator on A
Aa = iter(A_Alt)
ainf = Aa.next()
asup = Aa.next() # two first values of A_Alt
#iterator on B
Ba = iter(B_Alt)
Bv = iter(B_Val)
# regrid
try:
while True:
altB = Ba.next()
valB = Bv.next()
# find ainf and asup in A_Alt such that ainf < altB < asup
while asup<altB:
try:
ainf,asup = asup, Aa.next()
except StopIteration:
break
# find closest
if abs(ainf-altB)<=abs(asup-altB):
addto(C, valB, ainf)
else:
addto(C, valB, asup)
except StopIteration:
pass
# do the median
res = [ nanmedian(k[1]) for k in C ]
print res
然后想法迭代两个向量/高度列表,并且对于B的每个高度,找到围绕它的两个高度A.然后,很容易找到最接近的......
这比Daan的解决方案更不易读,但它应该更高效(数据大小呈线性)。
如果您的数据没有像那样存储,您只需要修改。
答案 3 :(得分:1)
这是一种方式:
import numpy as np
def regrid_op(x, y, xi, op=np.median):
x, y, xi = np.atleast_1d(x, y, xi)
if (x.ndim, y.ndim, xi.ndim) != (1, 1, 1):
raise ValueError("works only for 1D data")
yi = np.zeros(xi.shape, dtype=y.dtype)
yi.fill(np.nan)
# sort data
j = np.argsort(x)
x = x[j]
y = y[j]
# group items by nearest neighbour
x0s = np.r_[xi, np.inf]
xc = .5*(x0s[:-1] + x0s[1:])
j0 = 0
for i, j1 in enumerate(np.searchsorted(x, xc)):
print "x =", xi[i], ", y =", y[j0:j1] # print some debug info
yi[i] = op(y[j0:j1])
j0 = j1
return yi
xi = np.array([1, 2, 3, 4])
x = np.array([0.7, 0.9, 1.7, 2.0, 2.4, 2.9, 3.1, 3.2, 3.9, 4.1])
y = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10.])
print regrid_op(x, y, xi)
我没有看到在xi
数组中对项进行矢量化的方法,所以如果网格A
中的点数不是太大,这应该是有效的。
编辑:这也假定xi
中的点已排序。
答案 4 :(得分:0)
覆盖第二种情况的一种方法(网格B到A,即从几个高度到多个高度)是这样的:
外推功能(来自here)
from scipy.interpolate import interp1d
def extrap1d(interpolator):
xs = interpolator.x
ys = interpolator.y
def pointwise(x):
if x < xs[0]:
return ys[0]
elif x > xs[-1]:
return ys[-1]
else:
return interpolator(x)
def ufunclike(xs):
return array(map(pointwise, array(xs)))
return ufunclike
值
A_Alt = array([1,2,3,4])
A_Val = array([.33, .5, .6, .8])
B_Alt = array([.7, 0.9, 1.7, 2., 2.4, 2.9, 3.1, 3.2, 3.9, 4.1])
实际重新划分:
f_i = interp1d(A_Alt, A_Val, kind='nearest')
f_x = extrap1d(f_i)
f_x(B_Alt)
输出:
array([ 0.33, 0.33, 0.5 , 0.5 , 0.5 , 0.6 , 0.6 , 0.6 , 0.8 , 0.8 ])