How can I "group by" cell value in pandas?

Viewed 299

I have a DataFrame which look like:

_|a |b |c
x|1 |1 |1
y|2 |2 |3
z|3 |2 |1

I want the result to be:

{
    1: [(x,a),(x,b),(x,c),(z,c)}
    2: [(y,a),(y,b),(z,b)]
    3: [(y,c),(z,a)]
}

I dont care if the result is a dictionary or another dataframe

4 Answers

You can stack the dataframe then use groupby inside a dict comprehension to create key-value pairs correspoding to cell value and index:

s = df.stack()
dct = {k: [*g.index] for k, g in s.groupby(s)}

{1: [('x', 'a'), ('x', 'b'), ('x', 'c'), ('z', 'c')],
 2: [('y', 'a'), ('y', 'b'), ('z', 'b')],
 3: [('y', 'c'), ('z', 'a')]}

You can use GroupBy.groups here

g = df.stack()
g.groupby(g).groups
{
  1: [('x', 'a'), ('x', 'b'), ('x', 'c'), ('z', 'c')], 
  2: [('y', 'a'), ('y', 'b'), ('z', 'b')], 
  3: [('y', 'c'), ('z', 'a')]
}

Try this -

#Dummy example - 
df = pd.DataFrame({'A':[1,2,3,1],'B':[1,1,3,2]}, index=['x','y','z','w'])

#Create tuples of value, index and column
l = [(i,(j,k)) for k,v in df.items() for i,j in zip(v,v.index)]

#Group them by value and create list
pd.DataFrame(l).groupby(0)[1].apply(list)
0
1    [(x, A), (w, A), (x, B), (y, B)]
2                    [(y, A), (w, B)]
3                    [(z, A), (z, B)]

There are some nice answers here, I chose to use melt, I'm adding this as perhaps it's useful to see / perhaps there are mistakes in this which others should avoid and someone will highlight.

Here's an approach though:

# sample data
df = pd.DataFrame(
    {
        "a": [1, 2, 3],
        "b": [1, 2, 2],
        "c": [1, 3, 1],
    },
    index=list("xyz"),
)
cell_values = {}
for cell_value, g in df.reset_index().melt(id_vars="index").groupby("value"):
    cell_values[cell_value] = set(g[["index", "variable"]].apply(tuple, axis=1))

I've assumed that only unique entries were wanted, and have used set() as a result.

Related