5

I have a table like this

   user         company company2 company3 company4
    1           Mac     Lenovo    Hp      null              
    2           Mac       MSI     Sony                          

And using pandas I would like it to be

     user    company
     1          Mac
     1          Lenovo
     1          Hp
     2         Mac

and so on Here I tried it but didnt work with pandas pivot.

dataframe = pd.read_csv('data.csv')
dataframe.fillna(value='', inplace=True)
#dataframe.pivot(index='user', columns='company')

Above code doesnt work and gives error.

MaxU - stand with Ukraine
  • 205,989
  • 36
  • 386
  • 419
Aurora
  • 282
  • 3
  • 16
  • 1
    "It doesn't work" is not particularly specific. Please include the exact error message you see. – Metropolis Apr 14 '17 at 19:22
  • @Metropolis I was thinking the error is pretty stupid so dint want to use it. Sorry will do my best next time – Aurora Apr 14 '17 at 19:32
  • You can edit your question and include the error message. The exact error is usually very helpful for helping to debug a problem. – Metropolis Apr 14 '17 at 19:35

2 Answers2

8

you can use pd.melt method:

In [211]: pd.melt(df, id_vars='user', value_vars=df.columns.drop('user').tolist())
Out[211]:
   user  variable   value
0     1   company     Mac
1     2   company     Mac
2     1  company2  Lenovo
3     2  company2     MSI
4     1  company3      Hp
5     2  company3    Sony
6     1  company4    null
7     2  company4     NaN

or

In [213]: pd.melt(df,
                  id_vars='user', value_vars=df.columns.drop('user').tolist(),
                  value_name='Company') \
            .drop('variable',1)
Out[213]:
   user Company
0     1     Mac
1     2     Mac
2     1  Lenovo
3     2     MSI
4     1      Hp
5     2    Sony
6     1    null
7     2     NaN

UPDATE: dropping NaN's and sorting resulting DF by user:

In [218]: pd.melt(df,
     ...:         id_vars='user', value_vars=df.columns.drop('user').tolist(),
     ...:         value_name='Company') \
     ...:   .drop('variable',1) \
     ...:   .dropna() \
     ...:   .sort_values('user')
     ...:
Out[218]:
   user Company
0     1     Mac
2     1  Lenovo
4     1      Hp
6     1    null
1     2     Mac
3     2     MSI
5     2    Sony

PS if you want to get rid of null values - use df.replace('null', np.nan) instead of df:

In [219]: pd.melt(df.replace('null', np.nan),
     ...:         id_vars='user', value_vars=df.columns.drop('user').tolist(),
     ...:         value_name='Company') \
     ...:   .drop('variable',1) \
     ...:   .dropna() \
     ...:   .sort_values('user')
     ...:
Out[219]:
   user Company
0     1     Mac
2     1  Lenovo
4     1      Hp
1     2     Mac
3     2     MSI
5     2    Sony
MaxU - stand with Ukraine
  • 205,989
  • 36
  • 386
  • 419
4

It is possible to use stack for it (don't know if it is more efficient then melt:

dataframe.set_index("user").stack().reset_index(-1, drop=True)

user
1       Mac
1    Lenovo
1        Hp
2       MSI
2       Mac
2      Sony

Stack essentially pushes the columns to be part of the index (and create MultiIndex) - thus, for every column-row combination, you get a row in the new DataFrame. That is, the DataFrame

   C1 C2
0  A  B
1  a  b

after stack() becomes the Series

0  C1 A
0  C2 B
1  C1 a
1  C2 b
tmrlvi
  • 2,235
  • 17
  • 35
  • I tried it but dint actually work properly, could you please edit the answer to follow my example, It would be great! – Aurora Apr 14 '17 at 19:38
  • I assumed `user` was your index. Try the above version (I added `set_index("user")`) – tmrlvi Apr 14 '17 at 19:43