【问题标题】:iterate function over list, and append the returned values在列表上迭代函数,并附加返回值
【发布时间】:2013-01-07 17:43:25
【问题描述】:

我有一个 CSV 数据集,40 列乘 800 行。 但作为一个例子,让我们说它看起来像这样:

Ref  X  Y
11   1  10 
11   2  9
11   3  8
11   4  7
12   5  6 
12   6  5
12   7  4
13   8  3
13   9  2

您将如何定义一个函数来返回每个 Ref 的平均 X 和 Y 值列表?即产生类似的东西:

Ref_list = [11,12,13]        
Av_X = [2.5,6,12.5]

我怀疑这是处理它的最佳方法,但我编写了以下代码:

my_data = genfromtxt('somedata.csv', delimiter=',',skiprows=1) 

X=[]
for i in my_data:
    X.append(i[0])
    counter=collections.Counter(X)
    keys=np.sort((counter.keys())) #find and sort ref key values

def getdata():
    X , Y = [], []
    for i in my_data:
       if i[0] == refs:
           X.append(i[1])
           Y.append(i[2])
    AV_X=np.average(X)
    AV_Y=np.average(X)
    return AV_X, AV_Y

for refs in keys: # run function over key range 
    AV_X, AV_Y = getdata()

我在这里卡住了,我试图在 ref no 的范围内迭代函数。 (键)并附加返回的值。但除了错误之外,我只能获得最后一个 Ref 的值。在键中。

我想有更好的方法可以做到这一点,但我还是这个东西的新手。 非常感谢您的任何建议

【问题讨论】:

    标签: python function counter average


    【解决方案1】:

    您可以将出色的 pandas 库用于此类工作:

    from StringIO import StringIO
    import pandas as pd
    
    df = pd.read_csv(StringIO('your_data'),
            delim_whitespace=True)
    
    df.groupby('Ref').mean()
    
           X    Y
    Ref          
    11   2.5  8.5
    12   6.0  5.0
    13   8.5  2.5
    

    正如您在最后一行中看到的,您的问题计算错误...

    你也可以问median, sum, max, etc..

    【讨论】:

    • 另外,您可以剪切StringIO并将其替换为文件路径。 df = read_csv('test.csv',delim_whitespace=True) df.groupby('Ref').mean()
    • @root 是的,正确,谢谢...最初我在字符串中输入了上面的内容,但为了清楚起见,我决定跳过这些行
    【解决方案2】:
    import csv, collections, operator
    def j(): return dict(X=[], Y=[])
    def mean(inlist): return operator.truediv(sum(inlist),len(inlist))
    a = collections.defaultdict(j)
    # get all the data
    for line in csv.DictReader(open(myfile, 'r')):
        a[line['Ref']]['X'].append(line['X'])
        a[line['Ref']]['Y'].append(line['Y'])
    
    
    # now, for the averages themselves
    
    def get_avgs(inputlist, xy):
        return [mean(a[item][xy]) for item in inputlist]
    

    用途:

    get_avgs([11,12,13], 'X')
    # returns:
    [2.5,6,12.5]
    

    【讨论】:

      【解决方案3】:
      >>> A=np.array([[11,1,10,],[11,2,9],[11,3,8],[11,4,7],[12,5,6,],[12,6,5],[12,7,4],[13,8,3],[13,9,2]])
      >>> A
      array([[11,  1, 10],
             [11,  2,  9],
             [11,  3,  8],
             [11,  4,  7],
             [12,  5,  6],
             [12,  6,  5],
             [12,  7,  4],
             [13,  8,  3],
             [13,  9,  2]])
      #Slice the data
      >>> A[:,0]
      array([11, 11, 11, 11, 12, 12, 12, 13, 13])
      >>> refs=np.unique(A[:,0])
      #Unique value of all references.
      >>> refs
      array([11, 12, 13])
      #To get the average of each column
      >>> np.average(A,axis=0)
      array([ 11.77777778,   5.        ,   6.        ])
      

      我想你想要这个?

      #Create a mask
      >>> A[:,0]==11
      array([ True,  True,  True,  True, False, False, False, False, False], dtype=bool)
      >>> Mask=A[:,0]==11
      >>> A[Mask]
      array([[11,  1, 10],
             [11,  2,  9],
             [11,  3,  8],
             [11,  4,  7]])
      >>> np.average(A[Mask],axis=0)
      array([ 11. ,   2.5,   8.5])
      >>> np.vstack([np.average(A[A[:,0]==x],axis=0) for x in ref])
      array([[ 11. ,   2.5,   8.5],
             [ 12. ,   6. ,   5. ],
             [ 13. ,   8.5,   2.5]])
      

      所以最后你可以拥有:

      >>> refs=np.unique(A[:,0])
      array([11, 12, 13])
      >>> np.vstack([np.average(A[A[:,0]==x],axis=0) for x in ref])
      array([[ 11. ,   2.5,   8.5],
             [ 12. ,   6. ,   5. ],
             [ 13. ,   8.5,   2.5]])
      

      有一种更好的方法可以通过引入更高维矩阵来避免列表理解。

      【讨论】:

        【解决方案4】:

        如果您愿意,您可以一次完成所有操作,而无需先进行排序。

        counts = {}
        averages = {}
        for line in data_file:
            ref = line[0]
            data = map(float, line[1:])
            if ref not in counts:
                counts[ref] = 1
                averages[ref] = data
            else:
                counts[ref] += 1
                averages[ref] = map(lambda running, new: ((running * (counts[ref] - 1)) + new) / counts[ref], averages[ref], data)
        

        您可以将defaultdict 用于countsaverages,但我认为在这种情况下它并不能真正帮助清晰或简洁。

        如果你分 2 次完成它可能会更有效率,但仍然没有排序。

        counts = {}
        totals = {}
        for line in data_file:
            ref = line[0]
            data = map(float, line[1:])
            if ref not in counts:
                counts[ref] = 1
                totals[ref] = data
            else:
                counts[ref] += 1
                totals[ref] = map(lambda running, new: running + new, averages[ref], data)
        averages = {ref : map(lambda total: total / counts[ref], totals[ref]) for ref in counts}
        

        【讨论】:

          【解决方案5】:

          对于低于几十万行的任何内容,我什至不会为 numpy 烦恼......为什么不直接使用它:

          #assuming your data is a list of lists and you want the average of the 2nd column
          avg = sum(x[1] for x in mydata) / len(mydata)
          

          当然,如果您只想要匹配某个表达式的所有项目的平均值,请使用列表推导来过滤数据,然后计算结果列表的平均值:

          my_specific_data = [x[1] for x in mydata if x[0] == refs]
          #... avg as above
          

          【讨论】:

            猜你喜欢
            • 2020-07-26
            • 2014-09-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-11-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多