【问题标题】:Convert an array of objects into an array of arrays with Python使用 Python 将对象数组转换为数组数组
【发布时间】:2021-08-20 19:11:16
【问题描述】:

我有一个大型 .csv 数据库,其列名 VELOCITY 包含 3D 速度矢量。

VELOCITY 列的每个元素的格式为:'(v1, v2, v3)'

读取我使用的数据:

df = pd.read_csv('database.csv')
df = pd.DataFrame(df)

现在,我尝试定义一个velocity_array,其中每个元素都是3D 速度向量。

velocity_array = np.asarray(df['VELOCITY'])

我得到这样的东西:

['(a1, a2, a3)',
 '(b1, b2, b3)',
 '(c1, c2, c3)',
 .
 .
 .
 '(z1, z2, z3)']

这不是我需要的。我需要有一组 3D 速度数组。像这样的:

[[a1, a2, a3],
 [b1, b2, b3],
 [c1, c2, c3],
 .
 .
 .
 [z1, z2, z3]]

这样我就可以通过调用 velocity_array[i] 来恢复 3D 速度数组。

感谢任何帮助,谢谢!

#=====

只需添加(按要求):

df.head() 看起来像这样:

     SC_VELOCITY                        EVENT_ID
0   (-7143.645, -825.2191, -2463.361)   388161
1   (-7143.645, -825.2191, -2463.361)   400028
2   (-7087.896, -1058.8871, -2533.3374) 415847
3   (-7024.463, -1291.3812, -2600.547)  527126
4   (-6953.418, -1522.4622, -2664.9265) 605939 

【问题讨论】:

  • 可以打印df.head() 并分享吗?
  • 您想将字符串元组转换为整数列表吗?
  • 嗨@Mstaino,我将添加 df.head(),谢谢!
  • 源数据框很可能在列中有元组,但是当保存到 csv 并重新加载时,它们变成了字符串。 csv 格式实际上是 2d(行和列),因此不能直接存储此类列的额外维度。 pandas 对带有 (python) 字符串的列使用对象 dtype

标签: python arrays pandas numpy


【解决方案1】:

从您的示例数据中可以看出,velocity_array 中的每个条目都有 2 个单引号将条目括起来,例如'(a1, a2, a3)'。因此,假设您的条目实际上是字符串条目。

如果是这样,您可以通过以下方式将列中的每个字符串转换为列表:

df['VELOCITY'] = df['VELOCITY'].str.strip("()").str.split(r',\s*')

结果:

velocity_array = np.asarray(df['VELOCITY'])

print(velocity_array)

输出:

[list(['a1', 'a2', 'a3']) list(['b1', 'b2', 'b3'])
 list(['c1', 'c2', 'c3']) list(['z1', 'z2', 'z3'])]

编辑:

如果您的 a1、a2 条目实际上是浮点数,并且您还希望将它们从字符串转换为浮点数,您可以使用:

velocity_array = df['VELOCITY'].str.strip("()").str.split(r',\s*', expand=True).astype(float).to_numpy()

结果:

基于您df.head()的样本数据:

print(velocity_array)

[[-7143.645   -825.2191 -2463.361 ]
 [-7143.645   -825.2191 -2463.361 ]
 [-7087.896  -1058.8871 -2533.3374]
 [-7024.463  -1291.3812 -2600.547 ]
 [-6953.418  -1522.4622 -2664.9265]]

【讨论】:

  • 嗨@SeaBeam,感谢您的回复。我尝试使用您的建议, df['VELOCITY'][0]=['a1', 'a2','a3'] 和 df['VELOCITY'][0][0] = 'a1' ;这些 cotes 仍然是个问题,因为我无法使用它们进行操作。
  • @Diving 请参阅我上面的编辑,了解将条目转换为数字的修改后的解决方案,以便您可以使用它们进行操作。请注意,使用eval 的解决方案有两个问题:1)对于大型数据集非常慢。 2) 如果您的输入数据来自外部来源,则存在安全问题。请谨慎使用该解决方案。
  • 嗨@SeaBean,感谢您的额外评论。我正在和你们一起学习。谢谢!
【解决方案2】:

有几种方法可以满足您的需要。只是为了添加答案,并通过您的输出假设您的数据框看起来像

'(1,2,3)'
'(3,4,5)'
...

你可以这样做:

from ast import literal_eval #python has an eval but it is not recommended due to potential security issues
df = pd.read_csv('database.csv') #no need to call pd.DataFrame, read_csv already does that
np.vstack(df.iloc[:,0].apply(literal_eval).values)

除了答案中提供的其他方法

【讨论】:

  • 用 vel_array = np.vstack(df_temp.iloc[:,0].apply(eval).values) ,我们得到 vel_array[0] = [a1, a2, a3],没有 cotes , 只有值。现在可以对元素进行操作:vel_array[0][0] + vel_array[0][1] = some_number。
  • 请注意,对您从文件 can be dangerous 读取的数据调用 eval。如果您的数组之一是"(1, os.remove('SOMETHING IMPORTANT', recursive=True), 3)",那么您会使用这种方法意外丢失数据
  • @Diving 如果你打算使用这个答案,请考虑使用ast 包的ast.literal_eval 而不是eval,如it is significantly less dangerous (though not entirely safe) than just plain old eval
  • @MichaelDelgado 好点。我更改了答案以反映您的评论
【解决方案3】:

查看强大的 pandas string operators

在这种情况下,series.str.stripseries.str.split 可以解决问题:

In [11]: df['velocity'].str.strip('()').str.split(', ', expand=True).to_numpy()
Out[11]:
array([['a1', 'a2', 'a3'],
       ['b1', 'b2', 'b3'],
       ['c1', 'c2', 'c3'],
       ['z1', 'z2', 'z3']], dtype=object)

如果你的数据其实是float类型,可以加.astype(float)将字符串转成float64:

In [12]: df['velocity'].str.strip('()').str.split(', ', expand=True).to_numpy().astype(float)
Out[12]:
array([[-7143.645 ,  -825.2191, -2463.361 ],
       [-7143.645 ,  -825.2191, -2463.361 ],
       [-7087.896 , -1058.8871, -2533.3374],
       [-7024.463 , -1291.3812, -2600.547 ],
       [-6953.418 , -1522.4622, -2664.9265]])

性能考虑

请注意,与ast.literal_eval 等逐行操作相比,对于较大的数组,向量化字符串运算符的速度要快得多。

对于一万行四列的数组:

In [23]: s = pd.DataFrame(np.random.random(size=(10000,4))).apply(lambda x: '({},{},{},{})'.format(x[0], x[1], x[2], x[3]), axis=1)

In [24]: s
Out[24]:
0       (0.9134272324343906,0.09784434338612968,0.1064...
1       (0.6171577052744037,0.552712839936354,0.684161...
2       (0.05253084132451025,0.6216173862765718,0.3920...
3       (0.39577548909770743,0.35020447632615737,0.632...
4       (0.4761450474353096,0.20003567087846386,0.2113...
                              ...
9995    (0.3618865364493633,0.4947066480156196,0.17413...
9996    (0.4083358148057057,0.09394431583700069,0.8712...
9997    (0.9466315666988651,0.4692990331960303,0.04969...
9998    (0.22868850839996946,0.4712850069678187,0.4834...
9999    (0.1525379507879958,0.6019087151036507,0.07105...
Length: 10000, dtype: object

pandas 字符串操作符快 10 倍以上

In [26]: %%timeit
    ...: np.vstack(s.apply(ast.literal_eval))
    ...:
    ...:
160 ms ± 13.1 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [27]: %%timeit
    ...: s.str.strip('()').str.split(', ', expand=True).to_numpy()
    ...:
    ...:
14.2 ms ± 704 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

【讨论】:

  • 嗨@Michael_Delgado,感谢您的回复。我尝试使用您的建议:``` vel = df['velocity'].str.strip('()').str.split(', ', expand=True).to_numpy() ``` 但是 vel [0]=['a1', 'a2','a3'] 和 vel[0][0] = 'a1' ;这些 cotes 仍然是个问题,因为我无法使用它们进行操作。
  • 嗨@Diving - 如果您的数据是数字,您应该在问题中指定。我的答案将答案保留为字符串,因为在您的示例中,数据是字符串。要将我提供的结果转换为浮点数,只需将.astype(float) 添加到命令中即可。
  • 太好了,@Michael_Delgado!再次感谢,我正在学习。很好的教训。
猜你喜欢
  • 2021-11-08
  • 2018-10-13
  • 2019-04-13
  • 2018-11-08
  • 2016-08-06
  • 2021-05-03
相关资源
最近更新 更多