假设我有一个很大的CSV文件,其中包含有关在指定日期和时间是否下雨的数据。一个玩具示例如下。
Day, Time, Rain
1, 0800, 1
1, 0818, 0
1, 0842, 1
1, 0900, 0
2, 0800, 0
2, 0822, 1
2, 0845, 1
2, 0900, 1
我希望编写代码来计算一天下雨的时间比例。我的计算方法如下(从当天的第二次观察开始):
例如,在第1天,下雨了30分钟(一半为0800至0818,一半为0818至0842,一半为0842和0900)。在第2天,下雨了49分钟(从0800到0822的一半时间,从0822到0900的降雨)。
如何在Python中快速执行此操作?我知道for line in file:
遍历每一行,但不存储前一行的内存。
答案 0 :(得分:4)
我将维护一个变量,保留最后看到的行,并在每次迭代时对其进行更新:
last_line = None
for line in lines:
# You need to change this to explicitly check against None if line can be empty
if not last_line:
# Handle no last line on the first iteration
# Use line and last_line
# Update the last line seen
last_line = line
您还可以在开始时将last_line
默认设置为有效值,这样就无需在循环中进行检查了。但是,这并不总是可行的。
可以想象有更复杂的方法,例如使用自己的版本压缩lines
,其中每个元素都偏移一个,但这可能要简单得多。
答案 1 :(得分:1)
[注意:如果这是一次性的,那么我建议使用Carcigenicate的答案]
这对于生成器和yield
语句很有用。以下函数将接受您的迭代器,并产生2元组的对,可根据需要使用该对。
生成器功能:
def lineandlast(listish, first=True, last=True):
iterator = iter(listish)
lastline = next(iterator)
if first:
yield lastline, None
for line in iterator:
yield line, lastline
lastline = line
if last:
yield None, lastline
示例:
for line, last in lineandlast([1,2,3,4,5]):
print(line, last)
输出:
1 None
2 1
3 2
4 3
5 4
None 5
注释:
有两个关键字参数first
和last
,可用于控制上述输出示例中第一项和最后一项的输出。
答案 2 :(得分:0)
您可以zip()
行,知道上一行和当前行。
演示:
with open('data.csv') as in_file:
# skip headers
next(in_file)
# convert _io_TextIOWrapper object to list
in_file = list(in_file)
# print out current and previous lines
for curr, prev in zip(in_file[1:], in_file):
print("CURRENT: %s, PREVIOUS: %s" % (curr.strip(), prev.strip()))
输出:
CURRENT: 1, 0818, 0, PREVIOUS: 1, 0800, 1
CURRENT: 1, 0842, 1, PREVIOUS: 1, 0818, 0
CURRENT: 1, 0900, 0, PREVIOUS: 1, 0842, 1
CURRENT: 2, 0800, 0, PREVIOUS: 1, 0900, 0
CURRENT: 2, 0822, 1, PREVIOUS: 2, 0800, 0
CURRENT: 2, 0845, 1, PREVIOUS: 2, 0822, 1
CURRENT: 2, 0900, 1, PREVIOUS: 2, 0845, 1
您还可以使用csv
库进行csv文件处理。
答案 3 :(得分:0)
您可以使用itertools.groupby
:
import itertools, csv, typing
from functools import reduce
def calculate_minutes(stats:typing.List[list]) -> int:
new_row = [(int(a), list(b)) for a, b in itertools.groupby(stats, key=lambda x:x[-1])]
result = 0
for i in range(len(new_row)-1):
[m, _start], [m1, _end] = new_row[i], new_row[i+1]
if any([m, m1]):
a, b = int(_start[-1][0]), int(_end[0][0])
result += abs((((int(str(a)[0])-int(str(b)[0]))*60)+int(str(a)[1:])-int(str(b)[1:]))//2)
if m and len(_start) > 1:
a, b = int(_start[-1][0]), int(_start[0][0])
result += abs(((int(str(a)[0])-int(str(b)[0]))*60)+int(str(a)[1:])-int(str(b)[1:]))
if m1 and len(_end) > 1:
a, b = int(_end[-1][0]), int(_end[0][0])
result += abs(((int(str(a)[0])-int(str(b)[0]))*60)+int(str(a)[1:])-int(str(b)[1:]))
return result
with open('filename.csv') as f:
data = list(csv.reader(f))
new_results = {a:[c for _, *c in b] for a, b in itertools.groupby(data[1:], key=lambda x:x[0])}
final_results = {a:calculate_minutes(b) for a, b in new_results.items()}
print(final_results)
输出:
{'1': 30, '2': 49}