【问题标题】:Slicing rows of pandas dataframe between在之间切片熊猫数据框的行
【发布时间】:2015-08-27 10:31:38
【问题描述】:

我有一个 pandas 数据框,其中有一列标记另一列中有趣的数据点(例如峰和谷的位置)。我经常需要对每个标记之间的值进行一些计算。有没有一种巧妙的方法可以使用标记作为端点对数据帧进行切片,以便我可以在每个切片上运行一个函数?数据框看起来像这样,并标记了所需的切片:

   numbers     markers
0  0.632009    None
1  0.733576    None    # Slice 1 (0,1,2)
2  0.585944       x    _________
3  0.212374    None
4  0.491948    None    
5  0.324899    None    # Slice 2 (3,4,5,6)
6  0.389103       y    _________
7  0.638451    None
8  0.123557    None    # Slice 3 (7,8,9)
9  0.588472       x    _________

我目前的方法是创建一个由标记出现的索引组成的数组,使用这些值迭代这个数组以对数据帧进行切片,然后将这些切片附加到一个列表中。我最终得到了一个 numpy 数组列表,然后我可以将函数应用于:

import pandas as pd
df = pd.DataFrame({'numbers':np.random.rand(10),'markers':[None,None,'x',None,None,None,'y',None,None,'x']})

index_array = df[df.markers.isin(['x', 'y'])].index  # returns an array of xy indices    
slice_list = []

prev_i = 0  # first slice of the dataframe needs to start from index 0
for i in index_array:
    new_slice = df.numbers[prev_i:i+1].values  # i+1 to include the end marker in the slice
    slice_list.append(new_slice)
    prev_i = i+1  # excludes the start marker in the next slice

for j in slice_list:
    myfunction(j)

这可行,但我想知道是否有更惯用的方法使用花哨的索引/分组/透视或我缺少的东西? 我看过使用 groupby,但这不起作用,因为在标记列上分组只返回标记所在的行,并且多索引和数据透视表需要唯一标签。我不会费心去问,除了 pandas 几乎可以做任何事情的工具,所以我的期望可能高得离谱。

我不拘泥于以数组列表结尾,这只是我找到的解决方案。我非常愿意接受有关从一开始就改变我的数据结构方式的建议,如果这能让事情变得更容易的话。

【问题讨论】:

    标签: pandas subset slice


    【解决方案1】:

    您可以使用 compare-cumsum-groupby 模式的变体来做到这一点。从

    开始
    >>> df["markers"].isin(["x","y"])
    0    False
    1    False
    2     True
    3    False
    4    False
    5    False
    6     True
    7    False
    8    False
    9     True
    Name: markers, dtype: bool
    

    我们可以移位并取累计和得到:

    >>> df["markers"].isin(["x","y"]).shift().fillna(False).cumsum()
    0    0
    1    0
    2    0
    3    1
    4    1
    5    1
    6    1
    7    2
    8    2
    9    2
    Name: markers, dtype: int64
    

    之后groupby 随心所欲地工作:

    >>> group_id = df["markers"].isin(["x","y"]).shift().fillna(False).cumsum()
    >>> for k,g in df.groupby(group_id):
    ...     print(k)
    ...     print(g)
    ...     
    0
        numbers markers
    0  0.632009    None
    1  0.733576    None
    2  0.585944       x
    1
        numbers markers
    3  0.212374    None
    4  0.491948    None
    5  0.324899    None
    6  0.389103       y
    2
        numbers markers
    7  0.638451    None
    8  0.123557    None
    9  0.588472       x
    

    【讨论】:

    • 谢谢!这正是我一直在寻找的东西。有人介意指出我的问题有什么问题吗?对于我仅有的两个问题,我刚刚收到 4 次反对票,但没有任何解释原因。太冗长了?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-29
    • 2015-08-11
    • 2017-02-22
    • 1970-01-01
    • 2015-10-30
    • 1970-01-01
    • 2021-02-27
    相关资源
    最近更新 更多