应用于整个数据集的函数

3
手动定义 pq:
p = [[45.1024,7.7498],[45.1027,7.7513],[45.1072,7.7568],[45.1076,7.7563]]
q = [[45.0595,7.6829],[45.0595,7.6829],[45.0564,7.6820],[45.0533,7.6796],[45.0501,7.6775]]
  • 步骤 1 (fine)

正常的代码部分

def _c(ca, i, j, p, q):
    if ca[i, j] > -1:
        return ca[i, j]
    elif i == 0 and j == 0:
        ca[i, j] = np.linalg.norm(p[i]-q[j])
    elif i > 0 and j == 0:
        ca[i, j] = max(_c(ca, i-1, 0, p, q), np.linalg.norm(p[i]-q[j]))
    elif i == 0 and j > 0:
        ca[i, j] = max(_c(ca, 0, j-1, p, q), np.linalg.norm(p[i]-q[j]))
    elif i > 0 and j > 0:
        ca[i, j] = max(
            min(
                _c(ca, i-1, j, p, q),
                _c(ca, i-1, j-1, p, q),
                _c(ca, i, j-1, p, q)
            ),
            np.linalg.norm(p[i]-q[j])
            )
    else:
        ca[i, j] = float('inf')
    return ca[i, j]
  • 问题出在第二步
def frdist(p, q):

    # Remove nan values from p
    p = np.array([i for i in p if np.any(np.isfinite(i))], np.float64) # ESSENTIAL PART TO REMOVE NaN
    q = np.array([i for i in q if np.any(np.isfinite(i))], np.float64) # ESSENTIAL PART TO REMOVE NaN

    len_p = len(p)
    len_q = len(q)

    if len_p == 0 or len_q == 0:
        raise ValueError('Input curves are empty.')

    # p and q no longer have to be the same length
    if len(p[0]) != len(q[0]):
        raise ValueError('Input curves do not have the same dimensions.')

    ca = (np.ones((len_p, len_q), dtype=np.float64) * -1)

    dist = _c(ca, len_p-1, len_q-1, p, q)
    return(dist)

frdist(p, q)
0.09754839824415232

问题: 在步骤2中,如何将代码应用于给定的(再次是样本数据集。真实数据集非常大)数据集df:
    1           1.1     2           2.1     3           3.1     4           4.1     5           5.1
0   43.1024     6.7498  NaN         NaN     NaN         NaN     NaN         NaN     NaN         NaN
1   46.0595     1.6829  25.0695     3.7463  NaN         NaN     NaN         NaN     NaN         NaN
2   25.0695     5.5454  44.9727     8.6660  41.9726     2.6666  84.9566     3.8484  44.9566     1.8484
3   35.0281     7.7525  45.0322     3.7465  14.0369     3.7463  NaN         NaN     NaN         NaN
4   35.0292     7.5616  45.0292     4.5616  23.0292     3.5616  45.0292     6.7463  NaN 

通过取p的第一行和q的第二行,然后计算距离frdist(p,q)。然后再次将p作为第一行,但现在q是第三行。然后是1和3。

最终我应该得到一个大小为(rows, rows)且对角线为0的矩阵。因为本身的距离为0:

 0 1 2 3 4 5 ... 105
0 0
1   0
2     0
3       0  
4         0
5           0
...           0
105              0
1个回答

1

由于您的工作代码需要一个列表的列表作为参数,所以您需要将数据框的每一行转换为类似于示例中的pq的列表的列表。假设df是您的数据框,您可以按照以下方式进行操作:

def pairwise(it):
    a = iter(it)
    return zip(a, a)

ddf = df.apply(lambda x : [pair for pair in pairwise(x)], axis=1)

我从这个答案中使用了pairwise函数。

ddf是一个数据帧,其中每个元素都是像pq一样的列表。

然后你需要处理行索引的组合。看看itertools模块。根据你的需求,你可以使用product, permutationscombinations中的一个。

如果你想要做每个组合,你可以使用:

from itertools import product
idxpairs = product(ddf.index, repeat=2)

idxpairs 包含数据框中所有可能的索引对。您可以循环遍历它们。

您可以按照以下方式构建最终矩阵:

fmatrix = pd.DataFrame(index=ddf.index, columns=ddf.index)

for pp in idxpairs:
    fmatrix.loc[pp[0], pp[1]] = frdist(ddf.iloc[pp[0]], ddf.iloc[pp[1]])

现在这会对每个元素进行暴力计算。如果你有一个大的数据框,且预先知道最终矩阵具有一定的属性,如对角线为0且对称(我想 frdist(p, q) == frdist(q, p)),则可以通过使用例如combinations而不是product来避免重复计算,以节省时间。
from itertools import combinations
idxpairs = combinations(ddf.index, 2)

fmatrix = pd.DataFrame(index=ddf.index, columns=ddf.index)

for pp in idxpairs:
    res = frdist(ddf.iloc[pp[0]], ddf.iloc[pp[1]])
    fmatrix.loc[pp[0], pp[1]] = res
    fmatrix.loc[pp[1], pp[0]] = res

一个修正:''itertoos'' 应该是 ''itertools'',对吗? - Mamed
一切都运作正常。但有一个问题:您可以在我的p和q示例中看到,frdist0.09754839824415232。但是,当我将您的代码应用于真实数据集时,在那里我的前两行是我在这里说明的p和q的数字时,我的frdist0.0879574 - Mamed
是的,itertoos 是一个打字错误。已修复。 - Valentino
关于不同的结果,我不知道。请检查数字是否真的相同:我已经测试过了,使用frdist直接和我的解决方案都得到了相同的结果。 - Valentino
好的。谢谢。现在它可以工作了。我现在需要处理“RecursionError: maximum recursion depth exceeded in comparison”。 - Mamed
你的 _c 函数是递归的,它来自于那里。 - Valentino

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接