使用pandas处理实时传入数据的最佳/ pythonic方法是哪种?
我每隔几秒就会收到以下格式的数据点:
{'time' :'2013-01-01 00:00:00', 'stock' : 'BLAH',
'high' : 4.0, 'low' : 3.0, 'open' : 2.0, 'close' : 1.0}
我想将它附加到现有的DataFrame,然后对其进行一些分析。
问题是,只是使用DataFrame.append追加行可能会导致所有复制的性能问题。
有些人建议预先分配一个大型DataFrame并在数据进入时进行更新:
In [1]: index = pd.DatetimeIndex(start='2013-01-01 00:00:00', freq='S', periods=5)
In [2]: columns = ['high', 'low', 'open', 'close']
In [3]: df = pd.DataFrame(index=t, columns=columns)
In [4]: df
Out[4]:
high low open close
2013-01-01 00:00:00 NaN NaN NaN NaN
2013-01-01 00:00:01 NaN NaN NaN NaN
2013-01-01 00:00:02 NaN NaN NaN NaN
2013-01-01 00:00:03 NaN NaN NaN NaN
2013-01-01 00:00:04 NaN NaN NaN NaN
In [5]: data = {'time' :'2013-01-01 00:00:02', 'stock' : 'BLAH', 'high' : 4.0, 'low' : 3.0, 'open' : 2.0, 'close' : 1.0}
In [6]: data_ = pd.Series(data)
In [7]: df.loc[data['time']] = data_
In [8]: df
Out[8]:
high low open close
2013-01-01 00:00:00 NaN NaN NaN NaN
2013-01-01 00:00:01 NaN NaN NaN NaN
2013-01-01 00:00:02 4 3 2 1
2013-01-01 00:00:03 NaN NaN NaN NaN
2013-01-01 00:00:04 NaN NaN NaN NaN
另一种选择是建立一个dicts列表。只需将传入的数据附加到列表中并将其切片为较小的DataFrame即可完成工作。
In [9]: ls = []
In [10]: for n in range(5):
.....: # Naive stuff ahead =)
.....: time = '2013-01-01 00:00:0' + str(n)
.....: d = {'time' : time, 'stock' : 'BLAH', 'high' : np.random.rand()*10, 'low' : np.random.rand()*10, 'open' : np.random.rand()*10, 'close' : np.random.rand()*10}
.....: ls.append(d)
In [11]: df = pd.DataFrame(ls[1:3]).set_index('time')
In [12]: df
Out[12]:
close high low open stock
time
2013-01-01 00:00:01 3.270078 1.008289 7.486118 2.180683 BLAH
2013-01-01 00:00:02 3.883586 2.215645 0.051799 2.310823 BLAH
或类似的东西,可能会稍微处理一下输入。
答案 0 :(得分:15)
我会按如下方式使用HDF5 / pytables:
实际上,我定义的函数使用每个"键的列表"这样您就可以在同一个过程中将多个DataFrame存储到HDF5存储中。
我们定义了一个函数,您可以使用每行d
来调用它:
CACHE = {}
STORE = 'store.h5' # Note: another option is to keep the actual file open
def process_row(d, key, max_len=5000, _cache=CACHE):
"""
Append row d to the store 'key'.
When the number of items in the key's cache reaches max_len,
append the list of rows to the HDF5 store and clear the list.
"""
# keep the rows for each key separate.
lst = _cache.setdefault(key, [])
if len(lst) >= max_len:
store_and_clear(lst, key)
lst.append(d)
def store_and_clear(lst, key):
"""
Convert key's cache list to a DataFrame and append that to HDF5.
"""
df = pd.DataFrame(lst)
with pd.HDFStore(STORE) as store:
store.append(key, df)
lst.clear()
注意:我们使用with语句在每次写入后自动关闭商店。 可能可以更快地保持开放,但如果是这样it's recommended that you flush regularly (closing flushes)。另请注意,使用collections deque而不是列表可能更具可读性,但此处列表的性能会略好一些。
要使用此功能,请拨打:
process_row({'time' :'2013-01-01 00:00:00', 'stock' : 'BLAH', 'high' : 4.0, 'low' : 3.0, 'open' : 2.0, 'close' : 1.0},
key="df")
注意:" df"是pytables商店中使用的存储key。
作业完成后,请确保store_and_clear
剩余的缓存:
for k, lst in CACHE.items(): # you can instead use .iteritems() in python 2
store_and_clear(lst, k)
现在可以通过以下方式获得完整的DataFrame:
with pd.HDFStore(STORE) as store:
df = store["df"] # other keys will be store[key]
len(df)
)。此外,要获取最新的读取,您可以定义一个get方法,用于在读取之前存储和清除。通过这种方式,您可以获得最新的数据:
def get_latest(key, _cache=CACHE):
store_and_clear(_cache[key], key)
with pd.HDFStore(STORE) as store:
return store[key]
现在访问时使用:
df = get_latest("df")
你会得到最新的" df"可用。
另一个选项是稍微更多参与:在vanilla pytables中定义自定义表,请参阅tutorial。
注意:您需要知道字段名称才能创建column descriptor。
答案 1 :(得分:9)
您实际上是在尝试解决两个问题:捕获实时数据和分析数据。第一个问题可以通过专为此目的而设计的Python logging来解决。然后通过读取相同的日志文件可以解决另一个问题。