Pandas 列线相交
Pandas columns line intersection
我有一个 pandas 数据框,其中每一列代表从 1 到 0 的下降线的 y 值,索引代表 x 值。现在我有兴趣找到这些线与给定常数(线性插值)之间的交点。
所需输出示例:
>>> df = pd.DataFrame({'y1': [1, .7, .4, .1, 0],
'y2': [1, .9, .7, .3, 0],
'y3': [1, .6, .3, .2, 0],
'y4': [1, .7, .5, .3, 0]}, index=[0, 10, 20, 30, 40])
>>> xs = get_intersection(df, .5)
>>> xs
{'x1': 16.6667, # = scipy.interpolate.interp1d([.7, .4], [10, 20])(.5)
'x2': 25.0, # = interp1d([.7, .3], [20, 30])(.5)
'x3': 13.3332, # = interp1d([.6, .3], [10, 20])(.5)
'x4': 20} # No interpolation required
我的数据包含大约 400 行和 50.000 列。
可能的解决方案:
我发现 使用以下方法找到两条线之间的交点:
idx = np.argwhere(np.diff(np.sign(f - g)) != 0).reshape(-1) + 0
我认为这可以根据我的数据帧进行调整,但我不确定如何从这里开始:
>>> idx = np.argwhere(np.diff(np.sign(df - .5), axis=0) != 0)
>>> idx
array([[1, 0],
[1, 2],
[1, 3],
[2, 1],
[2, 3]], dtype=int64)
由于人们似乎误解了这个问题,我有兴趣找到这些要点:
可以通过线性插值最近的两个点找到。
解法:
B.M. 给了我正确方向的一步:
def get_intersection(df, c):
dfind = len(df) - df.loc[::-1].apply(np.searchsorted, args=(c,), raw=True)
result = {}
for i, v in enumerate(dfind):
result[df.columns.values[i]] = interp1d([df.iloc[v][i], df.iloc[v - 1][i]], [df.index[v], df.index[v - 1]])(.5)
return result
>>> get_intersection(df, .5)
{'y1': array(16.666666666666668), 'y2': array(25.0), 'y3': array(13.333333333333332), 'y4': array(20.0)}
由于您需要一维函数 (interp1d),因此循环与 pandas 函数一样清晰、易读且速度快。使用 np.searchsorted 找到好的段 :
d = dict()
ind=df.index.values
for k,v in df.iteritems():
y=v.values
i=len(y)-np.searchsorted(y[::-1],0.5) #indices
sl = slice(i-1,i+1)
d[k]= +scipy.interpolate.interp1d(v[sl],ind[sl])(.5)
print (pd.Series(d))
# y1 16.666667
# y2 25.000000
# y3 13.333333
# y4 20.000000
# dtype: float64
如果不存在交叉点,可能必须对此进行调整。
我有一个 pandas 数据框,其中每一列代表从 1 到 0 的下降线的 y 值,索引代表 x 值。现在我有兴趣找到这些线与给定常数(线性插值)之间的交点。
所需输出示例:
>>> df = pd.DataFrame({'y1': [1, .7, .4, .1, 0],
'y2': [1, .9, .7, .3, 0],
'y3': [1, .6, .3, .2, 0],
'y4': [1, .7, .5, .3, 0]}, index=[0, 10, 20, 30, 40])
>>> xs = get_intersection(df, .5)
>>> xs
{'x1': 16.6667, # = scipy.interpolate.interp1d([.7, .4], [10, 20])(.5)
'x2': 25.0, # = interp1d([.7, .3], [20, 30])(.5)
'x3': 13.3332, # = interp1d([.6, .3], [10, 20])(.5)
'x4': 20} # No interpolation required
我的数据包含大约 400 行和 50.000 列。
可能的解决方案:
我发现
idx = np.argwhere(np.diff(np.sign(f - g)) != 0).reshape(-1) + 0
我认为这可以根据我的数据帧进行调整,但我不确定如何从这里开始:
>>> idx = np.argwhere(np.diff(np.sign(df - .5), axis=0) != 0)
>>> idx
array([[1, 0],
[1, 2],
[1, 3],
[2, 1],
[2, 3]], dtype=int64)
由于人们似乎误解了这个问题,我有兴趣找到这些要点:
可以通过线性插值最近的两个点找到。
解法: B.M. 给了我正确方向的一步:
def get_intersection(df, c):
dfind = len(df) - df.loc[::-1].apply(np.searchsorted, args=(c,), raw=True)
result = {}
for i, v in enumerate(dfind):
result[df.columns.values[i]] = interp1d([df.iloc[v][i], df.iloc[v - 1][i]], [df.index[v], df.index[v - 1]])(.5)
return result
>>> get_intersection(df, .5)
{'y1': array(16.666666666666668), 'y2': array(25.0), 'y3': array(13.333333333333332), 'y4': array(20.0)}
由于您需要一维函数 (interp1d),因此循环与 pandas 函数一样清晰、易读且速度快。使用 np.searchsorted 找到好的段 :
d = dict()
ind=df.index.values
for k,v in df.iteritems():
y=v.values
i=len(y)-np.searchsorted(y[::-1],0.5) #indices
sl = slice(i-1,i+1)
d[k]= +scipy.interpolate.interp1d(v[sl],ind[sl])(.5)
print (pd.Series(d))
# y1 16.666667
# y2 25.000000
# y3 13.333333
# y4 20.000000
# dtype: float64
如果不存在交叉点,可能必须对此进行调整。