[英]For Python Pandas, how can I append to a column value (type list) based on the index date range?
数据是一个 dataframe 单列,即“股票代码”,这是一个股票代码列表。
date tickers
1996-01-02 [AAL, AAMRQ, AAPL, ABI, ABS, ABT, ABX, ACKH, A...
1996-01-03 [AAL, AAMRQ, AAPL, ABI, ABS, ABT, ABX, ACKH, A...
1996-01-04 [AAL, AAMRQ, AAPL, ABI, ABS, ABT, ABX, ACKH, A...
1996-01-10 [AAL, AAMRQ, AAPL, ABI, ABS, ABT, ABX, ACKH, A...
1996-01-11 [AAL, AAMRQ, AAPL, ABI, ABS, ABT, ABX, ACKH, A...
如果日期大于 2018-10-31,我想将 append 的股票代码“Lin”添加到列表中。 我已经有一个解决方案,但我怀疑是最佳的。 这是我所拥有的:
# add LIN after 2018-10-31
def _add_symbol(row, symbol, date):
if row.name > date:
row.tickers.append(symbol)
return row.tickers
df['tickers'] = df.apply(_add_symbol, symbol='LIN', date='2018-10-31', axis=1)
我敢打赌,有一个使用 lambda 的班轮会做同样的事情,但我想不通,所以我按照我知道的去做。
您应该尽可能避免使用 apply,但是将项目附加到单元格中的列表是很棘手的,我不确定没有某种迭代的任何方法。 话虽如此,您可以通过将日期条件放在索引器中然后应用过滤结果来稍微优化您的操作。 这应该会显着提高速度:
df.loc[df['date']>'2018-10-31','tickers'].apply(lambda x: x.append('LIN'))
编辑:关于应用与列操作的一些快速比较。 对于这个例子,我只是使用了一个简单的操作,其中“A”列中的值递增 1。我们将比较以下两种实现上述结果的方法:
apply_op = """
df['A']=df.apply(lambda row: row['A']+1,axis=1)
"""
series_op = """
df['A']=df['A']+1
"""
首先,我们将进行一些速度测试,看看每个测试的执行速度。
df:
A B C D
0 1 2 9 6
1 5 8 1 9
2 6 8 0 1
3 6 1 6 8
4 9 0 1 4
.. .. .. .. ..
995 1 3 8 9
996 1 2 3 3
997 2 2 9 1
998 4 9 2 5
999 10 2 0 3
[1000 rows x 4 columns]
Apply op:
[in]:
df['A']=df.apply(lambda row: row['A']+1,axis=1)
[out]:
A B C D
0 1 2 9 6
1 5 8 1 9
2 6 8 0 1
3 6 1 6 8
4 9 0 1 4
Average execution time:0.0226791306 ms
Series op:
[in]:
df['A']=df['A']+1
[out]:
A B C D
0 1 2 9 6
1 5 8 1 9
2 6 8 0 1
3 6 1 6 8
4 9 0 1 4
Average execution time:0.0005004938999999986 ms
串联操作的速度提高了约 4000%。
现在让我们来看看底层,看看每个操作编译了哪些指令:
>>> dis.dis(apply_op)
2 0 LOAD_NAME 0 (df)
2 LOAD_ATTR 1 (apply)
4 LOAD_CONST 0 (<code object <lambda> at 0x090B56A8, file "<dis>", line 2>)
6 LOAD_CONST 1 ('<lambda>')
8 MAKE_FUNCTION 0
10 LOAD_CONST 2 (1)
12 LOAD_CONST 3 (('axis',))
14 CALL_FUNCTION_KW 2
16 LOAD_NAME 0 (df)
18 LOAD_CONST 4 ('A')
20 STORE_SUBSCR
22 LOAD_CONST 5 (None)
24 RETURN_VALUE
Disassembly of <code object <lambda> at 0x090B56A8, file "<dis>", line 2>:
2 0 LOAD_FAST 0 (row)
2 LOAD_CONST 1 ('A')
4 BINARY_SUBSCR
6 LOAD_CONST 2 (1)
8 BINARY_ADD
10 RETURN_VALUE
>>> dis.dis(series_op)
2 0 LOAD_NAME 0 (df)
2 LOAD_CONST 0 ('A')
4 BINARY_SUBSCR
6 LOAD_CONST 1 (1)
8 BINARY_ADD
10 LOAD_NAME 0 (df)
12 LOAD_CONST 0 ('A')
14 STORE_SUBSCR
16 LOAD_CONST 2 (None)
18 RETURN_VALUE
自从我不得不编写任何程序集以来已经有一段时间了,但我将尝试快速解释我们在上面看到的内容。 apply_op 的第一个 output 显示了为 df 中的每一行调用的 apply function 的子例程。 对于每一行,必须检索行、列 ('A') 和常量 (1) 以执行操作。
在 series_op 的第二个 output 中,我们可以看到整个“A”列作为单个常量加载了一次。 这个串联运算只执行了两次加法运算; 整个数组一次,最后一项除外,最后一次(第二次)用于数组的最后一项。
关于数组向量化的更多信息:(顺便说一句,我很少找到有意义的数据帧并行化用例。) Python 中的向量化和并行化与 Numpy 和 Z251D2BBFE9A3B95E5691CEB30DC
尽管我不知道我是否会更好地称呼它,但这段代码的计算效率更高(一点点)。 您的代码可以正常工作并且更易于阅读。
如果您不使用 pandas 行中的列表,则可以提高效率。 (我可以想到一种比使用 lambda 更有效的 append 方法。)
import numpy as np
df['tickers'] = np.where(df['date']>pd.to_datetime('2018-10-31'),
df['tickers'],
df['tickers'].apply(lambda x: x = ['LIN'])
另外,请注意日期的比较。 我使用与示例相同的日期比较,假设您知道自己在做什么,但您正在比较文本。 为了在示例代码中进行比较,我需要添加pd.to_datetime
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.