【问题标题】:Python - find average for columns with unique matching value in nested listPython - 在嵌套列表中查找具有唯一匹配值的列的平均值
【发布时间】:2013-04-16 13:44:06
【问题描述】:

这与这个问题非常相似:Finding minimum, maximum and average values for nested lists?

问题的重要区别和根源是我想在列表中(嵌套在列表中)为每个唯一列名(人名)找到最小值、最大值、平均值。

例如: 每一行基本上都是(具有相似的虚构名称)-

epochtime, name, score, level, extralives 

例如

    1234455, suzy, 120, 3, 0
    1234457, billy, 123, 1, 2
    1234459, billy, 124, 2, 4
    1234459, suzy, 224, 5, 4
    1234460, suzy, 301, 7, 1
    1234461, billy, 201, 3, 1

这些是按时间排列的:

if epochtime < 1234500 and epochtime > 1234400:
        timechunk1.append(line)

每个时间块都有一个列表列表:

listoflists = [timechunk1, timechunk2....]

对于这个问题,这可能会也可能不会过分杀伤力/无关紧要。

我如何找到每个唯一名称(billy 或 suzy)的每个字段(分数、级别、extralives)的最小值、最大值和平均值 - 除了 billy 或 suzy 之外,还有很多,所以应该是最好不要在每个列表(timechunk1,timechunk2)中单独列出它们

【问题讨论】:

  • 大概名称没有聚集在您的时间块中?
  • 没有。我曾想过用 sorted(alist, key=lambda player: player[1]) 重新排列列表 - 但没有 - 每个列表中的每个“名称”都有不同数量的项目(timechunk1 等)。

标签: python list unique identity-column


【解决方案1】:

pandas 示例:

>>> import pandas as pd
>>> df = pd.read_csv("grouped.csv", sep="[,\s]*")
>>> df
   epochtime   name  score  level  extralives
0    1234455   suzy    120      3           0
1    1234457  billy    123      1           2
2    1234459  billy    124      2           4
3    1234459   suzy    224      5           4
4    1234460   suzy    301      7           1
5    1234461  billy    201      3           1
>>> g = df.groupby("name").describe()
>>> g
                  epochtime       score  level  extralives
name                                                      
billy count        3.000000    3.000000    3.0    3.000000
      mean   1234459.000000  149.333333    2.0    2.333333
      std          2.000000   44.747439    1.0    1.527525
      min    1234457.000000  123.000000    1.0    1.000000
      25%    1234458.000000  123.500000    1.5    1.500000
      50%    1234459.000000  124.000000    2.0    2.000000
      75%    1234460.000000  162.500000    2.5    3.000000
      max    1234461.000000  201.000000    3.0    4.000000
suzy  count        3.000000    3.000000    3.0    3.000000
      mean   1234458.000000  215.000000    5.0    1.666667
      std          2.645751   90.835015    2.0    2.081666
      min    1234455.000000  120.000000    3.0    0.000000
      25%    1234457.000000  172.000000    4.0    0.500000
      50%    1234459.000000  224.000000    5.0    1.000000
      75%    1234459.500000  262.500000    6.0    2.500000
      max    1234460.000000  301.000000    7.0    4.000000

或者简单地说:

>>> df.groupby("name").mean()
       epochtime       score  level  extralives
name                                           
billy    1234459  149.333333      2    2.333333
suzy     1234458  215.000000      5    1.666667

然后:

>>> g.ix[("billy","mean")]
epochtime     1234459.000000
score             149.333333
level               2.000000
extralives          2.333333
Name: (billy, mean), dtype: float64
>>> g.ix[("billy","mean")]["score"]
149.33333333333334
>>> g["score"]
name        
billy  count      3.000000
       mean     149.333333
       std       44.747439
       min      123.000000
       25%      123.500000
       50%      124.000000
       75%      162.500000
       max      201.000000
suzy   count      3.000000
       mean     215.000000
       std       90.835015
       min      120.000000
       25%      172.000000
       50%      224.000000
       75%      262.500000
       max      301.000000
Name: score, dtype: float64

等等。如果您正在以 R/SQL 方式思考,但又想使用 Python,那么一定要试试 pandas。

注意你也可以做多列分组:

>>> df.groupby(["epochtime", "name"]).mean()
                 score  level  extralives
epochtime name                           
1234455   suzy     120      3           0
1234457   billy    123      1           2
1234459   billy    124      2           4
          suzy     224      5           4
1234460   suzy     301      7           1
1234461   billy    201      3           1

【讨论】:

  • 看起来不错,但 csv 并不特定于一个时间组 - 该程序按原样将行分成不同的时间块(如示例中所示)。我需要从列表中生成数据框或直接附加到数据框。 stackoverflow.com/questions/10715965/…
  • 以上内容更多是为了暗示。取决于你的分块是如何完成的——我不能从你的例子中完全概括——你也可以以矢量化的方式做到这一点。
  • 这是一个很好的例子。我只需要将列表(例如'timechunk1')转换为数据框或重组内容以直接附加到不同的数据框。
  • 我的经验是,如果我可以将数据保存在一起并使用列信息(例如 epochtimes)将数据分组到同一个数据框中,事情通常会更顺利。将事物分成不同的框架感觉就像拥有一个用于男性和女性的数据框等。不过,我还是试一试,看看会发生什么。
【解决方案2】:

您必须收集每个名称、每个字段的列表。

collections.defaultdict 与工厂一起使用来创建嵌套列表:

from collections import defaultdict

columns = ('score', 'level', 'extralives')

def per_user_data():
    return {k: [] for k in columns}

stats_per_timechunk = []

for timechunk in listoflists:
    # group data per user, per column (user -> {c1: [], c2: [], c3: []})
    data = defaultdict(per_user_data)    
    for userdata in timechunk:
        per_user = data[userdata[1]]
        for column, value in zip(columns, userdata[2:]):
            per_user[column].append(value)

    # collect min, max and average stats per user, per column 
    # (user -> {c1: {min: 0, max: 0, avg: 0}, ..})
    stats = {}

    for user, per_user in data.iteritems():
        stats[user] = {column: {
                'min': min(per_user[column]),
                'max': max(per_user[column]),
                'avg': sum(per_user[column]) / float(len(per_user[column])),
            } for column in columns}

    stats_per_timechunk.append(stats)

将您的示例输入数据转储到一个时间块中会给我:

>>> pprint(stats_per_timechunk)
[{'billy': {'extralives': {'avg': 2.3333333333333335, 'max': 4, 'min': 1},
            'level': {'avg': 2.0, 'max': 3, 'min': 1},
            'score': {'avg': 149.33333333333334, 'max': 201, 'min': 123}},
  'suzy': {'extralives': {'avg': 1.6666666666666667, 'max': 4, 'min': 0},
           'level': {'avg': 5.0, 'max': 7, 'min': 3},
           'score': {'avg': 215.0, 'max': 301, 'min': 120}}}]

也许您应该考虑使用不同的数据结构来代替所有这些列表,或者使用pandas 之类的东西来帮助您更有效地分析数据。

【讨论】:

  • 当然。我愿意接受建议。基本文件是一个 csv,其中每一行都与示例类似。是的,我在看它,并认为如果我使用 SQL 做事情可能会更容易,但如果可能的话,我想留在 Python 中。Pandas 的建议看起来不错。我也在 R 中做了一些这样的事情,但是 Python 中的 R 对我来说似乎很不直观。
  • 熊猫应该是你的下一个停靠港;它的既定目标是准确处理这种分析。
  • 我尝试了这个建议。但是我做错了,stats_per_time_chunk 返回了一个空字符串 {}, {}, {},
  • 这意味着data 是空的,这意味着timechunks 可能是空的?在代码中添加打印语句来解决这个问题。
  • @Donnied:你认真对待赏金吗?如果你不是也没关系! :-)
猜你喜欢
  • 2015-05-17
  • 2020-10-16
  • 1970-01-01
  • 2018-03-09
  • 1970-01-01
  • 1970-01-01
  • 2019-08-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多