在Python中更新numpy数组数据结构

时间:2015-12-02 17:57:34

标签: arrays python-2.7 numpy data-structures

我在更新数据结构时遇到了一些问题,无法找出原因。

我有这个数据结构:

USER_EVENT_PAIR_NUMPY_DATA_TYPE = numpy.dtype([('user_id', numpy.int64, 1), ('dated_id', numpy.int64, 1),
                                          ('preference_value', numpy.float64, 1),
                                          ('weighted_preference_value', numpy.float64, 1),
                                          ('date_type', numpy.int8, 1),
                                          ('user_rating', numpy.int8, 1),
                                          ('pair_met_at_event_round_num', numpy.int16, 1),
                                          ('match_type', numpy.int8, 1)])

我创建了一个数组:

arr = numpy.empty([0,1],dtype=USER_EVENT_PAIR_NUMPY_DATA_TYPE)

我会定期向其中添加行:

row = numpy.array([(dater1.get_user_key,    #User1ID
                            dater2.get_user_key,    #User2ID
                            Dater1PreferenceVal,    #Initial preference value
                            0.0,                    #Weighted preference value
                            DateType,               # Date type
                            0,                      # User rating
                            -1,                     # Pair met at event round
                            0)],                    # Match type
                          dtype=USER_EVENT_PAIR_NUMPY_DATA_TYPE)

eupm = numpy.row_stack((eupm, row))

然后,稍后,我想修改特定用户对的值(user_id和dated_id的组合)。但是,当我这样做时,它不会更改数组中的值。如果我在此set语句之前和之后打印数组中的值,则它是相同的。它成功地从数组中读取现有值。我错过了什么?

eupm[(eupm[:]['user_id'] == user1.get_user_key) & (eupm[:]['dated_id'] == user2.get_user_key)][0][2] = PreferenceVal

谢谢!

1 个答案:

答案 0 :(得分:0)

(先看)

如果您对eupm之后的row_stack感到满意,那么该部分代码就不是问题所在。您没有向我们展示关键部分 - 您如何尝试更改值。

  

然后,稍后,我想修改特定用户对的值(user_id和dated_id的组合)。但是,当我这样做时,它不会更改数组中的值。

此代码丢失。

您是否尝试同时修改两个字段,例如

eupm[['user_id','dated_id']][row_select] = ('new','value')

索引多个字段尚未完全开发。您可以阅读这些值,但无法对其进行修改。您必须一次更改一个字段,或更改整个记录。

你的代码不完整,所以我只是做了一个有根据的猜测。

===================================

(第2次详细介绍)

您的row定义包含对未知值的引用。因此,我必须插入自己的值来进行切割粘贴。那是不好的形式。如果您愿意,可以轻松复制结果。

在您的测试中,[:]是多余的:

In [163]: eupm[:]['user_id']
Out[163]: array([[123]], dtype=int64)

eupm['user_id']就足够了。

现在我实际上试图复制你的结果,我发现最后一个表达式实际上是赋值,而不是测试。像这样的长表达难以阅读。

eupm[(eupm[:]['user_id'] == user1.get_user_key) & (eupm[:]['dated_id'] == user2.get_user_key)][0][2] = PreferenceVal

这里有一些东西,希望更具可读性:

In [167]: mask=(eupm['user_id'] == 123) & (eupm['dated_id'] == 123)

In [168]: mask
Out[168]: array([[ True]], dtype=bool)

In [169]: eupm[mask]
Out[169]: 
array([(123L, 123L, 123.0, 0.0, 123, 0, -1, 0)], 
      dtype=[('user_id', '<i8'), ('dated_id', '<i8'), ('preference_value', '<f8'), ('weighted_preference_value', '<f8'), ('date_type', 'i1'), ('user_rating', 'i1'), ('pair_met_at_event_round_num', '<i2'), ('match_type', 'i1')])

所以我发现了一个满足2 id条件的元素。

In [170]: eupm[mask][0]
Out[170]: (123L, 123L, 123.0, 0.0, 123, 0, -1, 0)

所以这就取消了第一张唱片

In [171]: eupm[mask][0][2]
Out[171]: 123.0

第3场。我会使用字段名称:

In [174]: eupm[mask][0]['preference_value']
Out[174]: 123.0

最后你尝试了一项任务:

In [172]: eupm[mask][0][2]=1000

没有变化:

In [173]: eupm
Out[173]: 
array([[(123L, 123L, 123.0, 0.0, 123, 0, -1, 0)]], 
      dtype=[('user_id', '<i8'), ('dated_id', '<i8'), ('preference_value', '<f8'), ('weighted_preference_value', '<f8'), ('date_type', 'i1'), ('user_rating', 'i1'), ('pair_met_at_event_round_num', '<i2'), ('match_type', 'i1')])

这里的问题是eupm[mask]是副本,而不是视图。

使用视图的例子是:

In [176]: eupm[:1][0]['preference_value']=1000

In [177]: eupm
Out[177]: 
array([[(123L, 123L, 1000.0, 0.0, 123, 0, -1, 0)]], ...)

任何时候使用布尔掩码索引数组都会获得副本,并且必须非常小心使用第二个索引。

arr[mask][0] = ...   # does not work

我认为你需要做的是获取行号和索引:

In [180]: idx=numpy.where(mask)    
In [181]: idx
Out[181]: (array([0]), array([0]))  # eupm is (1,1) (2d)
In [182]: idx=idx[0][0]  # 2d makes selecting the index more complicated

正确索引:

In [187]: eupm[idx,0]['preference_value']=2000

你真的需要将arr初始化为(0,1)形状吗? 2D?您的复杂dtype已经提供了伪二维结构。

我意识到我的答案很长而且有点散漫,但那是现实生活调试的本质。

====================

您还可以先按字段索引(这会创建一个视图):

eupm['preference_value'][mask]=3000

但您仍然无法为此额外申请[0]