Itertools:基于前3行或列表中前几个元素在Pandas中选择

1 投票
1 回答
632 浏览
提问于 2025-04-20 08:44

我今天遇到一个问题,希望能得到一些帮助。我的实验数据是这样的:参与者在屏幕上被要求按下键盘上的四个按钮之一——'m'、'x'、'n'、'z',一共进行了1600次试验。在偶数次试验中,按键的顺序是遵循一个随机选择的模式(比如说:mnzxmnzxmnzx),而在奇数次试验中,按哪个键是随机的。现在我手里的数据集只包含了参与者在每次试验中按下了哪个键。我需要找出:

(1) 参与者的按键模式是什么。(我尝试过这个,因为模式是会重复的)

def find_pattern(df):
'''find the pattern for this subject'''
   criterion = df['trial'].isin([1, 3, 5, 7])
   the_pattern = df[criterion].circle_key.tolist()
   return df


df = df.groupby('sid').apply(find_pattern)

(2) 找出这个参与者模式的所有可能组合(也就是说,如果我按了'm',那么下一个模式的元素会是'x')

为此,我尝试了很多不同的itertools,但没有一个完全符合我的要求。我基本上想要从列表中:

 ['m', 'x', 'z', 'n'] 

对我在(1)中得到的每一个元素,进行所有可能的两个元素的组合,并且要保持顺序。所以这将是:

 [('m', 'x'), ('x', 'z'), ('z', 'n'), ('n', 'm')]

而且没有其他可能性。接下来,我想创建一列,把最近三次试验的结果(包括当前这一试验)组合成一个三元组,就像下面的triplet列那样。我觉得应该有某种滚动窗口,或者简单的方法来选择最近的三次试验。我尝试了各种错误的方法——我似乎无法弄清楚如何在数据框中引用“当前”这一行(不使用for列表)……

我需要这些值,因为我想比较triplet的第一个和最后一个元素是否是可能组合之一(possible_comb)。所以对于第3次试验,答案应该是TRUE,而第4次试验的答案应该是FALSE。

任何帮助都将非常感激。我的当前数据看起来是这样的:

trial sid key
1     1   'm'
2     1   'm'  
3     1   'x'
4     1   'n'
5     1   'x'
6     1   'x'
7     1   'n'
1     2   'm'
2     2   'm'
...   ... 

我希望它看起来像这样:

trial sid key    pattern               possible_comb                                 triplet
1     1   'm'    ['m', 'x', 'x', 'n']  [('m','x'), ('x','x'), ('x','n'), ('n', 'm')] NaN
2     1   'm'    ['m', 'x', 'x', 'n']  [('m','x'), ('x','x'), ('x','n'), ('n', 'm')] NaN
3     1   'x'    ['m', 'x', 'x', 'n']  [('m','x'), ('x','x'), ('x','n'), ('n', 'm')] ['m', 'm', 'x']
4     1   'n'    ['m', 'x', 'x', 'n']  [('m','x'), ('x','x'), ('x','n'), ('n', 'm')] ['m', 'x', 'n']
5     1   'x'    ['m', 'x', 'x', 'n']  [('m','x'), ('x','x'), ('x','n'), ('n', 'm')] ['x', 'n', 'x']
6     1   'x'    ['m', 'x', 'x', 'n']  [('m','x'), ('x','x'), ('x','n'), ('n', 'm')] ['n', 'x', 'x'] 
7     1   'n'    ['m', 'x', 'x', 'n']  [('m','x'), ('x','x'), ('x','n'), ('n', 'm')] ['x', 'x', 'n']
1     2   'n'    ['n', 'x', 'm', 'n']  [('m','x'), ('x','x'), ('x','n'), ('n', 'm')] NaN
2     2   'm'    ['n', 'x', 'm', 'n']  [('m','x'), ('x','x'), ('x','n'), ('n', 'm')] NaN
...   ... 

1 个回答

2

要获取“模式”,你只需要根据主题ID进行分组,然后取每隔一个的元素。可以用下面这个方法来实现:

>>> d.groupby('sid')['key'].apply(lambda c: list(c[::2]))
sid
1      ['m', 'x', 'x', 'n']

(我把你的例子简化了,只保留了一个主题,因为你只提供了主题2的部分数据,而那部分数据太短,无法形成一个“模式”。所以这里是主题1的模式。)

如果你想把这个数据复制到原始数据表中对应主题的每一行,可以使用 map 来获取每个主题ID的模式:

>>> d['pattern'] = d.sid.map(d.groupby('sid')['key'].apply(lambda c: list(c[::2])))
>>> d
   trial  sid  key               pattern
0      1    1  'm'  ['m', 'x', 'x', 'n']
1      2    1  'm'  ['m', 'x', 'x', 'n']
2      3    1  'x'  ['m', 'x', 'x', 'n']
3      4    1  'n'  ['m', 'x', 'x', 'n']
4      5    1  'x'  ['m', 'x', 'x', 'n']
5      6    1  'x'  ['m', 'x', 'x', 'n']
6      7    1  'n'  ['m', 'x', 'x', 'n']

要获取连续的组合,你只需把第一个元素加到最后面(这样序列就“循环”了),然后通过抓取两个元素的小列表来提取组合,可以用这样的函数:

def getCombs(pattern):
    pattern = pattern + [pattern[0]]
    return [pattern[ix:ix+2] for ix in xrange(len(pattern)-1)]

然后你就可以把这些模式放入你的数据表中:

>>> d['combs'] = d.pattern.map(getCombs)
>>> d.combs
0    [['m', 'x'], ['x', 'x'], ['x', 'n'], ['n', 'm']]
1    [['m', 'x'], ['x', 'x'], ['x', 'n'], ['n', 'm']]
2    [['m', 'x'], ['x', 'x'], ['x', 'n'], ['n', 'm']]
3    [['m', 'x'], ['x', 'x'], ['x', 'n'], ['n', 'm']]
4    [['m', 'x'], ['x', 'x'], ['x', 'n'], ['n', 'm']]
5    [['m', 'x'], ['x', 'x'], ['x', 'n'], ['n', 'm']]
6    [['m', 'x'], ['x', 'x'], ['x', 'n'], ['n', 'm']]
Name: combs, dtype: object

(这里我只显示“combs”这一列,因为如果显示所有列会让表格太宽,不方便查看。)

撰写回答