Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在numpy数组中找到平衡点_Python_Arrays_Numpy - Fatal编程技术网

Python 在numpy数组中找到平衡点

Python 在numpy数组中找到平衡点,python,arrays,numpy,Python,Arrays,Numpy,考虑以下阵列: a = np.array([1,2,3,4,3,2,1]) 我想得到平均分割数组的元素,即元素前面的数组的和等于元素后面的数组的和。在这种情况下,第4个元素a[3]将数组平均分割。有没有更快的方法?还是我必须迭代所有元素 所需功能: f(a) = 3 我喜欢这样的东西: def equib(a): c = a.cumsum() return np.argmin(np.abs(c-(c[-1]/2))) 首先,我们构建a的累积和。Cumsum表示c[i]=s

考虑以下阵列:

a = np.array([1,2,3,4,3,2,1])
我想得到平均分割数组的元素,即元素前面的数组的和等于元素后面的数组的和。在这种情况下,第4个元素
a[3]
将数组平均分割。有没有更快的方法?还是我必须迭代所有元素

所需功能:

f(a) =  3

我喜欢这样的东西:

def equib(a):
    c = a.cumsum()
    return np.argmin(np.abs(c-(c[-1]/2)))
首先,我们构建
a
的累积和。Cumsum表示
c[i]=sum(a[:i])
。然后我们看绝对值,值和总重量之间的差值变得最小

更新@DSM注意到我的第一个版本有一点偏移,所以这里是另一个版本:

def equib(a):
    c1 = a.cumsum()
    c2 = a[::-1].cumsum()[::-1]
    return np.argmin(np.abs(c1-c2))

好吧,这是我得到的,但我不确定这是最快的方式:

def eq(a)
    c = np.cumsum(a)
    return sum(c <= c[-1]/2)
def均衡器(a)
c=np.累积和(a)

回报金额(c如果所有输入值都是非负的,那么最有效的方法之一似乎是构建一个累积和数组,然后在两边各用一半和对其进行二元搜索。然而,这样的二元搜索也很容易出错。在试图使二元搜索在所有边缘情况下都有效时,我最后做了以下测试:

class SplitpointTest(unittest.TestCase):
    def testFloatRounding(self):
        # Due to rounding error, the cumulative sums for these inputs are
        # [1.1, 3.3000000000000003, 3.3000000000000003, 5.5, 6.6]
        # and [0.1, 0.7999999999999999, 0.7999999999999999, 1.5, 1.6]
        # Note that under default settings, numpy won't display
        # enough precision to see that.
        self.assertEquals(2, splitpoint([1.1, 2.2, 1e-20, 2.2, 1.1]))
        self.assertEquals(2, splitpoint([0.1, 0.7, 1e-20, 0.7, 0.1]))

    def testIntRounding(self):
        self.assertEquals(1, splitpoint([1, 1, 1]))
    def testIntPrecision(self):
        self.assertEquals(2, splitpoint([2**60, 1, 1, 1, 2**60]))
    def testIntMax(self):
        self.assertEquals(
            2,
            splitpoint(numpy.array([40, 23, 1, 63], dtype=numpy.int8))
        )

    def testIntZeros(self):
        self.assertEquals(
            4,
            splitpoint(numpy.array([0, 1, 0, 2, 0, 2, 0, 1], dtype=int))
        )
    def testFloatZeros(self):
        self.assertEquals(
            4,
            splitpoint(numpy.array([0, 1, 0, 2, 0, 2, 0, 1], dtype=float))
        )
在决定不值得之前,我看了以下版本:

def splitpoint(a):
    c = numpy.cumsum(a)
    return numpy.searchsorted(c, c[-1]/2)
    # Fails on [1, 1, 1]

def splitpoint(a):
    c = numpy.cumsum(a)
    return numpy.searchsorted(c, c[-1]/2.0)
    # Fails on [2**60, 1, 1, 1, 2**60]

def splitpoint(a):
    c = numpy.cumsum(a)
    if c.dtype.kind == 'f':
        # Floating-point input.
        return numpy.searchsorted(c, c[-1]/2.0)
    elif c.dtype.kind in ('i', 'u'):
        # Integer input.
        return numpy.searchsorted(c, (c[-1]+1)//2)
    else:
        # Probably an object dtype. No great options.
        return numpy.searchsorted(c, c[-1]/2.0)
    # Fails on numpy.array([63, 1, 63], dtype=int8)

def splitpoint(a):
    c = numpy.cumsum(a)
    if c.dtype.kind == 'f':
        # Floating-point input.
        return numpy.searchsorted(c, c[-1]/2.0)
    elif c.dtype.kind in ('i', 'u'):
        # Integer input.
        return numpy.searchsorted(c, c[-1]//2 + c[-1]%2)
    else:
        # Probably an object dtype. No great options.
        return numpy.searchsorted(c, c[-1]/2.0)
    # Still fails the floating-point rounding and zeros tests.

如果我继续尝试的话,我可能会让它工作,但这不值得。chw21的第二个解决方案,基于显式最小化左右和之间的绝对差的解决方案,更容易推理,也更普遍适用。添加了
a=numpy.asarray(a)
,它通过了上述所有测试用例,还通过了以下测试,这些测试扩展了算法需要处理的输入类型:

class SplitpointGeneralizedTest(unittest.TestCase):
    def testNegatives(self):
        self.assertEquals(2, splitpoint([-1, 5, 2, 4]))
    def testComplex(self):
        self.assertEquals(2, splitpoint([1+1j, -5+2j, 43, -4+3j]))
    def testObjectDtype(self):
        from fractions import Fraction
        from decimal import Decimal
        self.assertEquals(2, splitpoint(map(Fraction, [1.5, 2.5, 3.5, 4])))
        self.assertEquals(2, splitpoint(map(Decimal, [1.5, 2.5, 3.5, 4])))
除非特别发现它太慢,否则我将使用chw21的第二种解决方案。在我测试它时稍微修改的形式中,这将是以下内容:

def splitpoint(a):
    a = np.asarray(a)
    c1 = a.cumsum()
    c2 = a[::-1].cumsum()[::-1]
    return np.argmin(np.abs(c1-c2))

我能看到的唯一缺陷是,如果输入有一个无符号的数据类型,并且没有精确分割输入的索引,那么该算法可能不会返回最接近分割输入的索引,因为
np.abs(c1-c2)
对无符号数据类型做的事情不正确。从未指定如果没有拆分索引,算法应该做什么,因此这种行为是可以接受的,尽管可能值得注意
np.abs(c1-c2)
和注释中未签名的数据类型。如果我们希望索引最接近于拆分输入,我们可以通过额外的运行时间获得它:

def splitpoint(a):
    a = np.asarray(a)
    c1 = a.cumsum()
    c2 = a[::-1].cumsum()[::-1]
    if a.dtype.kind == 'u':
        # np.abs(c1-c2) doesn't work on unsigned ints
        absdiffs = np.where(c1>c2, c1-c2, c2-c1)
    else:
        # c1>c2 doesn't work on complex input.
        # We also use this case for other dtypes, since it's
        # probably faster.
        absdiffs = np.abs(c1-c2)
    return np.argmin(absdiffs)
当然,这是对这种行为的测试,修改后的表单通过,而未修改的表单失败:

class SplitpointUnsignedTest(unittest.TestCase):
    def testBestApproximation(self):
        self.assertEquals(1, splitpoint(numpy.array([5, 5, 4, 5], dtype=numpy.uint32)))

你们可以从下面的代码中找到平衡点

    a = [1,3,5,2,2]
b = equilibirum(a)
n = len(a)
first_sum = 0
last_sum = 0
if n==1:
    print (1)
    return 0
for i in range(n):
    first_sum=first_sum+a[i]
    for j in range(i+2,n):
        last_sum=last_sum+a[j]
    if first_sum ==last_sum:
        s=i+2
        print (s)
        return 0
    last_sum=0

你的数组中有两个'3'。在我看来,也许你应该返回所需元素的索引,而不是它的值,只是为了知道哪个3是实际的平衡?在这个特定的例子中,它是:

f(a) = 4 # (because a[4] = 3)
而不是:

f(a) = 3
如果是这样的话,我的建议是如何定义适当的函数:

def equi(arr):
  length = len(arr)
  if length == 0: return -1
  if length == 1: return 0

  i = 1
  j = 0 

  # starting sum1 (the 'left' sum)
  sum1 = 0

  # starting sum2 (the 'right' sum)
  sum2 = sum(arr[1:])

  while j < length:
      if sum1 == sum2: return j
      if j == length-1:
        sum2 = 0
      else:
        sum1 += arr[j]
        sum2 -= arr[j+1]
      j += 1
  if sum1 != 0: return -1
def equi(arr):
长度=长度(arr)
如果长度==0:返回-1
如果长度==1:返回0
i=1
j=0
#起始sum1(“左”和)
sum1=0
#起始sum2(“正确”总和)
sum2=总和(arr[1:]
而j<长度:
如果sum1==sum2:返回j
如果j==长度-1:
sum2=0
其他:
sum1+=arr[j]
sum2-=arr[j+1]
j+=1
如果sum1!=0:返回-1

注:这是我第一次对堆栈溢出做出贡献,我是编程行乞者。如果我的解决方案不好,请随意评论!

几乎,你应该np.abs减法(否则你会得到最小的第一个元素)@agomcas我一按enter键就注意到了。更新后的版本在OP的示例中仍然返回2,而它应该返回3,因为它无法区分前2和第二个(我的意思是在
argmin
的参数中)。我建议使用
searchsorted
来搜索
c
for
c[-1]/2
。将chw21和user2357112:np.searchsorted(a.cumsum(),a.sum()/2.)结合起来,就为了你在一个答案中投入的工作量,我不得不给你投票;)这是一项了不起的工作。我为此向你致敬。我会接受这个答案,因为它是关于这个问题的最完整的解释。