我已经在另一个更长的问题的背景下问过这个问题,但我想我曾试图同时提出太多问题。所以,为简单起见:
我有一个数据框,每次试用都会按下一个键。我想添加一个显示最后N行的列。因此,如果我的数据如下所示:
trial sid key_pressed RT
1 S04 x 0.502242
2 S04 m 0.348620
3 S04 m 0.312491
4 S04 x 0.342541
5 S04 n 0.419384
6 S04 n 0.348211
7 S04 z 0.376369
之后它看起来像这样(对于每一个人):
trial sid key_pressed RT last_3
1 S04 x 0.502242 NaN
2 S04 m 0.348620 NaN
3 S04 m 0.312491 [x, m, m]
4 S04 x 0.342541 [m, m, x]
5 S04 n 0.419384 [m, x, n]
6 S04 n 0.348211 [x, n, n]
7 S04 z 0.376369 [n, n, z]
这是否有矢量化解决方案?我似乎无法弄清楚如何选择相对行。 (熊猫新手 - 不是那么想这个方式,但是)
更新:根据以下贡献者的建议,我最终做到了这一点:
df['shifted'] = pd.concat([df.groupby('sid')['key_pressed'].shift(2) + df.groupby('sid')['key_pressed'].shift(1) + df.groupby('sid')['key_pressed'].shift(0)])
例如,创建了一个字符串mxm
。哪个更好。
答案 0 :(得分:2)
一种方法是使用shift
将相关列向下移动n
行,然后连接条目(它们是字符串,以便我们可以使用+
):
df.last_3 = df.key_pressed.shift(1) + ', ' + df.key_pressed.shift(2) + ', ' + df.key_pressed.shift(3)
这将创建前三个条目的字符串,用逗号和空格(不是列表)分隔。如果可能的话,我会避免在DataFrame中使用列表,因为事情会变得有些混乱。
答案 1 :(得分:1)
你想对这些名单做什么?在Series / DataFrames中存储列表通常不是很方便。无论如何,这会让你接近。你必须处理nans
,然后你就完成了。
In [6]: pd.concat([df.key_pressed.shift(i) for i in [0, 1, 2]], 1).apply(tuple, 1).map(list)
Out[6]:
0 [x, nan, nan]
1 [m, x, nan]
2 [m, m, x]
3 [x, m, m]
4 [n, x, m]
5 [n, n, x]
6 [z, n, n]
dtype: object
请注意,我们必须转换为元组然后转换为列表,以避免pandas自动获取列表并将其重新转换为系列。试试这个,你会明白为什么它不起作用:
pd.concat([df.key_pressed.shift(i) for i in [0, 1, 2]], 1).apply(list, 1)
答案 2 :(得分:0)
哦 - 也许这是最好的解决方案。人们可以将数据“转移”一定数量:
df['shifted'] = df.groupby('sid')['key_pressed'].shift(2)
然后我可以根据这些转移的数据创建列表。
答案 3 :(得分:0)
这个解决方案避免了循环,但是我不确定它是否真的算作“矢量化”,因为一旦你开始使用apply()
,我认为你开始失去任何性能优势矢量:
key_table = pd.concat(
[df.key_pressed.shift(2), df.key_pressed.shift(1), df.key_pressed],
axis=1
)
df['last_3'] = key_table.apply(
lambda row: ', '.join(str(k) for k in row),
axis=1
)
输出:
trial sid key_pressed RT last_3
0 1 S04 x 0.502242 nan, nan, x
1 2 S04 m 0.348620 nan, x, m
2 3 S04 m 0.312491 x, m, m
3 4 S04 x 0.342541 m, m, x
4 5 S04 n 0.419384 m, x, n
5 6 S04 n 0.348211 x, n, n
6 7 S04 z 0.376369 n, n, z