【问题标题】:Extract a sub-section of a Pandas dataframe提取 Pandas 数据框的子部分
【发布时间】:2019-04-23 19:16:18
【问题描述】:

我有一个这样的数据框:

Name   ID   Level
Name1   A     1
Name2   B     2
Name3   C     3
Name4   D     1
Name5   E     2
Name6   F     1

等等……

我正在寻找一种方法来根据名称标准仅提取此数据帧的一部分。所以我想提取从 Name4 开始的所有内容,直到该组中最后一个人的名字是另一个级别 1..即从 Name4 提取到 Name5 因为 Name6 是级别 1。

或者作为另一个例子,我想从 Name1 中提取到 Name3,因为 Name4 是 Level 1。

我可以在 Excel 中使用宏来执行此操作...找到 Name1,查看 Level 列,如果不是 1,则获取这行数据并继续执行,直到您点击 Name再次有一个Level 1,然后停止,然后输出这个部分

希望这是有道理的。

【问题讨论】:

  • 解压成什么?请举例说明您期望的输出
  • 你检查 df.groupby 了吗?
  • 您是如何获得“级别”列的?我觉得有更简单的方法来对列进行分组,而不是遍历每一行并检查“级别”变量的变化。
  • 抱歉,如果我的问题不够彻底。还在学习如何正确提问,一定要学会交出预期。感谢您的反馈意见。我确实查看了 groupby 函数,但这并没有帮助。 Level 变量将作为下载数据的一部分提供

标签: python pandas dataframe


【解决方案1】:

你可以这样做:

创建一个包含组值的新列“组”,然后您可以groupby此列

g = 0
for i in df.index:
    if df.loc[i, "Level"] == 1:
        g += 1
    df.loc[i, "Group"] = g

【讨论】:

    【解决方案2】:

    使用这个数据框:

    In [0]: df
    Out[0]: 
        Name ID  Level
    0  Name1  A      1
    1  Name2  B      2
    2  Name3  C      3
    3  Name4  D      1
    4  Name5  E      2
    5  Name6  F      1
    

    使用辅助列/系列来指示行是否处于某个级别(目标级别)。 target_lvl = 1:

    helper_series = (df['Level'] == target_lvl)
    
    In [1]: helper_series
    Out[1]: 
    0     True
    1    False
    2    False
    3     True
    4    False
    5     True
    

    现在您可以获取映射每个子集的开始和结束的范围列表:

    ranges = df.index.where(helper_series).dropna().astype(int).tolist()
    
    In [2]: ranges
    Out[2]:
    [0, 3, 5]
    

    注意ranges 的值是属于target-lvl 的每一行的索引。

    最后,你只需要从ranges中提取子集:

    subsets = list()
    for i in range(len(ranges)):
        if i == 0:
            continue
        subsets.append(df.iloc[ ranges[i-1] : ranges[i] , :])
    
    last_subset = df.iloc[ ranges[-1] :, :]
    if not last_subset.empty:    
        subsets.append(last_subset)
    
    In [3]: subsets
    Out[3]:
       Name  ID  Level  
    0  Name1  A    1    
    1  Name2  B    2  
    2  Name3  C    3 
    
       Name  ID  Level  
    3  Name4  D    1  
    4  Name5  E    2
    

    【讨论】:

    • 这几乎可以工作,除非我在 1 级之后有另一个级别,除非我在数据帧的末尾插入一个虚拟的 1 级数据行,否则最后一个子部分不会被拾取。我可以忍受。我自己确实创建了一个助手系列,但作为 Pandas 的新手,我不知道如何使用它
    • 如果您想添加最后一个子集,我刚刚编辑了答案。
    【解决方案3】:

    这会将所需的Name 带到一个地方 -

    df.groupby(df.groupby(['Level']).cumcount())['Name'].apply(lambda x: ','.join(x))
    
    0    Name1,Name2,Name3
    1          Name4,Name5
    2                Name6
    Name: Name, dtype: object
    

    您现在可以根据需要为每个实体设置Level / 操作apply() 函数中的lambda 以实现它

    【讨论】:

      【解决方案4】:

      设置数据框:

      df = pd.DataFrame({'Name': ['Name1', 'Name2', 'Name3', 'Name4', 'Name5', 'Name6'],
                         'ID': ['A', 'B', 'C', 'D', 'E', 'F'],
                         'Level': [1, 2, 3, 1, 2, 1]})
      

      使用系列移位查找新组(新级别 1)的位置,用 1 标记,然后执行 cumsum。

      grp_markers = (df.Level - df.Level.shift()).fillna(-1).values <= 0
      df['grp'] = grp_markers.cumsum()
      

      找到这样的子集:

      df[df.grp == 2]
      
          Name ID  Level    grp
      3  Name4  D      1      2
      4  Name5  E      2      2
      

      现在您还可以使用 grp 列进行 groupby 操作...

      【讨论】:

        猜你喜欢
        • 2021-04-01
        • 1970-01-01
        • 2019-02-09
        • 2023-03-14
        • 1970-01-01
        • 2023-03-30
        • 2020-03-09
        • 2016-12-14
        • 1970-01-01
        相关资源
        最近更新 更多