Python 如何找到按分组的两列数据帧行的交点,并从包含该值的单元格中删除该值?

Python 如何找到按分组的两列数据帧行的交点,并从包含该值的单元格中删除该值?,python,pandas,dataframe,Python,Pandas,Dataframe,我有一个数据框,如下所示: name teamA teamB foo a b foo b c foo c b bar a e bar a d ... 我想分别查找每个名称的行交叉点,但同时查找teamA和teamB列的行交叉点。然后删除包含该交点值的单元格的值。 在本例中,对于名称“foo”,行的交点将是“b”,而对于名称“bar”将是“a”。 因此,删除此交点值后的数据帧如下所示: na

我有一个数据框,如下所示:

name  teamA   teamB
foo    a        b
foo    b        c
foo    c        b
bar    a        e
bar    a        d
...
我想分别查找每个名称的行交叉点,但同时查找teamA和teamB列的行交叉点。然后删除包含该交点值的单元格的值。 在本例中,对于名称“foo”,行的交点将是“b”,而对于名称“bar”将是“a”。 因此,删除此交点值后的数据帧如下所示:

name  teamA   teamB
foo     a      " "
foo    " "      c
foo     c      " "
bar    " "      e
bar    " "      d
...
最近,我尝试将teamA和teamB作为一个专栏,以示例团队命名

name   teams
foo    [a, b]
foo    [b, c]
foo    [c, b]
...
之后我想得到

name   teams
foo    [a, " "]
foo    [" ", c]
foo    [c, " "]
...
但我发现更推荐将其分为两列,我发现答案很有趣,但我不知道如何将其应用于分组数据帧。 (请参阅“筛选多个列”部分和“保留至少有一列为真的行”)。 如该例所示:

dataframe[['teamA', 'teamB']].isin('b').any(axis=1)

0     True
1     True
2     True
3     True
dtype: bool
其中“b”将是我将迭代的值(团队)之一。在每次迭代之后,如果整列为True,我将从每行的列teamA或teamB中删除该值,并继续到另一个组

我得到的错误是:

Cannot access callable attribute 'isin' of 'DataFrameGroupBy' objects, try using the 'apply' method


我们可以做
melt
,然后放下复制品,然后
pivot
将其放回原处

s=df.reset_index().melt(['index','name']).\
      drop_duplicates(['name','value'],keep=False).\
         pivot_table(index=['index','name'],columns='variable',values='value',aggfunc='first').\
            fillna('').reset_index(level=1)
s['team']=list(zip(s.teamA,s.teamB))
s
Out[102]: 
variable name teamA teamB   team
index                           
0         foo     a        (a, )
1         foo           c  (, c)
2         foo           d  (, d)
3         bar           e  (, e)
4         bar           d  (, d)

也许不如@温约本漂流好,但你可以考虑使用一个非常灵活的自定义函数

将熊猫作为pd导入
df=pd.DataFrame({“name”:[“foo”]*3+[“bar”]*2,
“teamA”:[“a”、“b”、“b”、“a”、“a”],
“团队b”:[“b”、“c”、“d”、“e”、“d”]})
def fun(x):
toRemove=列表(设置(x[“teamA”].值)。交叉点(x[“teamB”]))
对于[“teamA”、“teamB”]中的列:
x[col]=np.where(x[col].isin(toRemove),“”,x[col])
返回x
df.groupby(“名称”).apply(乐趣)
哪个输出是:

name teamA teamB
0福阿
1富c
二福
3巴
4巴
+。 示例数据帧:

print(df)

  name teamA teamB
0  foo     a     b
1  foo     b     c
2  foo     b     d
3  bar     a     e
4  bar     a     d
5  bar     b     a

然后使用+
join
split
获得
teams
列:

new_df['teams']=new_df[['teamA','teamB']].apply(lambda x: ','.join(x).split(','),axis=1)
print(new_df)

  name teamA teamB   teams
0  foo     a        [a,  ]
1  foo           c  [ , c]
2  foo           d  [ , d]
3  bar           e  [ , e]
4  bar           d  [ , d]
5  bar     b        [b,  ]

尝试使用
groupby
并应用
stack
drop\u duplicates
unstack
fillna

(df[['teamA', 'teamB']].groupby(df.name, sort=False)
                       .apply(lambda x: x.stack().drop_duplicates(keep=False))
                       .unstack().fillna('').reset_index('name'))

Out[93]:
  name teamA teamB
0  foo     a
1  foo           c
2  foo           d
3  bar           e
4  bar           d

在我昨天编辑了我的问题之后。。。 这是我的数据帧(
df
):

这就是解决方案:

def fun(x):
    melted = pd.melt(x.reset_index(), id_vars=['name', 'year'], value_vars=['teamA', 'teamB'], var_name='var_name',
                    value_name='team')
    toRemove = melted.team.mode().iloc[0]
    for col in ["teamA", "teamB"]:
        x[col] = x[col].replace(toRemove,'something')
    return x


df = df.groupby(["name", "year"]).apply(fun)
因此,我融化了我的数据帧,并在从两列中移除该值之后找到最频繁的值。
谢谢@rpanai!每个答案都很有帮助,但你的答案是最有用的

所以,我的问题显然不完整。如果我必须按两列进行分组怎么办?如果有两个以上的重复项,如下面的示例所示,该怎么办
name teamA teamB foo a b foo b c foo b c bar a e bar a d
我只想删除b值,因为它们显示在每一行中。我可以这样做,比如删除最频繁的值或类似的东西,但我的主要问题是按两列进行分组。因此,我的问题显然不完整。如果我必须按两列进行分组怎么办?如果有两个以上的重复项,比如下面的例子(我也会编辑我的主要问题,这样你们就可以很好地看到它了),会怎么样
name teamA teamB foo a b foo b c foo b c bar a e bar a d
我只想删除b值,因为它们显示在每一行中。我可以这样做,比如删除最频繁的值或类似的东西,但我的主要问题是通过两列进行分组。你的答案非常有用,但我的问题不完整。请看我在主要问题中编辑的表格。
(df[['teamA', 'teamB']].groupby(df.name, sort=False)
                       .apply(lambda x: x.stack().drop_duplicates(keep=False))
                       .unstack().fillna('').reset_index('name'))

Out[93]:
  name teamA teamB
0  foo     a
1  foo           c
2  foo           d
3  bar           e
4  bar           d
name  teamA   teamB year
foo    a        b    1
foo    b        c    1
foo    c        b    1
bar    a        e    2
bar    a        d    2
foo    a        h    2
foo    h        c    2
foo    h        b    2
...
def fun(x):
    melted = pd.melt(x.reset_index(), id_vars=['name', 'year'], value_vars=['teamA', 'teamB'], var_name='var_name',
                    value_name='team')
    toRemove = melted.team.mode().iloc[0]
    for col in ["teamA", "teamB"]:
        x[col] = x[col].replace(toRemove,'something')
    return x


df = df.groupby(["name", "year"]).apply(fun)