Integers coerced to float when getting rows from all-numeric data frames
When selecting a row in a data frame that only contains numeric values, pandas coerces any integer values to floats.  I assume this keeps the underlying data structure more contiguous and improves performance, but it's not really semantically correct, because floats can't do everything that integers can.  For example, the problem I ran into today came about because I was trying to use values from an integer column to index into a string:

```pycon
>>> df = pd.DataFrame([[1, 2.0], [3, 4.0]], columns=['a' , 'b'])
>>> df
   a    b
0  1  2.0
1  3  4.0
>>> df.dtypes
a      int64
b    float64
dtype: object
>>> df.apply(lambda x: 'ABCD'[x.a], axis=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.7/site-packages/pandas/core/frame.py", line 6487, in apply
    return op.get_result()
  File "/usr/lib/python3.7/site-packages/pandas/core/apply.py", line 151, in get_result
    return self.apply_standard()
  File "/usr/lib/python3.7/site-packages/pandas/core/apply.py", line 257, in apply_standard
    self.apply_series_generator()
  File "/usr/lib/python3.7/site-packages/pandas/core/apply.py", line 286, in apply_series_generator
    results[i] = self.f(v)
  File "<stdin>", line 1, in <lambda>
TypeError: ('string indices must be integers', 'occurred at index 0')
```

Note that either (i) removing the float column or (ii) adding a non-numeric column resolves the error.  This makes code that depends on true integer behavior fragile, because it could be broken as unrelated columns are added or removed.

```pycon
>>> df.drop('b', axis=1).apply(lambda x: 'ABCD'[x.a], axis=1)
0    B
1    D
dtype: object
>>> df.assign(c=['a', 'b']).apply(lambda x: 'ABCD'[x.a], axis=1)
0    B
1    D
dtype: object
```

Clearly pandas prefers if everything is the same data type, but also knows how to handle the case where columns have different types.  When given integer and float columns, pandas just considers them all "numeric" and coerces the integers to floats so that everything can be the same type.  I would argue that integers and floats should be considered different types, because integers can do things (e.g. indexing and slicing) that floats can't, but I'll admit that I have a very narrow view of what's going on here.

---

For what it's worth, a simpler way to see this same coercion is to just select a row:

```pycon
>>> df
   a    b
0  1  2.0
1  3  4.0
>>> df.iloc[0]
a    1.0
b    2.0
Name: 0, dtype: float64
>>> df.drop('b', axis=1).iloc[0]
a    1
Name: 0, dtype: int64
>>> df.assign(c=['a', 'b']).iloc[0]
a    1
b    2   # I double-checked that b is still a float here, even though it's shown without a decimal.
c    a
Name: 0, dtype: object
```

#### Output of ``pd.show_versions()``

<details>

INSTALLED VERSIONS
------------------
commit: None
python: 3.7.4.final.0
python-bits: 64
OS: Linux
OS-release: 5.2.5-arch1-1-ARCH
machine: x86_64
processor: 
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
LOCALE: en_US.UTF-8

pandas: 0.24.2
pytest: 4.6.3
pip: 19.2.3
setuptools: 41.0.1
Cython: None
numpy: 1.16.4
scipy: 1.3.0
pyarrow: None
xarray: None
IPython: 7.5.0
sphinx: 2.1.1
patsy: None
dateutil: 2.8.0
pytz: 2019.1
blosc: None
bottleneck: None
tables: None
numexpr: None
feather: None
matplotlib: 3.1.1
openpyxl: 2.6.2
xlrd: 1.2.0
xlwt: None
xlsxwriter: None
lxml.etree: 4.4.0
bs4: None
html5lib: None
sqlalchemy: None
pymysql: None
psycopg2: None
jinja2: 2.10.1
s3fs: None
fastparquet: None
pandas_gbq: None
pandas_datareader: None
gcsfs: None

</details>
