【问题标题】:how to calculate number of items in per user groupby item如何计算每个用户分组项目中的项目数
【发布时间】:2011-08-07 05:41:59
【问题描述】:

我怎样才能输出这样的结果:

user    I   R   H
=================
atl001  2   1   0
cms017  1   2   1
lhc003  0   1   2

来自这样的列表:

atl001 I
atl001 I
cms017 H
atl001 R
lhc003 H
cms017 R
cms017 I
lhc003 H
lhc003 R
cms017 R

即我想计算每个用户的IHR 的数量。请注意,在这种特殊情况下,我不能使用 itertools 中的 groupby。在此先感谢您的帮助。干杯!!

【问题讨论】:

  • 我太老了,不能做家庭作业。这些是运行condor_q -format "%s " Owner -format "%s\n" 'ifThenElse(JobStatus==1,"I",ifThenElse(JobStatus==2,"R",ifThenElse(JobStatus==5,"H",string(JobStatus)))' 的部分结果,显示了现场的当前作业状态。我只是想总结每个用户的runningholdidle 工作。干杯!!

标签: python python-2.3


【解决方案1】:

作为提示:

使用嵌套字典结构来计算出现次数:

用户 -> 字符 -> 用户出现的字符

编写解析器代码并递增计数器并打印结果 由你决定......一个很好的练习。

【讨论】:

  • 不是每个人(尤其是我)都是像你这样的 Python 专家。我可以在 bash 中做到这一点,但我希望它在 python 中将该部分集成到我现有的代码中。不过感谢您的提示。干杯!!
  • 然后学习它...或在 bash 中进行。 Stackoverflow 不是关于编写我的代码 :)
  • 恕我直言,如果回复对您来说有问题,请不要回复;不管你知道什么,都留给自己。我从来没有要求你写我的代码,我只是要求一些建议,一个示例代码总是比你的“书中的理论”更好。我真的不需要从你那里知道我应该使用什么 - bash 或 python 或其他东西。如果你帮不上忙,那就不要,只会让事情变得更糟。如果我问了一个我应该首先问的问题,我向大家道歉。谢谢!
【解决方案2】:

好吧,无论如何,使用groupby 解决这个问题是没有意义的。首先,您的数据未排序(groupby 不会为您排序组),并且行非常简单。

在处理每一行时保持计数。我假设你不知道你会得到什么标志:

from sets import Set as set # python2.3 compatibility
counts = {} # counts stored in user -> dict(flag=counter) nested dicts
flags = set()
for line in inputfile:
    user, flag = line.strip().split()
    usercounts = counts.setdefault(user, {})
    usercounts[flag] = usercounts.setdefault(flag, 0) + 1
    flags.add(flag)

之后打印信息是迭代计数结构的问题。我假设用户名总是 6 个字符长:

flags = list(flags)
flags.sort()
users = counts.keys()
users.sort()
print "user  %s" % ('  '.join(flags))
print "=" * (6 + 3 * len(flags))
for user in users:
    line = [user]
    for flag in flags:
        line.append(counts[user].get(flag, 0))
    print '  '.join(line)

以上所有代码都未经测试,但应该大致可以工作。

【讨论】:

  • 用户名并不总是 6 个字符长,但我可以解决这个问题来打印输出。我已经有一个以特定格式打印标题(和结果)的功能,我认为你的代码适合在那里。完成后我会在这里报告。谢谢您的帮助。干杯!!
【解决方案3】:
data='''atl001 I
atl001 I
cms017 H
atl001 R
lhc003 H
cms017 R
cms017 I
lhc003 H
lhc003 R
cms017 R'''

stats={}
for i in data.split('\n'):
    user, irh = i.split()
    u = stats.setdefault(user, {})
    u[irh] = u.setdefault(irh, 0) + 1

print 'user  I  R  H'
for user in sorted(stats):
    stat = stats[user]
    print user, stat.get('I', 0), stat.get('R', 0), stat.get('H', 0) 

【讨论】:

  • @dugres:这是我做错的地方:u = stats.get(user, {})。由于sorted()(因为我使用的是v2.3),我无法运行您的脚本,但我可以从这里获取它。谢谢您的帮助。干杯!!
  • @MacUsers 你在u = stats.get(user, {})做错了什么意思@字典的方法get() 存在于Python 2.3 对了,你打算用多长时间的史前版本的Python?
  • @eyquem:使用 v2.3 根本不是 my plan。我们使用的网格中间件的某些部分与这个特定版本的 python 相关联。这是一个完整的生产系统,我们不允许升级/更改诸如 python、gcc、libstdc 等之类的东西。升级 python 可能不会破坏任何东西,但我不能冒险假设什么都不会发生。此外,没有可用于 RHEL5 的更高版本的 rpm 包。我们将在 6 月升级到 SL6 (RHEL6)。干杯!!
  • @MacUsers:python 在 RHEL5 中有 v2.4 版本。 yum whatprovides /usr/bin/python -> Repo: base; python-2.4.3-43.el5。 Python 2.4 有itertools.groupby()
  • @dugres 在您的代码中,stats 是一个字典,其元素是字典,它们都具有相同的键 'I'、'R'、'H'。我不喜欢包含这种占用内存的重复信息的数据结构。无论如何,如果我们不关心内存,你的代码很好,我赞成。 - 请注意,n = u.get(irh, 0)u[irh] = n+1 这两行可以替换为 u[irh] = u.setdefault(irh,0) + 1,因此您的代码会变得更短。
【解决方案4】:
data = 112*'cms017 R\n'

data = data + '''atl001 I
cms017 R
atl001 I
cms017 H
atl001 R
lhcabc003 H
cms017 R
lhcabc003 H
lhcabc003 R
cms017 R
cms017 R
cms017 R'''
print data,'\n'

stats = {}
d = {'I':0,'R':1,'H':2}
L = 0
for line in data.splitlines():
    user,irh = line.split()
    stats.setdefault(user,[0,0,0])
    stats[user][d[irh]] += 1
    L = max(L, len(user))

LL = len(str(max(max(stats[user])
                 for user in stats )))

cale = ' %%%ds %%%ds %%%ds' % (LL,LL,LL)
ch = 'user'.ljust(L) + cale % ('I','R','H')

print '%s\n%s' % (ch, len(ch)*'=')
print '\n'.join(user.ljust(L) + cale % tuple(stats[user])
                for user in sorted(stats.keys()))

结果

user        I   R   H
=====================
atl001      2   1   0
cms017      0 117   1
lhcabc003   0   1   2

.

还有:

data = 14*'cms017 R\n'

data = data + '''atl001 I
cms017 R
atl001 I
cms017 H
atl001 R
lhcabc003 H
cms017 R
lhcabc003 H
lhcabc003 R
cms017 R
cms017 R
cms017 R'''
print data,'\n'

Y = {}
L = 0
for line in data.splitlines():
    user,irh = line.split()
    L = max(L, len(user))
    if (user,irh) not in Y:
        Y.update({(user,'I'):0,(user,'R'):0,(user,'H'):0})
    Y[(user,irh)] += 1

LL = len(str(max(x for x in Y.itervalues())))

cale = '%%-%ds %%%ds %%%ds %%%ds' % (L,LL,LL,LL)
ch = cale % ('user','I','R','H')

print '%s\n%s' % (ch, len(ch)*'=')
li = sorted(Y.keys())
print '\n'.join(cale % (a[0],Y[b],Y[c],Y[a])
                for a,b,c in (li[x:x+3] for x in xrange(0,len(li),3)))

结果

user       I  R  H
==================
atl001     2  1  0
cms017     0 19  1
lhcabc003  0  1  2

.

PS:

用户名都用 L 个字符对齐

在我的代码中,为了避免塞巴斯蒂安的代码中的复杂性,在我的代码中,I、R、H 以相同数量的 LL 字符对齐,这是此列中所有结果的最大值

【讨论】:

  • @eyquem:你能解释一下这行:LL = len(str(max(max(stats[user]) for user in stats )))吗?像往常一样,我在for 所在的行上遇到了同样的“语法错误”。我不明白为什么每次你形成这样的一行时,我都会在完全相同的地方得到语法错误;我必须做错事才能理解它。知道我错过了什么吗?干杯!!
  • @MacUsers stats[user] for user in stats 依次为 [2,1,0][0,117,1][0,1 ,2] 然后 max(stats[user]) 连续为 2, 117, 2。因此 max(max(stats[user]) for user in stats ) 为 117 :它是观察到一个用户和一个用户的最大出现次数状态(在我的示例中为 cms017 和 R)。之后我感兴趣的是确定这个数字的书写长度,以证明所有用户的所有出现次数和相同宽度的所有状态(在我的示例中为 3 个字符)。
  • @MacUsers 您使用 Python 2.3 版本之一,并且生成器表达式仅在 Python 2.4 中引入:请参阅 python.org/dev/peps/pep-0289PEP 289 -- 生成器表达式 : "BDFL Pronouncements : This PEP is ACCEPTED for Py2.4" 括号之间的迭代是生成器表达式......你不能使用。在现代主义延迟到达的遥远土地上,您必须用生成器函数或列表推导替换生成器表达式。在本例中,写LL = len(str(max[max(stats[user]) for user in stats ]))
  • @eyquem :即使LL = len(str(max[max(stats[user]) for user in stats ])) 返回相同的“语法错误”。刚刚在 v2.4 上尝试了您的代码,它工作得很好。干杯!!
  • @MacUsers 你能成功写出理解列表吗?例如,定义li = [12,45,13,2,8,16,178,12,45,45],然后定义newli = [x for x in li if x<20]。它是否有效?顺便问一下,您使用的确切版本是什么: 2.3, 2.3.1 , 2.3.2 ...?
【解决方案5】:

这是一个变体,它使用嵌套字典来计算作业状态并在打印前计算最大字段宽度:

#!/usr/bin/env python
import fileinput
from sets import Set as set # python2.3

# parse job statuses
counter = {}
for line in fileinput.input():
    user, jobstatus = line.split()
    d = counter.setdefault(user, {})
    d[jobstatus] = d.setdefault(jobstatus, 0) + 1

# print job statuses
# . find field widths
status_names = set([name for st in counter.itervalues() for name in st])
maxstatuslens = [max([len(str(i)) for st in counter.itervalues()
                      for n, i in st.iteritems()
                      if name == n])
                 for name in status_names]
maxuserlen = max(map(len, counter))
row_format = (("%%-%ds " % maxuserlen) +
              " ".join(["%%%ds" % n for n in maxstatuslens]))
# . print header
header = row_format % (("user",) + tuple(status_names))
print header
print '='*len(header)
# . print rows
for user, statuses in counter.iteritems():
    print row_format % (
        (user,) + tuple([statuses.get(name, 0) for name in status_names]))

示例

$ python print-statuses.py <input.txt
user   I H R
============
lhc003 0 2 1
cms017 1 1 2
atl001 2 0 1

这是一个变体,它使用带有元组 (user, status_name) 作为键的平面字典:

#!/usr/bin/env python
import fileinput
from sets import Set as set # python 2.3

# parse job statuses
counter = {}
maxstatuslens = {}
maxuserlen = 0
for line in fileinput.input():
    key = user, status_name = tuple(line.split())
    i = counter[key] = counter.setdefault(key, 0) + 1
    maxstatuslens[status_name] = max(maxstatuslens.setdefault(status_name, 0),
                                     len(str(i)))
    maxuserlen = max(maxuserlen, len(user))

# print job statuses
row_format = (("%%-%ds " % maxuserlen) +
              " ".join(["%%%ds" % n for n in maxstatuslens.itervalues()]))
# . print header
header = row_format % (("user",) + tuple(maxstatuslens))
print header
print '='*len(header)
# . print rows
for user in set([k[0] for k in counter]):
    print row_format % ((user,) +
        tuple([counter.get((user, status), 0) for status in maxstatuslens]))

用法和输出是一样的。

【讨论】:

  • @J.F. Sebastian 请问什么叫 FLAT 字典?
  • @eyquem:嵌套:{'atl001': {'I': 2, 'R': 1}},平面:{('atl001', 'I'): 2, ('atl001', 'R'): 1}
  • @J.F.塞巴斯蒂安 好的,谢谢。这就是我在第二个解决方案中使用的:Y 是平面字典
  • @J.F. Sebastian,@eyquem:你们太棒了!我为你学到了很多东西;真的很感激。我正在检查你的代码,看看哪一个最适合我。干杯!!
  • @J.F. Sebastian:使用平面字典而不是嵌套字典有什么优势吗?干杯!!
猜你喜欢
  • 1970-01-01
  • 2021-02-13
  • 2020-12-27
  • 2018-06-22
  • 2011-02-27
  • 2021-10-28
  • 1970-01-01
  • 2012-07-23
  • 2011-12-27
相关资源
最近更新 更多