【问题标题】:Python - Combining For LoopsPython - 组合 For 循环
【发布时间】:2017-08-17 17:40:57
【问题描述】:

我有两个分别来自 2016 年和 2017 年的数据字典,它们具有相同的 5 个键。我想计算每个键值与其字典中值总和的百分比,然后将每个单独键的两个百分比加入标签。我已经设法在下面这样做了,但是我的方法需要大量的 for 循环并且看起来有些笨拙。我正在寻找压缩或重写我的代码的方法,以使其更高效。

UsersPerCountry, UsersPerPlatform, UsersPerPlatform2016, UsersPerPlatform2017 = Analytics.UsersPerCountryOrPlatform()

labels = []
sizes16 = []
sizes17 = []
sumc1 = 0
sumc2 = 0
percentages = []

for k, v in dict1.iteritems():
    sumv1 += v
for k, v in dict1.iteritems():
    v1 = round(((float(v) / sumc1) * 100), 1)
    percentages.append(v1)
    labels.append(k)
    sizes16.append(c)
for k, v in dict2.iteritems():
    sumv1 += v
for k, v in dict2.iteritems():
    v2 = round(((float(v) / sumc1) * 100), 1)
    percentages.append(v2)
    sizes17.append(c)
for i in range(5):
    labels[i] += (', ' + str(percentages[i]) + '%' + ', ' + str(percentages[i + 5]) + '%')

这是标签的样子:

编辑:我现在已经添加了变量声明。我认为关于将所有变量设置为空列表或 0 的散列线就足够了。

【问题讨论】:

  • 请贴出完整的代码sn-p。例如sumc1c 从未被声明...
  • 你考虑过使用Pandas吗?您可以将每个字典放入 pd.DataFrame 并使用 panda 的矢量化机制在两行中执行相同的计算。即df = pd.DataFrame(dict1)df2=pd.DataFrame(dict2),甚至将它们组合成一个df = pd.concat([df1,df2], keys = [2016,2017])

标签: python performance dictionary for-loop


【解决方案1】:

您可以使用 Panda 的数据框类来简化事情。我有点不确定你的百分比是如何计算的,所以可能需要稍微计算一下,否则,试试这个:

import pandas as pd

#convert data to DataFrame class
df1 = pd.DataFrame(dict1)
df2 = pd.DataFrame(dict2)

#compute the percentages
percnt1 = df1.sum(axis=0).div(df1.sum().sum())
percnt2 = df2.sum(axis=0).div(df2.sum().sum())

#to get the sum:
percnt1 + percnt2

这是一个例子:

## create a data frame:
import numpy as np
df1 = pd.DataFrame({'Android':np.random.poisson(10,100), 'iPhone':np.random.poisson(10,100), 
'OSX':np.random.poisson(10,100), 'WEBGL':np.random.poisson(10,100), 'Windows':np.random.poisson(10,100)})

In [11]: df1.head()
Out[11]:
   Android  OSX  WEBGL  Windows  iPhone
0       12   12      9        9       5
1        9    8     14        7      11
2       12   10      7       10      11
3       11   12      7       17       5
4       15   16     15       11      13

In [10]: df1.sum(axis=0).div(df1.sum(axis=0).sum())
Out[10]:
Android    0.205279
OSX        0.198782
WEBGL      0.200609
Windows    0.198376
iPhone     0.196954
dtype: float64

【讨论】:

    【解决方案2】:

    没有熊猫:

    您应该利用 Python 的一些内置特性和函数。在这里,我试图复制您正在做的事情,以使其更具 Pythonic。

    请注意,这是未经测试的,因为您没有提供完整的代码 sn-p(未声明 sumc1 和 c)。我根据我认为您正在尝试做的事情写了这篇文章。

    # Your size16/size17 lists appear to be full of the constant c
    # can use Pythons list replication operation
    sizes16 = [c]*len(dict1)
    sizes17 = [c]*len(dict2)
    
    # define function for clarity / reduce redundancy
    def get_percentages(l):
      s = sum(l)
      percentages = [ round(((float(n) / s)*100),1) for n in l ]  # percentages calculation is a great place for list comprehension
      return percentages
    
    # can grab the labels directly, rather than in a loop
    labels = dict1.keys()
    
    percentages1 = get_percentages(dict1.values())
    percentages2 = get_percentages(dict2.values())
    
    # no magic number 5
    for i in range(len(labels)):
      labels[i] += (', ' + str(percentages[i]) + '%' + ', ' + str(percentages[i + 5]) + '%')
    

    如果我对你在做什么有更好的了解,最后一行可以被清理掉。

    我没有仔细看,但是这段代码可能会额外运行一两次数据,所以它的效率可能会低一些。但是,IMO 的可读性要高得多。

    【讨论】:

      【解决方案3】:

      这是一种无需外部库的方法。你没有提到代码运行方式的任何问题,只是它的美学(有人可能会说这会影响它的运行方式)。无论如何,这看起来很干净:

      # Sample data
      d1 = {'a':1.,'b':6.,'c':10.,'d':5.}
      d2 = {'q':10.,'r':60.,'s':100.,'t':50.}
      
      # List comprehension for each dictionary sum
      sum1 = sum([v for k,v in d1.items()])
      sum2 = sum([v for k,v in d2.items()])
      
      # Using maps and lambda functions to get the distributions of each dictionary
      d1_dist = map(lambda x: round(x/sum1*100, 1), list(d1.values()))
      d2_dist = map(lambda y: round(y/sum2*100, 1), list(d2.values()))
      
      
      # Insert your part with the labels here (I really didn't get that part)
      
      >>> print(d1_dist)
      [4.5, 45.5, 27.3, 22.7]
      

      如果您想将字典中的原始键连接到这些新的分布值,只需使用:

      d1_formatted = dict(zip(list(d1.keys()), d1_dist))
      >>> print(d1_formatted)
      {'a': 4.5, 'c': 45.5, 'b': 27.3, 'd': 22.7}
      

      【讨论】:

        猜你喜欢
        • 2016-07-01
        • 2011-07-18
        • 2021-09-15
        • 2020-09-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多