首页 > 解决方案 > Pandas-way 根据之前的 groupby() 探索分离 DataFrame 而不会丢失未分组的列

问题描述

我试图将我的真实数据的问题转化为我的问题中提供的示例数据。也许我只是有一个简单的技术问题。或者也许我的整个方式和工作流程不是最好的?

客观

有些人(列name)在不同的餐厅吃过不同fruit的食物day。还有一些我不想丢失的数据(列foo和)。bar

我想分离/拆分原始数据,而不会丢失附加数据(在foo和中bar)。分开的条件是在特定日子吃的独特水果的数量

那是初始数据

>>> df
   name  day       fruit  foo  bar
0   Tim    1       Apple  708   20
1   Tim    1       Apple  135  743
2   Tim    2       Apple  228  562
3  Anna    1      Banana  495  924
4  Anna    1  Strawberry  236  542
5   Bob    1  Strawberry  420  894
6   Bob    2       Apple   27  192
7   Bob    2        Kiwi  671  145

分开的中间结果应该看起来像这两个DataFrame

>>> two
   name  day       fruit  foo  bar
0  Anna    1      Banana  495  924
1  Anna    1  Strawberry  236  542
2   Bob    2       Apple   27  192
3   Bob    2        Kiwi  671  145

>>> non_two
   name  day       fruit  foo  bar
0   Tim    1       Apple  708   20
1   Tim    1       Apple  135  743
2   Tim    2       Apple  228  562
3   Bob    1  Strawberry  420  894

用文字解释的例子:Tim吃了Apple's at day 1and 2。有多少苹果并不重要。重要的是它是一种独特的水果。

到目前为止我做了什么

我做了一些groupby()魔术来找出谁以及何时吃了两种或更少/更多然后两种独特的水果。

import pandas as pd
import random as rd

data = {'name': ['Tim', 'Tim', 'Tim', 'Anna', 'Anna', 'Bob', 'Bob', 'Bob'],
        'day': [1, 1, 2, 1, 1, 1, 2, 2],
        'fruit': ['Apple', 'Apple', 'Apple', 'Banana', 'Strawberry',
                  'Strawberry', 'Apple', 'Kiwi'],
        'foo': rd.sample(range(1000), 8),
        'bar': rd.sample(range(1000), 8)
}

# That is the primary DataFrame
df = pd.DataFrame(data)

# Explore the data
a = df[['name', 'day', 'fruit']].groupby(['name', 'day', 'fruit']).count().reset_index()
b = a.groupby(['name', 'day']).count()

# People who ate 2 fruits on specific days
two = b[(b.fruit == 2)].reset_index()
print(two)

# People who ate less or more then 2 fruits on specific days
non_two = b[(b.fruit != 2)].reset_index()
print(non_two)

这是我的路障

有了数据框twonon_two我就有了我想要的信息。知道我想根据这些信息分离初始数据帧。我认为name并且day是我应该用来在初始数据框中选择和分离的列。

# filter mask
mymask = (df.name == two.name) & (df.day == two.day)

df_two = df[mymask]
df_non_two = df[~mymask]

但这不起作用。第一行加注ValueError: Can only compare identically-labeled Series objects

标签: pandas

解决方案


DataFrameGroupBy.nunique在 中使用GroupBy.transform,因此可能过滤原始DataFrame

mymask = df.groupby(['name', 'day'])['fruit'].transform('nunique').eq(2)

df_two = df[mymask]
df_non_two = df[~mymask]

print (df_two)
   name  day       fruit  foo  bar
3  Anna    1      Banana  335   62
4  Anna    1  Strawberry  286  694
6   Bob    2       Apple  822  738
7   Bob    2        Kiwi  793  449

推荐阅读