【问题标题】:Pandas split dataframe into multiple when condition is true当条件为真时,Pandas 将数据帧拆分为多个
【发布时间】:2018-07-24 00:17:54
【问题描述】:

我有一个数据框,如下面的 df 。我想为条件为真的每个数据块创建一个新的数据框,以便返回 df_1, df_2....df_n。

|      df           |       |  df_1 |   | df_2  |
| Value | Condition |       | Value |   | Value |
|-------|-----------|       |-------|---|-------|
| 2     | True      |   |   | 2     |   | 0     |
| 5     | True      |   |   | 5     |   | 5     |
| 4     | True      |   |   | 4     |   |       |
| 4     | False     |   |   |       |   |       |
| 2     | False     |   |   |       |   |       |
| 0     | True      |   |   |       |   |       |
| 5     | True      |   |   |       |   |       |
| 7     | False     |   |   |       |   |       |
| 8     | False     |   |   |       |   |       |      
| 9     | False     |   |   |       |   |       |

我唯一的想法是循环遍历数据帧,为每个真值块返回开始和结束索引,然后创建新的数据帧,循环遍历返回的索引,为每个开始/结束对返回类似这样的内容:

newdf = df.iloc[start:end]

但这样做似乎效率低下。

【问题讨论】:

    标签: python python-3.x pandas split


    【解决方案1】:

    由倒置布尔列的Series 创建DataFrames 的字典,并为where 的无组添加NaNs:

    g = (~df['Condition']).cumsum().where(df['Condition'])
    print (g)
    0    0.0
    1    0.0
    2    0.0
    3    NaN
    4    NaN
    5    2.0
    6    2.0
    7    NaN
    8    NaN
    9    NaN
    Name: Condition, dtype: float64
    
    #enumerate for starting groups from 1, 2, N
    dfs = {i+1:v for i, (k, v) in enumerate(df[['Value']].groupby(g))}
    print (dfs)
    {1:    Value
    0      2
    1      5
    2      4, 2:    Value
    5      0
    6      5}
    
    print (dfs[1])
       Value
    0      2
    1      5
    2      4
    
    print (dfs[2])
       Value
    5      0
    6      5
    

    【讨论】:

    • 我喜欢这个解决方案。原来我不需要字典,所以我只是用一个列表来形成 dfs。感谢您的回复。
    【解决方案2】:

    这是另一种解决方案。请注意 consecutive_groups 配方来自 more_itertools 库。

    from itertools import groupby
    from operator import itemgetter
    
    def consecutive_groups(iterable, ordering=lambda x: x):
        for k, g in groupby(enumerate(iterable), key=lambda x: x[0] - ordering(x[1])):
            yield map(itemgetter(1), g)
    
    grps = consecutive_groups(df[df.Condition].index)
    
    dfs = {i: df.iloc[list(j)] for i, j in enumerate(grps, 1)}
    
    # {1:    Value Condition
    # 0      2      True
    # 1      5      True
    # 2      4      True,
    # 2:    Value Condition
    # 5      0      True
    # 6      5      True}
    

    【讨论】:

      【解决方案3】:

      我决定提供一个答案,将每个 'Value' 放入自己的列中。

      m = df.Condition.values
      g = (~m).cumsum()
      d = df.loc[m, 'Value']
      g = g[m]
      c = d.groupby(g).cumcount()
      d.set_axis([c, g], inplace=False).unstack()
      
           0    2
      0  2.0  0.0
      1  5.0  5.0
      2  4.0  NaN
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-31
        • 1970-01-01
        • 2021-04-18
        • 2023-02-05
        • 2018-05-05
        • 2020-09-22
        • 2013-11-16
        相关资源
        最近更新 更多