Repository: pandas-dev/pandas

Issue:
BUG: melt changes type of tz-aware columns
#### Code Samples

```python
import pandas as pd
frame = pd.DataFrame({'klass':range(5), 'ts': [pd.Timestamp('2017-03-23 08:22:42.173378+01'), pd.Timestamp('2017-03-23 08:22:42.178578+01'), pd.Timestamp('2017-03-23 08:22:42.173578+01'), pd.Timestamp('2017-03-23 08:22:42.178378+01'), pd.Timestamp('2017-03-23 08:22:42.163378+01')], 'attribute':['att1', 'att2', 'att3', 'att4', 'att5'], 'value': ['a', 'b', 'c', 'd', 'd']})
# At this point, frame.ts is of dtype datetime64[ns, pytz.FixedOffset(60)]
frame.set_index(['ts', 'klass'], inplace=True)
queried_index = frame.query('value=="d"').index
pivoted_frame = frame.reset_index().pivot_table(index=['klass', 'ts'], columns='attribute', values='value', aggfunc='first')
melted_frame = pd.melt(pivoted_frame.reset_index(), id_vars=['klass', 'ts'], var_name='attribute', value_name='value')
# At this point, melted_frame.ts is of dtype datetime64[ns]
queried_after_melted_index = melted_frame.query('value=="d"').set_index(['ts', 'klass']).index
frame.loc[queried_index]  # Works
frame.loc[queried_index] = 'test'  # Works
frame.loc[queried_after_melted_index]  # Works
frame.loc[queried_after_melted_index] = 'test'  # Breaks
```
The last statement gives: 
```
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.5/dist-packages/pandas/core/indexing.py", line 140, in __setitem__
    indexer = self._get_setitem_indexer(key)
  File "/usr/local/lib/python3.5/dist-packages/pandas/core/indexing.py", line 127, in _get_setitem_indexer
    return self._convert_to_indexer(key, is_setter=True)
  File "/usr/local/lib/python3.5/dist-packages/pandas/core/indexing.py", line 1230, in _convert_to_indexer
    raise KeyError('%s not in index' % objarr[mask])
KeyError: "MultiIndex(levels=[[2017-03-23 07:22:42.163378, 2017-03-23 07:22:42.173378, 2017-03-23 07:22:42.173578, 2017-03-23 07:22:42.178378, 2017-03-23 07:22:42.178578], [0, 1, 2, 3, 4]],\n           labels=[[3, 0], [3, 4]],\n           names=['ts', 'klass']) not in index"
```

#### Problem description

- It is counter-intuitive that any operation (which does not explicitly mention in its docs that it does) alters the type of any column.
- Also counter-intuitive is that ```frame.loc``` has different behavior in a statement than it has in an assignment.

#### Expected Output
- ```melted_frame.ts``` and ```frame.ts``` have the same dtype.
- ```DataFrame.loc``` fails in both cases, not just in an assignment, or succeeds in both.

#### Output of ``pd.show_versions()``

<details>
INSTALLED VERSIONS
------------------
commit: None
python: 3.5.2.final.0
python-bits: 64
OS: Linux
OS-release: 4.4.0-66-generic
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
LOCALE: en_US.UTF-8

pandas: 0.19.2
nose: None
pip: 9.0.1
setuptools: 20.7.0
Cython: None
numpy: 1.12.0
scipy: None
statsmodels: None
xarray: None
IPython: 5.3.0
sphinx: None
patsy: None
dateutil: 2.6.0
pytz: 2016.10
blosc: None
bottleneck: None
tables: None
numexpr: None
matplotlib: None
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: 0.7.3
lxml: 3.5.0
bs4: 4.4.1
html5lib: 0.999
httplib2: 0.9.1
apiclient: None
sqlalchemy: None
pymysql: None
psycopg2: 2.6.1 (dt dec pq3 ext lo64)
jinja2: 2.8
boto: None
pandas_datareader: None

</details>



Discussion:
@stigviaene ``.melt`` doesn't have the battery of tests that most other things have. So not suprising that this doesn't convert correctly. Welcome to have you submit a patch to fix or at least see if you can locate the problem.

your comments on indexing are orthogonal. If you have a specific bug/comment you can raise in another issue.

Resolving patch:
diff --git a/pandas/core/reshape/melt.py b/pandas/core/reshape/melt.py
--- a/pandas/core/reshape/melt.py
+++ b/pandas/core/reshape/melt.py
@@ -13,7 +13,9 @@
 
 import re
 from pandas.core.dtypes.missing import notna
+from pandas.core.dtypes.common import is_extension_type
 from pandas.core.tools.numeric import to_numeric
+from pandas.core.reshape.concat import concat
 
 
 @Appender(_shared_docs['melt'] %
@@ -70,7 +72,12 @@ def melt(frame, id_vars=None, value_vars=None, var_name=None,
 
     mdata = {}
     for col in id_vars:
-        mdata[col] = np.tile(frame.pop(col).values, K)
+        id_data = frame.pop(col)
+        if is_extension_type(id_data):
+            id_data = concat([id_data] * K, ignore_index=True)
+        else:
+            id_data = np.tile(id_data.values, K)
+        mdata[col] = id_data
 
     mcolumns = id_vars + var_name + [value_name]
 


Test patch:
diff --git a/pandas/tests/reshape/test_melt.py b/pandas/tests/reshape/test_melt.py
--- a/pandas/tests/reshape/test_melt.py
+++ b/pandas/tests/reshape/test_melt.py
@@ -212,6 +212,27 @@ def test_multiindex(self):
         res = self.df1.melt()
         assert res.columns.tolist() == ['CAP', 'low', 'value']
 
+    @pytest.mark.parametrize("col", [
+        pd.Series(pd.date_range('2010', periods=5, tz='US/Pacific')),
+        pd.Series(["a", "b", "c", "a", "d"], dtype="category"),
+        pd.Series([0, 1, 0, 0, 0])])
+    def test_pandas_dtypes(self, col):
+        # GH 15785
+        df = DataFrame({'klass': range(5),
+                        'col': col,
+                        'attr1': [1, 0, 0, 0, 0],
+                        'attr2': col})
+        expected_value = pd.concat([pd.Series([1, 0, 0, 0, 0]), col],
+                                   ignore_index=True)
+        result = melt(df, id_vars=['klass', 'col'], var_name='attribute',
+                      value_name='value')
+        expected = DataFrame({0: list(range(5)) * 2,
+                              1: pd.concat([col] * 2, ignore_index=True),
+                              2: ['attr1'] * 5 + ['attr2'] * 5,
+                              3: expected_value})
+        expected.columns = ['klass', 'col', 'attribute', 'value']
+        tm.assert_frame_equal(result, expected)
+
 
 class TestLreshape(object):