Python平均表格数据帮助
好的,我有下面的工作程序。它打开一个列中的数据文件,该列对于excel来说太大,并查找每列的平均值: 样本数据为:Python平均表格数据帮助,python,Python,好的,我有下面的工作程序。它打开一个列中的数据文件,该列对于excel来说太大,并查找每列的平均值: 样本数据为: Joe Sam Bob 1 2 3 2 1 3 它回来了 Joe Sam Bob 1.5 1.5 3 这很好。问题是有些列的值为NA。我想跳过这个NA并计算剩余值的平均值 所以 应该输出为 Bobby 1.5 这是我在这里帮助建立的现有程序。感谢您的帮助 with open('C://avy.txt', "rtU") as f: columns = f
Joe Sam Bob
1 2 3
2 1 3
它回来了
Joe Sam Bob
1.5 1.5 3
这很好。问题是有些列的值为NA。我想跳过这个NA并计算剩余值的平均值
所以
应该输出为
Bobby
1.5
这是我在这里帮助建立的现有程序。感谢您的帮助
with open('C://avy.txt', "rtU") as f:
columns = f.readline().strip().split(" ")
numRows = 0
sums = [0] * len(columns)
for line in f:
# Skip empty lines
if not line.strip():
continue
values = line.split(" ")
for i in xrange(len(values)):
sums[i] += int(values[i])
numRows += 1
with open('c://finished.txt', 'w') as ouf:
for index, summedRowValue in enumerate(sums):
print>>ouf, columns[index], 1.0 * summedRowValue / numRows
现在我有这个:
以open('C://avy.txt',“rtU”)作为f:
上面写着:
回溯(最近一次呼叫最后一次):
文件“C:/avy10.py”,第11行,在
lino+=1
名称错误:未定义名称“lino”将最内部的循环更改为:
values = line.split(" ")
for i in xrange(len(values)):
if values[i] == "NA":
continue
sums[i] += int(values[i])
numRows += 1
更小的代码:
with open('in', "rtU") as f:
lines = [l for l in f if l.strip()]
names = '\t'.join(lines[0].split())
numbers = [[i.strip() for i in line.split()] for line in lines[1:]]
person_data = zip(*numbers)
person_data = [tuple(int(i) for i in t if i!="NA") for t in person_data]
averages = map(lambda x: str(float(sum(x))/len(x)), person_data)
with open('out', 'w') as f:
f.write(names)
f.write('\n')
f.write('\t'.join(averages))
在约翰·梅钦发表评论后,我对这一点进行了测试。针对他的评论:
3
,并将其读入Python,则需要在进行算术运算之前将字符串转换为数字
现在,您有了一个带有colums的文本文件。每列都有一个标题和一组项。每个项目要么是一个数字,要么不是。如果它是一个数字,它将被函数float
正确转换,如果它不是一个有效的数字(即,如果转换不存在),转换将引发一个名为ValueError
的异常
因此,您可以循环浏览您的列表和项目,正如在多个答案中正确解释的那样。如果可以转换为float,则累积统计信息。如果没有,继续忽略该条目
如果您需要更多关于什么是“duck typing”(一个范例,可以恢复为“为了许可而请求原谅更好”)的信息,请查看。如果你正在学习Python,你会经常听到这个术语
下面我介绍一个可以积累统计数据的类(你对平均值感兴趣)。可以为表中的每一列使用该类的实例
class Accumulator(object):
"""
Used to accumulate the arithmetic mean of a stream of
numbers. This implementation does not allow to remove items
already accumulated, but it could easily be modified to do
so. also, other statistics could be accumulated.
"""
def __init__(self):
# upon initialization, the numnber of items currently
# accumulated (_n) and the total sum of the items acumulated
# (_sum) are set to zero because nothing has been accumulated
# yet.
self._n = 0
self._sum = 0.0
def add(self, item):
# the 'add' is used to add an item to this accumulator
try:
# try to convert the item to a float. If you are
# successful, add the float to the current sum and
# increase the number of accumulated items
self._sum += float(item)
self._n += 1
except ValueError:
# if you fail to convert the item to a float, simply
# ignore the exception (pass on it and do nothing)
pass
@property
def mean(self):
# the property 'mean' returns the current mean accumulated in
# the object
if self._n > 0:
# if you have more than zero items accumulated, then return
# their artithmetic average
return self._sum / self._n
else:
# if you have no items accumulated, return None (you could
# also raise an exception)
return None
# using the object:
# Create an instance of the object "Accumulator"
my_accumulator = Accumulator()
print my_accumulator.mean
# prints None because there are no items accumulated
# add one (a number)
my_accumulator.add(1)
print my_accumulator.mean
# prints 1.0
# add two (a string - it will be converted to a float)
my_accumulator.add('2')
print my_accumulator.mean
# prints 1.5
# add a 'NA' (will be ignored because it cannot be converted to float)
my_accumulator.add('NA')
print my_accumulator.mean
# prints 1.5 (notice that it ignored the 'NA')
干杯。以下代码正确处理不同的计数,并检测额外的数据。。。换句话说,它相当健壮。如果文件为空(1)如果标题行为空,则可以通过显式消息(2)进行改进。另一种可能性是显式测试
“NA”
,如果字段既不是“NA”
也不是可浮动的,则发出错误消息
>>> import sys, StringIO
>>>
>>> data = """\
... Jim Joe Billy Bob
... 1 2 3 x
... 2 x x x 666
...
... 3 4 5 x
... """
>>>
>>> def get_averages(f):
... headers = f.readline().split()
... ncols = len(headers)
... sumx0 = [0] * ncols
... sumx1 = [0.0] * ncols
... lino = 1
... for line in f:
... lino += 1
... values = line.split()
... for colindex, x in enumerate(values):
... if colindex >= ncols:
... print >> sys.stderr, "Extra data %r in row %d, column %d" %
(x, lino, colindex+1)
... continue
... try:
... value = float(x)
... except ValueError:
... continue
... sumx0[colindex] += 1
... sumx1[colindex] += value
... print headers
... print sumx1
... print sumx0
... averages = [
... total / count if count else None
... for total, count in zip(sumx1, sumx0)
... ]
... print averages
编辑在此处添加:
... return headers, averages
...
>>> sio = StringIO.StringIO(data)
>>> get_averages(sio)
Extra data '666' in row 3, column 5
['Jim', 'Joe', 'Billy', 'Bob']
[6.0, 6.0, 8.0, 0.0]
[3, 2, 2, 0]
[2.0, 3.0, 4.0, None]
>>>
编辑
正常使用:
with open('myfile.text') as mf:
hdrs, avgs = get_averages(mf)
以下是一个功能解决方案:
text = """Joe Sam Bob
1 2 3
2 1 3
NA 2 3
3 5 NA"""
def avg( lst ):
""" returns the average of a list """
return 1. * sum(lst)/len(lst)
# split that text
parts = [line.split() for line in text.splitlines()]
#remove the headers
names = parts.pop(0)
# zip(*m) does something like transpose a matrix :-)
columns = zip(*parts)
# convert to numbers and leave out the NA
numbers = [[int(x) for x in column if x != 'NA' ] for column in columns]
# all left is averaging
averages = [avg(col) for col in numbers]
# and printing
for name, x in zip( names, averages):
print name, x
我在这里写了很多列表理解,所以你可以打印出中间步骤,但这些步骤可能是原因的生成器。这显然是错误的-因为它不能解释某些数据序列变得比其他数据序列小。-1需要为每列单独计数;使用int()而不是float()在过去,我对使用这种技术犹豫不决,因为我的主要语言是C#,这里的异常非常昂贵。在Python中,虽然这执行得很顺利,但更清楚地传达了代码的目标。我曾经遇到过完全相同的问题,这也是我的解决方案。-1错误地为每列使用固定的numRows;应该为每一列保留一个单独的计数。@John Machin:如果你注意到我的评论,我指定的想法是将其转换为
float
,或者在不可能的情况下继续。当然,循环的相关部分需要对每个要转换的项执行此操作。我从未指定此代码是复制粘贴的,我是在用代码传达想法。正如你所注意到的,提问者很好地理解了这一点,遗憾的是你没有。@Arrieta:“你可以在没有任何限制的情况下改变你的循环的相关部分?”???唯一的要求?如何减少实例数?询问者没有对你的回答发表评论;你怎么知道他“理解得很好”?我不知道阿里塔的答案是什么。如果我在编程方面那么熟练,我就不会在这里了。-1(1)不是失去情节,而是未能获得情节;这将在“NA”作为数据项首次出现时消失在一个洞中(2)“averages=”开头的语句过于模糊(3)person\u data=zip(numbers)
是胡说八道,因为numbers=lines[1://code>(4)。readlines()
是多余的这需要我手动输入数据吗?数据很长。我不想那样做。我不能像在旧代码中那样打开文件吗?不,它不需要手动键入数据。使用StringIO
仅仅是因为我想显示函数工作,而不需要单独的输入文件。我特意编写了答案,以便您可以对任何打开的文件类对象使用get\u averages
函数。请参阅我的编辑(它向函数添加了一个返回值)。现在尝试它,结果显示此行的语法无效:@Robert:哪行的语法无效?print>>sys.stderr,“第%d行第%d列的额外数据%r”%(x,lino,colindex+1)我认为这是最优雅的解决方案。@wok:优雅的解决方案不会检测到数据问题。具有列表理解的优雅解决方案通常会将内存浪费在数据的多个副本上(其大小已经让OP担心)。
with open('myfile.text') as mf:
hdrs, avgs = get_averages(mf)
text = """Joe Sam Bob
1 2 3
2 1 3
NA 2 3
3 5 NA"""
def avg( lst ):
""" returns the average of a list """
return 1. * sum(lst)/len(lst)
# split that text
parts = [line.split() for line in text.splitlines()]
#remove the headers
names = parts.pop(0)
# zip(*m) does something like transpose a matrix :-)
columns = zip(*parts)
# convert to numbers and leave out the NA
numbers = [[int(x) for x in column if x != 'NA' ] for column in columns]
# all left is averaging
averages = [avg(col) for col in numbers]
# and printing
for name, x in zip( names, averages):
print name, x