尝试将 pandas df 转换为 np 数组,dtaidistance 改为计算列表

Trying to convert pandas df to np array, dtaidistance computes list instead

我正在尝试计算从 pandas 转换而来的 ndarray 的距离矩阵。我尝试将 pandas df 当前转换为这种格式:

move_df = 
        movement
0       [4, 3, 6, 2]
1       [5, 2, 3, 6, 2]
2       [4, 7, 2, 3, 6, 1]
3       [4, 4, 4, 3]
...     ...
33410   [2, 6, 3, 1, 8]
[33410 x 1 columns]

通过使用以下内容到 numpy ndarray:

1) m = move_df.to_numpy() 
2) m = pd.DataFrame(move_df.tolist()).values
3) m = [move_df.tolist() for i in move_df.columns]

这些转换中的每一个都会产生一个这种格式的 numpy 数组:

[[list([4, 3, 6, 2])]
 [list([5, 2, 3, 6, 2])]
 [list([4, 7, 2, 3, 6, 1])]
 [list([4, 4, 4, 3])]
 ...
 [list([2, 6, 3, 1, 8])]]

因此,当我尝试 运行 dtaidistance 矩阵时,出现以下错误:

d_m = dtw.distance_matrix(m)

TypeError: unsupported operand type(s) for -: 'list' and 'list'

但是,当我通过复制和粘贴使用上述任何方法创建的几个 numpy 数组来创建列表列表时,代码有效。但这在 long 运行 中是不可行的,因为数组超过 30k 行。在从 pandas df 到 numpy 数组的转换中我做错了什么吗?我用了

print(type(m)) 

它输出它是一个 numpy 数组,我已经知道我不能从列表中减去一个列表,因此出现错误。

编辑:
对于 move_df.head(10).to_dict()

{'movement': {0: [4, 3, 6, 2], 
  1: [5, 2, 3, 6, 2], 
  2: [4, 7, 2, 3, 6, 1], 
  3: [4, 4, 4, 3], 
  4: [3, 6, 2, 3, 3], 
  5: [6, 2, 1], 
  6: [1, 1, 1, 1],
  7: [7, 2, 3, 1, 1],
  8: [7, 2, 3, 2, 1],
  9: [6, 2, 3, 1]}}

假设你想用长度为 4 的列表组成一个数组:

m = df['movement'].str.len().eq(4)
a = np.array(df.loc[m, 'movement'].to_list())

输出:

array([[4, 3, 6, 2],
       [4, 4, 4, 3],
       [1, 1, 1, 1],
       [6, 2, 3, 1]])

使用的输入:

df = pd.DataFrame({'movement': [[4, 3, 6, 2],
                                [5, 2, 3, 6, 2],
                                [4, 7, 2, 3, 6, 1],
                                [4, 4, 4, 3], 
                                [3, 6, 2, 3, 3],
                                [6, 2, 1],
                                [1, 1, 1, 1],
                                [7, 2, 3, 1, 1],
                                [7, 2, 3, 2, 1],
                                [6, 2, 3, 1]]})

使用以下方法创建的数据框:

In [112]: df = pd.DataFrame({'movement': {0: [4, 3, 6, 2],
     ...:   1: [5, 2, 3, 6, 2],
     ...:   2: [4, 7, 2, 3, 6, 1],
     ...:   3: [4, 4, 4, 3],
     ...:   4: [3, 6, 2, 3, 3],
     ...:   5: [6, 2, 1],
     ...:   6: [1, 1, 1, 1],
     ...:   7: [7, 2, 3, 1, 1],
     ...:   8: [7, 2, 3, 2, 1],
     ...:   9: [6, 2, 3, 1]}})

有一个包含列表的 object dtype 列。从该列派生的数组是 object dtype:

In [121]: arr = df['movement'].to_numpy()
In [122]: arr
Out[122]: 
array([list([4, 3, 6, 2]), list([5, 2, 3, 6, 2]),
       list([4, 7, 2, 3, 6, 1]), list([4, 4, 4, 3]),
       list([3, 6, 2, 3, 3]), list([6, 2, 1]), list([1, 1, 1, 1]),
       list([7, 2, 3, 1, 1]), list([7, 2, 3, 2, 1]), list([6, 2, 3, 1])],
      dtype=object)

通过选择列,我得到一个一维数组,而不是你得到的二维数组。其他都一样

这不能转换成二维数字数据类型数组。对于大多数用途,我们可以将其视为列表列表。

In [123]: arr.tolist()
Out[123]: 
[[4, 3, 6, 2],
 [5, 2, 3, 6, 2],
 [4, 7, 2, 3, 6, 1],
 [4, 4, 4, 3],
 [3, 6, 2, 3, 3],
 [6, 2, 1],
 [1, 1, 1, 1],
 [7, 2, 3, 1, 1],
 [7, 2, 3, 2, 1],
 [6, 2, 3, 1]]

如果列表的长度都相同,或者如果我们选择一个子集,则可以构造一个二维数组:

In [125]: arr[[0,3,6,9]]
Out[125]: 
array([list([4, 3, 6, 2]), list([4, 4, 4, 3]), list([1, 1, 1, 1]),
       list([6, 2, 3, 1])], dtype=object)
In [126]: 
In [126]: np.stack(arr[[0,3,6,9]])
Out[126]: 
array([[4, 3, 6, 2],
       [4, 4, 4, 3],
       [1, 1, 1, 1],
       [6, 2, 3, 1]])

填充和切片也可用于强制列表匹配长度 - 但这可能意味着丢失信息。

但是不知道 dtw.distance_matrix 期望什么(看起来它想要一个二维数值数组),或者这些列表代表什么,我不能更进一步。

基本点是您的数据框包含长度不同的列表。

(此处为 dtaidistance 作者之一)

dtaidistance 包需要三种格式之一:

  • 一个二维 numpy 数组(根据定义,所有序列的长度都相同)
  • 一维 numpy.array 或 array.array 的 Python 列表。
  • Python 个 Python 个列表

在你的情况下你可以这样做:

series = move_df['movement'].to_list()
dtw.distance_matrix(series)

然后在列表列表上工作。

要使用快速 C 实现,需要一个数组(Numpy 或 std lib 数组)。如果你想保持不同的长度,你可以这样做

series = move_df['movement'].apply(lambda a: np.array(a, dtype=np.double)).to_list()
dtw.distance_matrix_fast(series)

请注意,在您的 move_df 数据结构上就地执行应用操作可能是有意义的,这样您只需执行一次,而无需跟踪两个几乎相同的数据结构。执行此操作后,to_list 调用就足够了。因此:

move_df['movement'] = move_df['movement'].apply(lambda a: np.array(a, dtype=np.double))
series = move_df['movement'].to_list()
dtw.distance_matrix_fast(series)

如果你想使用 2D numpy 矩阵,你需要截断或填充所有系列,使其与其他答案中解释的长度相同(因为 dtw 填充更常见,不会丢失信息)。

ps。这假设你想做单变量 DTW,多变量时间序列的 ndim 子包需要不同的数据结构。