【问题标题】:Nested defaultdict - Error when updating value嵌套的 defaultdict - 更新值时出错
【发布时间】:2020-05-02 08:35:02
【问题描述】:

我有一本名为dQalpha 的字典和另一本名为dQbeta 的字典,它们分别计算工人的经验dQalpha[worker] 和一个项目的难度dQbeta[example]

我现在想添加一个名为 dQgamma 的新指标,它使用嵌套的默认字典 dQgamma[worker][example] 来计算工作人员和项目的相关性。

但是,如果我说 self.dQgamma=defaultdict(lambda: defaultdict(dict)),我会收到错误消息

TypeError: float() argument must be a string or a number

如果我说self.dQgamma=defaultdict(lambda: defaultdict(list)),我会收到此错误消息

ValueError: setting an array element with a sequence.

有人可以帮忙吗?这是代码:

self.dQalpha={}
self.dQbeta={}
self.dQgamma=defaultdict(lambda: defaultdict(dict))


der = np.zeros_like(x)
i = 0
for worker in self.workers:
    der[i] = -self.dQalpha[worker] 
    i = i + 1
for example in self.examples:
    der[i] = -self.dQbeta[example] 
    i = i + 1
for worker in self.workers:
    for example in self.examples:
        der[i] = self.dQgamma[worker][example] #VALUE ERROR HERE
        i = i + 1

return der

更新

如果我说 self.dQgamma=defaultdict(lambda: defaultdict(der.dtype)) ,我会得到 ​​p>

NameError: global name 'der' is not defined

编辑

  def gradientQ(self, dtype):

        self.optimize_df(x)
        self.dQalpha={}
        self.dQbeta={}
        self.dQgamma=defaultdict(lambda: defaultdict(x.dtype)) 
        #ERROR TypeError: first argument must be callable

        for example, worker_label_set in self.e2wl.items():
            dQb = 0
            for (worker, label) in worker_label_set:
                for tlabel in self.prior.keys():
                    sigma = self.sigmoid(self.alpha[worker]*self.expbeta(self.beta[example]))
                    delta = self.kronecker_delta(label,tlabel)
                    dQb = dQb + self.e2lpd[example][tlabel]*(delta-sigma)*self.alpha[worker]*self.expbeta(self.beta[example])\
                          *self.expgamma(self.gamma[worker][example])
            self.dQbeta[example] = dQb - (self.beta[example] - self.priorbeta[example])

        for worker, example_label_set in self.w2el.items():
            dQa = 0
            for (example, label) in example_label_set:
                for tlabel in self.prior.keys():
                    sigma = self.sigmoid(self.alpha[worker]*self.expbeta(self.beta[example]))
                    delta = self.kronecker_delta(label,tlabel)
                    dQa = dQa + self.e2lpd[example][tlabel]*(delta-sigma)*self.expbeta(self.beta[example])\
                          *self.expgamma(self.gamma[worker][example])

            self.dQalpha[worker] = dQa - (self.alpha[worker] - self.prioralpha[worker])


        for worker, example_label_set in self.w2el.items():
            for example, worker_label_set in self.e2wl.items():
                dQg = 0
                for tlabel in self.prior.keys():
                    sigma = self.sigmoid(self.alpha[worker]*self.expbeta(self.beta[example])*\
                                         self.expgamma(self.gamma[worker][example]))
                    delta = self.kronecker_delta(label, tlabel)
                    dQg = dQg + self.e2lpd[example][tlabel]*(delta-sigma)*self.alpha[worker]*self.expbeta(self.beta[example])\
                          *self.expgamma(self.gamma[worker][example])

            self.dQgamma[worker][example] = dQg - (self.gamma[worker][example] - self.priorgamma[worker][example])

def optimize_df(self,x):
    # unpack x
    i=0
    for worker in self.workers:
        self.alpha[worker] = x[i]
        i = i + 1

    for example in self.examples:
        self.beta[example] = x[i]
        i = i + 1

    for worker in self.workers:
        for example in self.examples:
            self.gamma[worker][example] = x[i]
            i = i + 1


    self.gradientQ(x.dtype)

    # pack x
    der = np.zeros_like(x)
    i = 0
    for worker in self.workers:
        der[i] = -self.dQalpha[worker] #Flip the sign since we want to minimize
        i = i + 1
    for example in self.examples:
        der[i] = -self.dQbeta[example] #Flip the sign since we want to minimize
        i = i + 1
    for worker in self.workers:
        for example in self.examples:
            der[i]= self.dQgamma[worker][example] #Flip the sign since we want to minimize #TODO: fix
            i = i + 1
    return der

【问题讨论】:

  • defaultdict(lambda: defaultdict(dict)) 会给你一个defaultdict,其中包含defaultdicts,其中包含dicts。当您执行self.dQgamma[worker][example] 时,您将获得dict 对象(或在第二种情况下为list 对象),而der[i] 需要一个浮点值,因此会出现错误。如果您希望dQgamma 成为包含defaultdicts 的float 值的defaultdict,则执行defaultdict(lambda: defaultdict(float))(如果您想存储x 具有的任何数据类型的值,甚至是defaultdict(lambda: defaultdict(x.dtype)))。
  • 感谢您的评论。你知道如何解决出现的NameError: global name 'der' is not defined吗?
  • 那是因为您没有在第二个 sn-p 中定义任何 der 变量。
  • 我在名为optimize_df 的第二个函数中将其定义为der = np.zeros_like(x),但在第一个函数中,如果我在定义dQalpha、dQbeta、dQgamma 之后执行此操作,则找不到@987654354 @然后我不知道该怎么办

标签: python arrays dictionary nested defaultdict


【解决方案1】:

self.dQgamma[worker][example] 返回的值是字典或列表(取决于您如何声明它)。

您尝试将其影响到一个需要标量的 numpy 数组。 这就是你有错误的原因。

您应该声明 dQgamma 以使其返回与您的数组兼容的值:

self.dQgamma=defaultdict(lambda: defaultdict(der.dtype.type))

编辑

在下面的所有cmets之后,我更新了我的答案。

首先,实际上是numpy.dtype 对象不可调用,您必须检索其type 可调用的属性。 所以我编辑了上面的代码块以匹配正确的语法。

然后,这是一个完整的示例,说明如何在函数中使用数组的类型(我更改了一些命名以匹配 PEP8 约定。

from collections import defaultdict

import numpy as np

class MyClass:
    def gradient(self, dtype):
        self.d_qgamma=defaultdict(lambda: defaultdict(dtype.type))

        print("Unset first level value:", self.d_qgamma[0])
        print("Unset second level value:", self.d_qgamma[0][0])

        self.d_qgamma['a'] = defaultdict(dtype.type, {'z': dtype.type(42)})
        print("Set first level value:", self.d_qgamma['a'])

        self.d_qgamma['b']['a'] = dtype.type("42")
        print("Set second level value:", self.d_qgamma['b']['a'])

        print("d_qgamma:", self.d_qgamma)

    def optimize_df(self, x):
        self.gradient(x.dtype)

        der = np.zeros_like(x)
        der[0] = self.d_qgamma['b']['a']
        return der

if __name__ == '__main__':
    print("der:", MyClass().optimize_df(np.zeros(4, np.float32)))
Unset first level value: defaultdict(<class 'numpy.float32'>, {})
Unset second level value: 0.0
Set first level value: defaultdict(<class 'numpy.float32'>, {'z': 42.0})
Set second level value: 42.0
d_qgamma: defaultdict(<function MyClass.gradient.<locals>.<lambda> at 0x7fcfd1663050>, {0: defaultdict(<class 'numpy.float32'>, {0: 0.0}), 'a': defaultdict(<class 'numpy.float32'>, {'z': 42.0}), 'b': defaultdict(<class 'numpy.float32'>, {'a': 42.0})})
der: [42.  0.  0.  0.]

如您所见,您将numpy.dtype 类型的x.dtype 传递给您的gradient 函数。 然后,您可以使用此dtype 对象并检索其可调用的type 属性:

  • 将其传递给您的 defaultdict 构造函数

    self.d_qgamma=defaultdict(lambda: defaultdict(dtype.type))

  • 投射任何你想存储的值

    self.d_qgamma['b']['a'] = dtype.type("42")

    这里的字符串"42"被转换为float,值为42.0

【讨论】:

  • 好吧,这是有道理的,虽然我还有另一个问题可能很愚蠢,但它说NameError: global name 'der' is not defined。因为我在一个函数中定义self.dQgamma=defaultdict(lambda: defaultdict(der.dtype)),然后在另一个函数中计算der。我更新了我的问题,以便您看到它的样子。
  • @joasa 这和你的代码在全球范围内的使用更相关……你事先知道x的类型和der的类型。如果是,请将der.dtype 替换为此类型。否则,您必须重新考虑您的代码,将xder 传递给gradientQ 或类似的东西,以便能够在需要时知道类型。
  • 我编辑了代码。在我的gradientQ 中,我想调用另一个函数optimize_df,但问题是optimize_df 有一个参数(x),我不知道如何在gradientQ 函数中定义它。我的意思是,既然我打电话给optimize_df,它的 x 参数不应该自动正常吗?
  • @joasa 这不是正确的解决方案。 optimize_df 已经调用了gradientQ。在这里你有一个无限循环(gradientQ 调用optimize_df 调用gradientQ 等)。此外,您如何在gradientQ 中调用optimize_df(x) 而在gradientQ 中没有x?而是将gradientQ 重新定义为def gradientQ(dtype),在optimize_df 中将其调用为self.gradientQ(x.dtype),并使用gradientQ 中的dtype 参数来构建您的defaultdict
  • 我试过你的建议,如果我理解正确的话,现在我看到了这个错误TypeError: first argument must be callable。为什么它不可调用?
猜你喜欢
  • 2013-10-11
  • 2020-04-01
  • 1970-01-01
  • 2022-01-12
  • 2021-11-28
  • 2018-12-28
相关资源
最近更新 更多