4

我需要关于编程模式和 DataFrame 用于我们数据的建议。我们有数以千计的小型 ASCII 文件,这些文件是粒子跟踪实验的结果(详见 www.openptv.net)。每个文件都是在该时间实例中识别和跟踪的粒子列表。文件的名称是帧的编号。例如:

ptv_is.10000(即帧号 10000)

prev next   x    y   z   
-1    5     0.0  0.0 0.0 
0     0     1.0 1.0 1.0  
1     1      2.0  2.0 2.0 
2     2      3.0  3.0 3.0 
3    -2      4.0  4.0 4.0 

ptv_is.10001(下一个时间范围,10001)

1    2      1.1 1.0 1.0 
2    8      2.0  2.0 2.0 
3    14       3.0  3.0 3.0 
4   -2       4.0  4.0 4.0 
-1   3      1.5  1.12  1.32 
0   -2      0.0   0.0 0.0 

ASCII 文件的列是: prev - 是粒子在前一帧中的行号,next 是粒子在下一帧中的行号,x,y,z 是粒子的坐标。如果 'prev' 的行索引为 -1 - 粒子出现在当前帧中并且没有及时返回链接。如果'next'是-2,那么粒子在时间上没有向前的链接,轨迹在这一帧结束。

因此,我们将这些文件读入具有相同列标题的单个 DataFrame 中,再加上我们添加时间索引,即帧号

prev next   x    y   z   time
-1    5     0.0  0.0 0.0 10000
0     0     1.0 1.0 1.0  10000
1     1      2.0  2.0 2.0 10000
2     2      3.0  3.0 3.0 10000
3    -2      4.0  4.0 4.0 10000

1    2      1.1 1.0 1.0 10001 
2    8      2.0  2.0 2.0 10001
3    14       3.0  3.0 3.0 10001
4   -2       4.0  4.0 4.0 10001
-1   3      1.5  1.12  1.32 10001
0   -2      0.0   0.0 0.0 10001

现在的步骤是我发现很难找到使用 DataFrame 的最佳方式。如果我们可以添加一个额外的列,称为轨迹 ID,我们稍后可以通过时间(在单个时间实例中创建粒子的子组并学习它们的空间分布)或轨迹 ID 重新索引此 DataFrame,然后创建轨迹(或链接的粒子并了解它们在空间中的时间演化,例如相同轨迹 ID 的 x(t)、y(t)、z(t))。

如果输入是:

prev next   x    y   z   time
-1    5     0.0  0.0 0.0 10000
0     0     1.0 1.0 1.0  10000
1     1      2.0  2.0 2.0 10000
2     2      3.0  3.0 3.0 10000
3    -2      4.0  4.0 4.0 10000

1    2      1.1 1.0 1.0 10001 
2    8      2.0  2.0 2.0 10001
3    14     3.0  3.0 3.0 10001
4   -2      4.0  4.0 4.0 10001
-1   3      1.5  1.12  1.32 10001
0   -2      0.0   0.0 0.0 10001

那么我需要的结果是:

prev next   x    y   z   time   trajectory_id
-1    5     0.0  0.0 0.0 10000   1
0     0     1.0 1.0 1.0  10000   2
1     1     2.0  2.0 2.0 10000   3
2     2     3.0  3.0 3.0 10000   4
3    -2     4.0  4.0 4.0 10000  -999 

1    2      1.1 1.0 1.0 10001    2
2    8      2.0  2.0 2.0 10001   3
3    14     3.0  3.0 3.0 10001   4
-1   -2     4.0  4.0 4.0 10001   -999     
-1   3      1.5  1.1  1.3 10001  5
0   -2      0.0   0.0 0.0 10001   1

意思是:

prev next    x    y   z   time   trajectory_id
-1  5       0.0  0.0  0.0    10000  1      < - appeared first time, new id
0   0       1.0  1.0  1.0    10000  2      < - the same
1   1       2.0  2.0  2.0    10000  3    <- the same
2   2       3.0  3.0  3.0    10000  4       <- the same
3  -2       4.0  4.0  4.0    10000  -999   <-  sort of NaN, there is no link in the next frame

1    2      1.1 1.0 1.0   10001  2 <- from row #1 in the time 10000, has an id = 2
2    8      2.0  2.0 2.0  10001  3 <- row #2 at previous time, has an id = 3
3    14     3.0  3.0 3.0  10001  4 < from row # 3, next on the row #14, id = 4
-1   -2     4.0  4.0 4.0  10001  -999  <- but linked, marked as NaN or -999     
-1   3      1.5  1.1  1.3 10001  5  <- new particle, new id = 5 (new trajectory_id)
0   -2      0.0   0.0 0.0 10001  1   <- from row #0  id = 1

希望这能更好地解释我在寻找什么。唯一的问题是我不知道如何通过 DataFrame 表的行进行滚动函数,创建一个新的索引列轨迹_id。

例如,带有列表的简单应用程序如下所示:

http://nbviewer.ipython.org/7020209

感谢关于熊猫使用的每一个提示,亚历克斯

4

2 回答 2

1

整洁的!这个问题很贴近我的心;我还使用pandas 进行粒子跟踪。这与我处理的问题不完全相同,但这是一个未经测试的草图,它提供了一些有用的 pandas 习语。

results = []
first_loop = True
next_id = None
for frame_no, frame in pd.concat(list_of_dataframes).groupby('time'):
    if first_loop:
        frame['traj_id'] = np.arange(len(frame))
        results.append(frame)
        next_id = len(frame)
        first_loop = False
        continue
    prev_frame = results[-1]
    has_matches = frame['prev'] > 0  # boolean indexer
    frame[has_matches]['traj_'id'] = prev_frame.iloc[frame[has_matches]['prev']]
    count_unmatched = (~has_matches).sum()
    frame[~has_matches]['traj_'id'] = np.arange(next_id, next_id + count_unmatched)
    next_id += count_unmatched
    results.append(frame)
pd.concat(results)
于 2013-10-17T13:41:38.363 回答
0

如果我理解得很好,您想随时间跟踪空间中粒子的位置。您正在处理五个维度的数据,因此可能 DataFrame 它不是解决您的问题的最佳结构,您可能会考虑面板结构或数据减少。

以一个粒子为例,您有两种可能性,首先将坐标视为三个不同的值,因此您需要三个字段或将它们视为一个整体,例如元组或点对象。在第一种情况下,你有时间加上三个值,所以你有四个轴,你需要一个 DataFrame。在第二种情况下,您有两个轴,因此您可以使用系列。

对于多个粒子,只需使用particle_id 并将所有DataFrames 放在Panel 中或将Series 放在DataFrame 中。

一旦您知道要使用哪种数据结构,就该将数据放入其中了。

按顺序读取文件并制作“活”粒子的集合,例如:

{particle_id1: { time1: (x1,y1,z1), time2: (x2,y2,z2), ...}, ...}

当检测到新粒子时(上一个为-1)分配一个新的particle_id并放入集合中。当粒子“死亡”从集合中弹出并将数据放入系列中,然后将此系列添加到粒子 DataFrame(或 DataFrame / Panel)中。

您还可以创建粒子 id 和下一个字段的索引以帮助识别 id:

{ next_position_of_last_file: particle_id, ... }

或者

{ position_in_last_file: particle_id, ...}
于 2013-10-17T15:37:01.100 回答