将带有 numpy 数组列表的字典转换为 pandas 数据帧的最有效方法?
Most efficient way to convert a dictionary with list of numpy arrays into pandas dataframe?
我正在尝试使用 numpy 向量化在多个时间段内对多个股票代码进行批量计算,但我不确定我处理问题的方式是否最有效。我正在使用 "tulipy" 技术指标库对不同股票的 "Close" 价格进行计算。
这是源数据作为数据框的样子:
Ticker Date Close
0 A 1999-11-18 31.473534
1 A 1999-11-19 28.880543
2 A 1999-11-22 31.473534
3 A 1999-11-23 28.612303
4 A 1999-11-24 29.372318
这是可重现的代码:
d = {'Ticker': ['A','A','A','A','A','A','A','A','A','A','A','A','A','A','A'], 'Date': ['1999-11-18', '1999-11-19', '1999-11-22', '1999-11-23', '1999-11-24','1999-11-26', '1999-11-29', '1999-11-30', '1999-12-01', '1999-12-02','1999-12-03', '1999-12-06', '1999-12-07', '1999-12-08', '1999-12-09'], 'Close': ['31.473534','28.880543','31.473534','28.612303','29.372318','29.461731','30.132332','30.177038','30.713520','31.562946','31.831188','32.725323','32.367668','32.322960','32.770027']}
df = pd.DataFrame(data=d)
将对浮点数进行计算。
然后,我根据查询结果创建一个 numpy 数组,并找到要迭代的唯一值(代码)以用于索引目的:
import pandas as pd
import numpy as np
import tulipy as ti
a = np.array([(df['Ticker']),(df['Date']),(df['Close'])])
x_unique = np.unique(a[0], return_counts=True, return_index=True)
这是源数据作为 numpy 数组的样子:
array([['A', Timestamp('1999-11-18 00:00:00'), 31.473533630371094],
['A', Timestamp('1999-11-19 00:00:00'), 28.880542755126953],
['A', Timestamp('1999-11-22 00:00:00'), 31.473533630371094],
然后,我遍历每个唯一的代码并从 "tulipy" 技术指标库计算相对强度指数 (RSI),同时还维护每个价格数据点的相应日期,并存储这些值在字典中:
dictt = {}
start = 0
d = 0
for i in x_unique[0]:
dictt[i] = [ti.rsi(a[2, start:start+x_unique[2][d]].astype(float), 14), a[1, start:start+x_unique[2][d]]]
start = start+x_unique[2][d]
d+=1
所有这些工作正常并且非常快,但我觉得好像有一种 numpy 方法可以迭代每个唯一的自动收报机而不是使用 "for i in x_unique[0]",因为一旦我实施这可能会占用大量资源6,000 多个代码。这是字典 (dictt) 示例输出:
{'A': [array([54.98280996, 51.72842265, 53.80685853, ..., 71.42460267,
68.75692746, 65.20371964]),
array([Timestamp('1999-11-18 00:00:00'), Timestamp('1999-11-19 00:00:00'),
Timestamp('1999-11-22 00:00:00'), ...,
Timestamp('2019-11-27 00:00:00'), Timestamp('2019-11-29 00:00:00'),
Timestamp('2019-12-02 00:00:00')], dtype=object),
array([31.47353363, 30.89731344, 31.02536237, ..., 79.59926089,
79.85942439, 79.96844085]),
下一个问题是如何以最有效的方式将其放入 pandas 数据框 and/or 和 sql 数据库中,因为将数据变成可读的方式大多数脚本的低效率在于。这是我将其转换为 pandas 数据帧的输出,它不是我想要的所需格式:
pd.DataFrame(dict([ (k,pd.Series(v)) for k,v in dictt.items() ]))
A AAPL AEP AMAT ATVI
0 [54.98280995952094, 51.72842265345178, 53.8068... [64.49276119489626, 58.970440366273245, 54.374... [48.78048780487805, 38.63298662704309, 37.7864... [41.830064699495054, 45.295506922269944, 44.34... [45.23809231868367, 45.23809231868366, 58.8677...
1 [1999-11-18 00:00:00, 1999-11-19 00:00:00, 199... [1980-12-12 00:00:00, 1980-12-15 00:00:00, 198... [1970-01-02 00:00:00, 1970-01-05 00:00:00, 197... [1980-03-17 00:00:00, 1980-03-18 00:00:00, 198... [1993-10-25 00:00:00, 1993-10-26 00:00:00, 199...
2 [31.473533630371094, 30.897313435872395, 31.02... [0.5133928656578064, 0.5074404809210036, 0.494... [30.625, 30.708333333333332, 30.71759259259259... [0.0954861119389534, 0.09510030928585264, 0.09... [0.9375, 0.9212962918811374, 0.908693407788688...
我希望它输出如下:
rsi date ema8 ema20 ema50 ema100 ema200
A 54.9828 1999-11-18 31.4735 31.4735 31.4735 31.4735 31.4735
A 51.7284 1999-11-19 30.8973 31.2266 31.3718 31.4222 31.4477
所以我的主要问题是:
- 有没有更好的方法对此进行矢量化计算
数据集,同时保持股票代码的 order/matching,
日期及其计算值?
- 我可以不考虑将所有数据存储在字典中并保留
numpy 数组中的所有内容?
- 我可以直接将 numpy 数组中的值存储到 sql
本质上是表格的数据库或 pandas 数据框?
加入数据框上的日期和 rsi 的更新:
df_dictt = pd.DataFrame(dictt).T
output = pd.DataFrame()
for i in range(len(df_dictt)):
df_join = pd.DataFrame(df_dictt[1][i]).rename(columns={1:'date'}).join(pd.DataFrame(df_dictt[0][i]).rename(columns={0:'rsi'}), how='left')
df_join['rsi'] = df_join['rsi'].shift(14)
df_join['ticker'] = df_dictt.index[i]
output = output.append(df_join, ignore_index=False)
要制作字典,您应该使用 pandas DataFrame.groupby
而不是处理成数组然后遍历它们。
dictt = {ticker: ti.rsi(group["Close"], 14)
for ticker, group in df.groupby("Ticker")}
group["Close"]
将是一个 pandas 系列。如果 rsi
函数不接受这个,那么你可能需要添加类似 group["Close"].to_numpy(dtype=float)
的东西来将它们转换成 numpy 数组。
您可以将 rsi 值直接添加到数据框,一次一组,如下所示:
for _, group in df.groupby("Ticker"):
df.loc[group.index[14:], "rsi"] = ti.rsi(group["Close"], 14)
您也可以 apply
将函数分组,但在这种情况下,您需要每次都转换为 pandas 系列,以便保留索引:
def rsi(group, period):
return pd.Series(ti.rsi(group["Close"], period), index=group.index[period:])
df["rsi"] = df.groupby("Ticker").apply(rsi, 14).reset_index(level=0, drop=True)
我正在尝试使用 numpy 向量化在多个时间段内对多个股票代码进行批量计算,但我不确定我处理问题的方式是否最有效。我正在使用 "tulipy" 技术指标库对不同股票的 "Close" 价格进行计算。
这是源数据作为数据框的样子:
Ticker Date Close
0 A 1999-11-18 31.473534
1 A 1999-11-19 28.880543
2 A 1999-11-22 31.473534
3 A 1999-11-23 28.612303
4 A 1999-11-24 29.372318
这是可重现的代码:
d = {'Ticker': ['A','A','A','A','A','A','A','A','A','A','A','A','A','A','A'], 'Date': ['1999-11-18', '1999-11-19', '1999-11-22', '1999-11-23', '1999-11-24','1999-11-26', '1999-11-29', '1999-11-30', '1999-12-01', '1999-12-02','1999-12-03', '1999-12-06', '1999-12-07', '1999-12-08', '1999-12-09'], 'Close': ['31.473534','28.880543','31.473534','28.612303','29.372318','29.461731','30.132332','30.177038','30.713520','31.562946','31.831188','32.725323','32.367668','32.322960','32.770027']}
df = pd.DataFrame(data=d)
将对浮点数进行计算。
然后,我根据查询结果创建一个 numpy 数组,并找到要迭代的唯一值(代码)以用于索引目的:
import pandas as pd
import numpy as np
import tulipy as ti
a = np.array([(df['Ticker']),(df['Date']),(df['Close'])])
x_unique = np.unique(a[0], return_counts=True, return_index=True)
这是源数据作为 numpy 数组的样子:
array([['A', Timestamp('1999-11-18 00:00:00'), 31.473533630371094],
['A', Timestamp('1999-11-19 00:00:00'), 28.880542755126953],
['A', Timestamp('1999-11-22 00:00:00'), 31.473533630371094],
然后,我遍历每个唯一的代码并从 "tulipy" 技术指标库计算相对强度指数 (RSI),同时还维护每个价格数据点的相应日期,并存储这些值在字典中:
dictt = {}
start = 0
d = 0
for i in x_unique[0]:
dictt[i] = [ti.rsi(a[2, start:start+x_unique[2][d]].astype(float), 14), a[1, start:start+x_unique[2][d]]]
start = start+x_unique[2][d]
d+=1
所有这些工作正常并且非常快,但我觉得好像有一种 numpy 方法可以迭代每个唯一的自动收报机而不是使用 "for i in x_unique[0]",因为一旦我实施这可能会占用大量资源6,000 多个代码。这是字典 (dictt) 示例输出:
{'A': [array([54.98280996, 51.72842265, 53.80685853, ..., 71.42460267,
68.75692746, 65.20371964]),
array([Timestamp('1999-11-18 00:00:00'), Timestamp('1999-11-19 00:00:00'),
Timestamp('1999-11-22 00:00:00'), ...,
Timestamp('2019-11-27 00:00:00'), Timestamp('2019-11-29 00:00:00'),
Timestamp('2019-12-02 00:00:00')], dtype=object),
array([31.47353363, 30.89731344, 31.02536237, ..., 79.59926089,
79.85942439, 79.96844085]),
下一个问题是如何以最有效的方式将其放入 pandas 数据框 and/or 和 sql 数据库中,因为将数据变成可读的方式大多数脚本的低效率在于。这是我将其转换为 pandas 数据帧的输出,它不是我想要的所需格式:
pd.DataFrame(dict([ (k,pd.Series(v)) for k,v in dictt.items() ]))
A AAPL AEP AMAT ATVI
0 [54.98280995952094, 51.72842265345178, 53.8068... [64.49276119489626, 58.970440366273245, 54.374... [48.78048780487805, 38.63298662704309, 37.7864... [41.830064699495054, 45.295506922269944, 44.34... [45.23809231868367, 45.23809231868366, 58.8677...
1 [1999-11-18 00:00:00, 1999-11-19 00:00:00, 199... [1980-12-12 00:00:00, 1980-12-15 00:00:00, 198... [1970-01-02 00:00:00, 1970-01-05 00:00:00, 197... [1980-03-17 00:00:00, 1980-03-18 00:00:00, 198... [1993-10-25 00:00:00, 1993-10-26 00:00:00, 199...
2 [31.473533630371094, 30.897313435872395, 31.02... [0.5133928656578064, 0.5074404809210036, 0.494... [30.625, 30.708333333333332, 30.71759259259259... [0.0954861119389534, 0.09510030928585264, 0.09... [0.9375, 0.9212962918811374, 0.908693407788688...
我希望它输出如下:
rsi date ema8 ema20 ema50 ema100 ema200
A 54.9828 1999-11-18 31.4735 31.4735 31.4735 31.4735 31.4735
A 51.7284 1999-11-19 30.8973 31.2266 31.3718 31.4222 31.4477
所以我的主要问题是:
- 有没有更好的方法对此进行矢量化计算 数据集,同时保持股票代码的 order/matching, 日期及其计算值?
- 我可以不考虑将所有数据存储在字典中并保留 numpy 数组中的所有内容?
- 我可以直接将 numpy 数组中的值存储到 sql 本质上是表格的数据库或 pandas 数据框?
加入数据框上的日期和 rsi 的更新:
df_dictt = pd.DataFrame(dictt).T
output = pd.DataFrame()
for i in range(len(df_dictt)):
df_join = pd.DataFrame(df_dictt[1][i]).rename(columns={1:'date'}).join(pd.DataFrame(df_dictt[0][i]).rename(columns={0:'rsi'}), how='left')
df_join['rsi'] = df_join['rsi'].shift(14)
df_join['ticker'] = df_dictt.index[i]
output = output.append(df_join, ignore_index=False)
要制作字典,您应该使用 pandas DataFrame.groupby
而不是处理成数组然后遍历它们。
dictt = {ticker: ti.rsi(group["Close"], 14)
for ticker, group in df.groupby("Ticker")}
group["Close"]
将是一个 pandas 系列。如果 rsi
函数不接受这个,那么你可能需要添加类似 group["Close"].to_numpy(dtype=float)
的东西来将它们转换成 numpy 数组。
您可以将 rsi 值直接添加到数据框,一次一组,如下所示:
for _, group in df.groupby("Ticker"):
df.loc[group.index[14:], "rsi"] = ti.rsi(group["Close"], 14)
您也可以 apply
将函数分组,但在这种情况下,您需要每次都转换为 pandas 系列,以便保留索引:
def rsi(group, period):
return pd.Series(ti.rsi(group["Close"], period), index=group.index[period:])
df["rsi"] = df.groupby("Ticker").apply(rsi, 14).reset_index(level=0, drop=True)