【问题标题】:Extract a subset of a pandas dataframe based on values (with repetition)?根据值(重复)提取熊猫数据框的子集?
【发布时间】:2016-11-29 23:41:21
【问题描述】:

假设我有以下数据框:

elements =  [1,1,1,1,1,2,3,4,5]
df = pd.DataFrame({'elements': elements})
df.set_index(['elements'])
print df
   elements
0      1
1      1
2      1
3      1
4      1
5      2
6      3

我有一个列表 [1, 1, 2, 3],我想要包含这 4 个元素的数据框子集,例如:

   elements
0      1
1      1   
5      2
6      3

我已经能够通过构建一个计算数组中项目出现次数的字典并通过附加初始数据帧的子部分来构建一个新数据帧来处理它。

您知道一些数据框方法来帮助我找到更优雅的解决方案吗?

在@jezrael 评论之后:我必须补充一点,我需要跟踪初始索引(在 df 中)。

我们可以将 df(第一个数据帧)视为资源存储库,我需要跟踪哪些行/索引归属于:

用例是:在 df 中的元素中,给我两个 1、一个 2 和一个 3。我会坚持这样一个事实,即我将第 0 行和第 1 行作为 1,第 4 行作为 2,第 5 行作为 3。

【问题讨论】:

    标签: pandas indexing dataframe duplicates subset


    【解决方案1】:

    merge 可以通过GroupBy.cumcount 使用新列进行提取:

    L = [1,1,2,3]
    df1 = pd.DataFrame({'elements':L})
    
    df['g'] = df.groupby('elements')['elements'].cumcount()
    df1['g'] = df1.groupby('elements')['elements'].cumcount()
    
    print (df)
       elements  g
    0         1  0
    1         1  1
    2         1  2
    3         1  3
    4         1  4
    5         2  0
    6         3  0
    7         4  0
    8         5  0
    
    print (df1)
       elements  g
    0         1  0
    1         1  1
    2         2  0
    3         3  0
    
    print (pd.merge(df,df1, on=['elements', 'g']))
       elements  g
    0         1  0
    1         1  1
    2         2  0
    3         3  0
    
    print (pd.merge(df.reset_index(),df1, on=['elements', 'g'])
                      .drop('g', axis=1)
                      .set_index('index')
                      .rename_axis(None))
       elements
    0         1
    1         1
    5         2
    6         3
    

    【讨论】:

    • 你需要来自df的旧索引吗?
    • 感谢您的回答和明智的评论@jezrael。是的,我需要来自 df 的旧索引:我们可以将其视为资源存储库,并且我需要跟踪哪些行/索引被归因:一个用例是:在 df 中的元素中给我两个 1、一个 2 和一个 3。我会更新问题
    【解决方案2】:

    当且仅当您的 Serieslist 已排序(否则,请参见下文),那么您可以这样做:

    L = [1, 1, 2, 3]
    df[df.elements.apply(lambda x: x == L.pop(0) if x in L else False)]
           elements
    0         1
    1         1
    5         2
    6         3
    

    list.pop(i) 返回并删除索引ilist 中的值。因为elementsL 都已排序,所以弹出子集列表L 的第一个元素(i==0) 将始终出现在elements 中相应的第一个元素处。

    因此,在elements 上的lambda 的每次迭代中,L 将变为:

    | element |       L      |   Output  |
    |=========|==============|===========|
    |    1    | [1, 1, 2, 3] |    True   |
    |    1    |    [1, 2, 3] |    True   |
    |    1    |       [2, 3] |   False   |
    |    1    |       [2, 3] |   False   |
    |    1    |       [2, 3] |   False   |
    |    2    |       [2, 3] |    True   |
    |    3    |          [3] |    True   |
    |    4    |           [] |   False   | 
    |    5    |           [] |   False   | 
    

    如您所见,您的列表最后是空的,所以如果有问题,您可以提前复制。或者,您实际上在刚刚创建的新数据框中拥有该信息!


    如果df.elements 未排序,请创建一个排序副本,在该副本上应用与上述相同的 lambda 函数,但它的输出将用作原始数据帧的索引(使用值为 True 的索引):

    df
       elements
    0         5
    1         4
    2         3
    3         1
    4         2
    5         1
    6         1
    7         1
    8         1
    cp = df.elements.copy()
    cp.sort_values(inplace=True)
    tmp = df.loc[cp.apply(lambda x: x == L.pop(0) if x in L else False)]
    print tmp
       elements
    2         3
    3         1
    4         2
    5         1
    

    HTH

    【讨论】:

    • 不错的答案:我可能有未排序的系列。但是我们可以对 L 和 df.elements 进行排序。我将其添加到您的答案中
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-14
    • 1970-01-01
    • 1970-01-01
    • 2017-06-26
    • 2016-08-09
    • 1970-01-01
    • 2020-12-27
    相关资源
    最近更新 更多