1

I get a dataframe as follows:

df
     c1  c2  c3  c4  c5  c6  c7  c8  c9  c10 c11 c12
r1   0   1   1   1   1   0   0   0   0   0   0   0
r2   1   2   2   2   2   1   1   1   1   0   0   0      
r3   1   0   2   0   0   1   0   0   0   0   0   0      


func(df)
     0   1   2
r1   8   4   0
r2   3   5   4
r3   9   2   1

And I want to do value_counts on each row and get 3 columns which are corresponding to the count of each value.
What I thought is to do melt() in each row, get values counts and fill it in corresponding place. BUT I think it is not a smart and convenient enough way.
So if not mind could anyone help me?
Thanks in advance.

Bowen Peng
  • 1,635
  • 4
  • 21
  • 39
  • 2
    Do not using apply please https://stackoverflow.com/questions/54432583/when-should-i-ever-want-to-use-pandas-apply-in-my-code – BENY Jul 28 '19 at 15:40

3 Answers3

3

try using simple pd.Series.value_counts and fillna with 0

df.apply(pd.Series.value_counts, axis=1).fillna(0)
     0   1   2
r1   8   4   0
r2   3   5   4
r3   9   2   1
tawab_shakeel
  • 3,701
  • 10
  • 26
  • 1
    Please try not using apply , for more info https://stackoverflow.com/questions/54432583/when-should-i-ever-want-to-use-pandas-apply-in-my-code – BENY Jul 28 '19 at 15:40
  • @WeNYoBen ok I'll try not to use apply in future.Thanks for the suggestion :) – tawab_shakeel Jul 28 '19 at 15:42
2

Here is one way

df.stack().groupby(level=0).value_counts().unstack(fill_value=0)
    0  1  2
r1  8  4  0
r2  3  5  4
r3  9  2  1

And with crosstab should be fast:-)

s=df.reset_index().melt('index')
pd.crosstab(s['index'],s.value)
value  0  1  2
index         
r1     8  4  0
r2     3  5  4
r3     9  2  1
BENY
  • 317,841
  • 20
  • 164
  • 234
2

Straightforwardly (with Dataframe.apply + pandas.Series.value_counts):

In [232]: df.apply(lambda s: s.value_counts(), axis=1).fillna(0)                                                  
Out[232]: 
      0    1    2
r1  8.0  4.0  0.0
r2  3.0  5.0  4.0
r3  9.0  2.0  1.0
RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105