38

Assuming the following DataFrame:

  key.0 key.1 key.2  topic
1   abc   def   ghi      8
2   xab   xcd   xef      9

How can I combine the values of all the key.* columns into a single column 'key', that's associated with the topic value corresponding to the key.* columns? This is the result I want:

   topic  key
1      8  abc
2      8  def
3      8  ghi
4      9  xab
5      9  xcd
6      9  xef

Note that the number of key.N columns is variable on some external N.

cs95
  • 379,657
  • 97
  • 704
  • 746
borice
  • 1,009
  • 1
  • 8
  • 15

3 Answers3

57

You can melt your dataframe:

>>> keys = [c for c in df if c.startswith('key.')]
>>> pd.melt(df, id_vars='topic', value_vars=keys, value_name='key')

   topic variable  key
0      8    key.0  abc
1      9    key.0  xab
2      8    key.1  def
3      9    key.1  xcd
4      8    key.2  ghi
5      9    key.2  xef

It also gives you the source of the key.


From v0.20, melt is a first class function of the pd.DataFrame class:

>>> df.melt('topic', value_name='key').drop('variable', 1)

   topic  key
0      8  abc
1      9  xab
2      8  def
3      9  xcd
4      8  ghi
5      9  xef
cs95
  • 379,657
  • 97
  • 704
  • 746
Alexander
  • 105,104
  • 32
  • 201
  • 196
7

After trying various ways, I find the following is more or less intuitive, provided stack's magic is understood:

# keep topic as index, stack other columns 'against' it
stacked = df.set_index('topic').stack()
# set the name of the new series created
df = stacked.reset_index(name='key')
# drop the 'source' level (key.*)
df.drop('level_1', axis=1, inplace=True)

The resulting dataframe is as required:

   topic  key
0      8  abc
1      8  def
2      8  ghi
3      9  xab
4      9  xcd
5      9  xef

You may want to print intermediary results to understand the process in full. If you don't mind having more columns than needed, the key steps are set_index('topic'), stack() and reset_index(name='key').

miraculixx
  • 10,034
  • 2
  • 41
  • 60
  • I can't seem to find any documentation on the `name` argument for `reset_index`, could you explain how it works? – ilyas patanam Dec 20 '15 at 03:54
  • it's the [Series.reset_index()](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.reset_index.html?highlight=reset_index) – miraculixx Dec 20 '15 at 03:58
7

OK , cause one of the current answer is mark as duplicated of this question, I will answer here.

By Using wide_to_long

pd.wide_to_long(df, ['key'], 'topic', 'age').reset_index().drop('age',1)
Out[123]: 
   topic  key
0      8  abc
1      9  xab
2      8  def
3      9  xcd
4      8  ghi
5      9  xef
BENY
  • 317,841
  • 20
  • 164
  • 234