Python 整数的唯一有序比

Python 整数的唯一有序比,python,algorithm,sorting,Python,Algorithm,Sorting,我有两个连续整数的有序列表m=0,1。。。M和n=0,1,2。。。N.m的每个值都有一个概率pm,N的每个值都有一个概率pn。我试图找到唯一值r=n/m及其概率pr的有序列表。我知道,如果n=0,r是无限的,如果m=n=0,r甚至可以是未定义的 在实践中,我希望M和N的顺序都是2E4,这意味着最多4E8个r值-这意味着3gb的浮点(假设8字节/浮点) 对于这个计算,我编写了下面的python代码 其思想是迭代m和n,对于每个新的m/n,将其插入正确的位置,如果它还不存在,则将其概率添加到现有的数

我有两个连续整数的有序列表m=0,1。。。M和n=0,1,2。。。N.m的每个值都有一个概率pm,N的每个值都有一个概率pn。我试图找到唯一值r=n/m及其概率pr的有序列表。我知道,如果n=0,r是无限的,如果m=n=0,r甚至可以是未定义的

在实践中,我希望M和N的顺序都是2E4,这意味着最多4E8个r值-这意味着3gb的浮点(假设8字节/浮点)

对于这个计算,我编写了下面的python代码

其思想是迭代m和n,对于每个新的m/n,将其插入正确的位置,如果它还不存在,则将其概率添加到现有的数字中。我的假设是,在途中对事情进行分类比等到最后更容易

与0相关的案例将添加到循环的末尾

我使用的是分数类,因为我们处理的是分数

代码还跟踪m/n的每个唯一值的多重性

我已经测试了M=N=100,速度非常慢。是否有更好的方法来解决这个问题,或者有更有效的方法来处理代码

时间:

  • M=N=30:1秒
  • M=N=50:6秒
  • M=N=80:30秒
  • M=N=100:82秒
将numpy导入为np
从分数进口分数
导入时间#用于计时
开始时间=时间。时间()#计时
M、 N=6,4
mList,nList=np.arange(1,M+1),np.arange(1,N+1)#从1到M,稍后处理0
mProbList,nprobist=[1/(M+1)]*(M),[1/(N+1)]*(N)#概率,此处假设相等(非一般情况)
#稍后处理mn=0
pmZero,pnZero=1/(M+1),1/(N+1)#P(M=0)和P(N=0)
pNaN=pmZero*pnZero#P(0/0)=P(m=0)P(n=0)
pZero=pmZero*(1-pnZero)#P(0)=P(m=0)P(n!=0)
pInf=pnZero*(1-pmZero)#P(inf)=P(m!=0)P(n=0)
#r=m/n、P(r)和mult(r)的主列表
#从第一行开始,m=1
rList=[nList[:-1]]中n的分数(mList[0],n)#最小的第一个
rprobist=[mProbList[0]*nprobist[::-1]]中的nP的nP#从第一行开始
rMultList=[1]*len(rList)#每个元素的多重性
#主回路
对于m,zip中的mP(mList[1:],mProbList[1:]):
对于n,zip中的nP(nList[:-1],npoblist[:-1]):#选择一个n值
r、 rP,rMult=分数(m,n),mP*nP,1
对于范围内的i(len(rList)-1):#查看它在现有列表中的位置
如果rrList[-1]:
rList.append(r)
RPR义务附加(rP)
rMultList.append(1)
打破
#处理0
rList.insert(0,分数(0,1))
RPR义务插入(0,pZero)
rMultList.insert(0,N)
#对付英夫蒂
rList.append(np.Inf)
rProbList.append(pInf)
rMultList.append(M)
#处理未定案件
rList.append(np.NAN)
rProbList.append(pNaN)
rMultList.append(1)
打印(“……在%s秒内完成。”%round(time.time()-start\u time,2))
打印(“*************最终列表\nr”、“Prob”、“Mult”)
对于zip中的r、rP、rM(rList、rProbList、rMultList):打印(r、rP、rM)
打印(“*************支票”)
打印(“mList”,mList,“nList”,nList)
打印(“概率总和=”,np.Sum(rprobist))
打印(“多重总和=”,np.Sum(rMultList),“\t(M+1)*(N+1)=”,(M+1)*(N+1))
我认为“事情很慢”,因为您选择了一种已知的低效排序。单个列表插入是O(K)(后面的列表元素必须被替换,并且定期添加存储分配)。因此,完整列表插入排序是O(K^2)。对于您的表示法,即O((M*N)^2)

如果你想要任何一种合理的性能,研究并使用最广为人知的方法。最直接的方法是将非异常结果作为简单的列表理解,并对倒数第二个列表使用内置排序。只需添加
n=0
案例,就可以在O(K log K)时间内完成

在下面的表达式中,我假设了
m
n
概率的函数。 这是一种符号方便;您知道如何直接计算它们,如果愿意,可以替换这些表达式

data = [ (mProb(m) * nProb(n), Fraction(m, n))
       for n in range(1, N+1)
           for m in range(0, M+1) ]
data.sort()
data.extend([ # generate your "zero" cases here ])

基于@Prune的建议,我对代码进行了如下修改。它更容易阅读,并且在N=M=80时运行速度快了一个数量级(我省略了处理0的过程——将以与原始帖子相同的方式完成)。我想可能有办法进一步调整合并和转换回列表

# Do calculations
data = [(Fraction(m, n), mProb(m) * nProb(n)) for n in range(1, N+1) for m in range(1, M+1)]
data.sort()

# Merge duplicates using a dictionary
d = {}
for r, p in data:
    if not (r in d): d[r] = [0, 0]
    d[r][0] += p
    d[r][1] += 1

# Convert back to lists
rList, rProbList, rMultList = [], [], []
for k in d:
    rList.append(k)
    rProbList.append(d[k][0])
    rMultList.append(d[k][1])

谢谢你的建议。你是说重复应该在
data.sort()
之后处理,也就是说,一旦事情被排序,就要寻找连续的重复,添加概率,并去掉多余的?我会尝试list(set()),但看不出它会如何处理概率。这只是处理重复项的方法:合并和求和。抢手货无法确定frac在您的第一行中的作用,在下面的后续行动中忽略了它(也忽略了“零”案例)。将接受此作为ans
# Do calculations
data = [(Fraction(m, n), mProb(m) * nProb(n)) for n in range(1, N+1) for m in range(1, M+1)]
data.sort()

# Merge duplicates using a dictionary
d = {}
for r, p in data:
    if not (r in d): d[r] = [0, 0]
    d[r][0] += p
    d[r][1] += 1

# Convert back to lists
rList, rProbList, rMultList = [], [], []
for k in d:
    rList.append(k)
    rProbList.append(d[k][0])
    rMultList.append(d[k][1])