我目前正在一个项目中,以估算流量计的不确定性。仪表不确定度基于四个不同的值:
第三方为电表提供了liq,cP,wlr和gvf的多个不同值的表。您可以猜测,仪表的数据永远不会完美地落入预定义的值之一。例如,一分钟的数据可能显示为:
对上面的数据进行四次插值,以找出不确定性。
我想出了一个解决方案,但似乎很笨拙,我想知道是否有人有任何想法。我还是熊猫游戏的新手,非常感谢看到其他人的解决方案。
最初,我对数据进行排序,以将表缩小为要查找的实际值之上和之下的值。
aliq = 6532 # stbpd
avisc = 22 # centipoise
awlr = 0.412 # water liquid ratio
agvf = 0.634 # gas volume fraction
def findclose(num, colm):
arr = colm.unique()
if num in arr:
clslo = num
clshi = num
else:
clslo = arr[arr > num].min() # close low value
clshi = arr[arr < num].max() # close high value
return [clslo, clshi]
df = tbl_vx52[
(tbl_vx52['liq'].isin(findclose(aliq,tbl_vx52['liq']))) &
(tbl_vx52['visc'].isin(findclose(avisc,tbl_vx52['visc']))) &
(tbl_vx52['wlr'].isin(findclose(awlr,tbl_vx52['wlr']))) &
(tbl_vx52['gvf'].isin(findclose(agvf,tbl_vx52['gvf'])))
].reset_index(drop=True)
该表从2240减少到16。而不是包含所有数据(tbl_vx52)。我已经创建了一些要加载的代码,因此您可以看到子数据框的外观,称为df,仅包含此示例区域上方和下方的值。
df = pd.DataFrame({'liq':[5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 7000, 7000, 7000, 7000, 7000, 7000, 7000, 7000],
'visc':[10, 10, 10, 10, 30, 30, 30, 30, 10, 10, 10, 10, 30, 30, 30, 30],
'wlr':[0.375, 0.375, 0.5, 0.5, 0.375, 0.375, 0.5, 0.5, 0.375, 0.375, 0.5, 0.5, 0.375, 0.375, 0.5, 0.5],
'gvf':[0.625, 0.75, 0.625, 0.75, 0.625, 0.75, 0.625, 0.75, 0.625, 0.75, 0.625, 0.75, 0.625, 0.75, 0.625, 0.75],
'uncert':[0.0707, 0.0992, 0.0906, 0.1278, 0.0705, 0.0994, 0.091, 0.128, 0.0702, 0.0991, 0.0905, 0.1279, 0.0704, 0.0992, 0.0904, 0.1283],
})
完成了一些非常粗略的循环,以开始基于各个输入(liq,visc,wlr或gvf)对值进行配对。下面显示的是gvf上的第一个循环。
pairs = [
slice(0,1),
slice(2,3),
slice(4,5),
slice(6,7),
slice(8,9),
slice(10,11),
slice(12,13),
slice(14,15)]
for pair in pairs:
df.loc[pair,'uncert'] = np.interp(
agvf,
df.loc[pair,'gvf'],
df.loc[pair,'uncert']
)
df.loc[pair,'gvf'] = agvf
df = df.drop_duplicates().reset_index(drop=True)
删除重复的值,从16行减少到8行。然后再对wlr重复一次。
pairs = [
slice(0,1),
slice(2,3),
slice(4,5),
slice(6,7)
]
for pair in pairs:
df.loc[pair,'uncert'] = np.interp(
awlr,
df.loc[pair,'wlr'],
df.loc[pair,'uncert']
)
df.loc[pair,'wlr'] = awlr
df = df.drop_duplicates().reset_index(drop=True)
对visc(四行)重复上述结构,最后对液体(两行)重复,直到子数组中只剩下一个值。这样就可以在您的工作点获得米的不确定性。
我知道它很笨重。对于不同方法的任何投入或想法,我们将不胜感激。
答案 0 :(得分:1)
好的,我能够找到并应用基于矩阵的解决方案。它基于三线性插值的矩阵方法,可以扩展为四线性插值。维基百科在trilinear interpolation上提供了很好的文章。维基百科文章中的8x8矩阵可以扩展为16x16,以进行四线性插值。下面编写了一个函数,以使矩阵内的每一行成为可能。
def quad_row(x, y, z, k):
"""
Generate a row for the quad interpolation matrix
x, y, z, k are scalar input values
"""
qrow = [1,
x, y, z, k,
x*y, x*z, x*k, y*z, y*k, z*k,
x*y*z, x*y*k, x*z*k, y*z*k,
x*y*z*k]
return qrow
显然,这只是三线性矩阵内行的扩展。该函数可以循环十六次以生成整个矩阵。
侧面注意:如果想花哨的话,可以使用itertools组合完成quad_row函数。优点是您可以输入任意大小的数组,并且它会为插值矩阵返回格式正确的行。该功能更灵活,但最终速度更慢。
from itertools import combinations
def interp_row(values):
values = np.asarray(values)
n = len(values)
intp_row = [1]
for i in range(1, n+1):
intp_row.extend([np.product(x) for x in list(combinations(values, i))])
return intp_row
如下所示,该函数可以接受输入表,查找接近插值的值,构建插值矩阵并执行矩阵数学运算。
def quad_interp(values, table):
"""
values - four points to interpolate across, pass as list or numpy array
table - lookup data, four input columns and one output column
"""
table = np.asarray(table)
A, B, C, D, E = np.transpose(table)
a, b, c, d = values
in_vector = quad_row(a, b, c, d)
mask = (
np.isin(A, findclose(a, A)) &
np.isin(B, findclose(b, B)) &
np.isin(C, findclose(c, C)) &
np.isin(D, findclose(d, D)))
quad_matrix = []
c_vector = []
for row in table[mask]:
x, y, z, v, w = row
quad_matrix.append(quad_row(x, y, z, v))
c_vector.append(w)
quad_matrix = np.matrix(quad_matrix)
c_vector = np.asarray(c_vector)
a_vector = np.dot(np.linalg.inv(quad_matrix), c_vector)
return float(np.dot(a_vector, in_vector))
例如,调用该函数将如下所示。
df = pd.DataFrame({'liq':[5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 7000, 7000, 7000, 7000, 7000, 7000, 7000, 7000],
'visc':[10, 10, 10, 10, 30, 30, 30, 30, 10, 10, 10, 10, 30, 30, 30, 30],
'wlr':[0.375, 0.375, 0.5, 0.5, 0.375, 0.375, 0.5, 0.5, 0.375, 0.375, 0.5, 0.5, 0.375, 0.375, 0.5, 0.5],
'gvf':[0.625, 0.75, 0.625, 0.75, 0.625, 0.75, 0.625, 0.75, 0.625, 0.75, 0.625, 0.75, 0.625, 0.75, 0.625, 0.75],
'uncert':[0.0707, 0.0992, 0.0906, 0.1278, 0.0705, 0.0994, 0.091, 0.128, 0.0702, 0.0991, 0.0905, 0.1279, 0.0704, 0.0992, 0.0904, 0.1283],
})
values = [6532, 22, 0.412, 0.634]
quad_interp(values, df)
可见,以上功能不存在错误处理。如果尝试以下操作,它将崩溃:
1。在表格边界之外插值。
2。输入表中已经存在的查找值,导致选择的点数少于16。
我也承认以下几点:
1。命名约定可能会更好
2。创建遮罩功能的方法可能更快捷
函数 findclose()显示为原始问题。
如果您有任何反馈或需要改进的地方,请告诉我。