test_quantile.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. # -*- coding: utf-8 -*-
  2. from __future__ import print_function
  3. import numpy as np
  4. import pytest
  5. import pandas as pd
  6. from pandas import DataFrame, Series, Timestamp
  7. from pandas.tests.frame.common import TestData
  8. import pandas.util.testing as tm
  9. from pandas.util.testing import assert_frame_equal, assert_series_equal
  10. class TestDataFrameQuantile(TestData):
  11. def test_quantile(self):
  12. from numpy import percentile
  13. q = self.tsframe.quantile(0.1, axis=0)
  14. assert q['A'] == percentile(self.tsframe['A'], 10)
  15. tm.assert_index_equal(q.index, self.tsframe.columns)
  16. q = self.tsframe.quantile(0.9, axis=1)
  17. assert (q['2000-01-17'] ==
  18. percentile(self.tsframe.loc['2000-01-17'], 90))
  19. tm.assert_index_equal(q.index, self.tsframe.index)
  20. # test degenerate case
  21. q = DataFrame({'x': [], 'y': []}).quantile(0.1, axis=0)
  22. assert(np.isnan(q['x']) and np.isnan(q['y']))
  23. # non-numeric exclusion
  24. df = DataFrame({'col1': ['A', 'A', 'B', 'B'], 'col2': [1, 2, 3, 4]})
  25. rs = df.quantile(0.5)
  26. xp = df.median().rename(0.5)
  27. assert_series_equal(rs, xp)
  28. # axis
  29. df = DataFrame({"A": [1, 2, 3], "B": [2, 3, 4]}, index=[1, 2, 3])
  30. result = df.quantile(.5, axis=1)
  31. expected = Series([1.5, 2.5, 3.5], index=[1, 2, 3], name=0.5)
  32. assert_series_equal(result, expected)
  33. result = df.quantile([.5, .75], axis=1)
  34. expected = DataFrame({1: [1.5, 1.75], 2: [2.5, 2.75],
  35. 3: [3.5, 3.75]}, index=[0.5, 0.75])
  36. assert_frame_equal(result, expected, check_index_type=True)
  37. # We may want to break API in the future to change this
  38. # so that we exclude non-numeric along the same axis
  39. # See GH #7312
  40. df = DataFrame([[1, 2, 3],
  41. ['a', 'b', 4]])
  42. result = df.quantile(.5, axis=1)
  43. expected = Series([3., 4.], index=[0, 1], name=0.5)
  44. assert_series_equal(result, expected)
  45. def test_quantile_axis_mixed(self):
  46. # mixed on axis=1
  47. df = DataFrame({"A": [1, 2, 3],
  48. "B": [2., 3., 4.],
  49. "C": pd.date_range('20130101', periods=3),
  50. "D": ['foo', 'bar', 'baz']})
  51. result = df.quantile(.5, axis=1)
  52. expected = Series([1.5, 2.5, 3.5], name=0.5)
  53. assert_series_equal(result, expected)
  54. # must raise
  55. with pytest.raises(TypeError):
  56. df.quantile(.5, axis=1, numeric_only=False)
  57. def test_quantile_axis_parameter(self):
  58. # GH 9543/9544
  59. df = DataFrame({"A": [1, 2, 3], "B": [2, 3, 4]}, index=[1, 2, 3])
  60. result = df.quantile(.5, axis=0)
  61. expected = Series([2., 3.], index=["A", "B"], name=0.5)
  62. assert_series_equal(result, expected)
  63. expected = df.quantile(.5, axis="index")
  64. assert_series_equal(result, expected)
  65. result = df.quantile(.5, axis=1)
  66. expected = Series([1.5, 2.5, 3.5], index=[1, 2, 3], name=0.5)
  67. assert_series_equal(result, expected)
  68. result = df.quantile(.5, axis="columns")
  69. assert_series_equal(result, expected)
  70. pytest.raises(ValueError, df.quantile, 0.1, axis=-1)
  71. pytest.raises(ValueError, df.quantile, 0.1, axis="column")
  72. def test_quantile_interpolation(self):
  73. # see gh-10174
  74. from numpy import percentile
  75. # interpolation = linear (default case)
  76. q = self.tsframe.quantile(0.1, axis=0, interpolation='linear')
  77. assert q['A'] == percentile(self.tsframe['A'], 10)
  78. q = self.intframe.quantile(0.1)
  79. assert q['A'] == percentile(self.intframe['A'], 10)
  80. # test with and without interpolation keyword
  81. q1 = self.intframe.quantile(0.1)
  82. assert q1['A'] == np.percentile(self.intframe['A'], 10)
  83. tm.assert_series_equal(q, q1)
  84. # interpolation method other than default linear
  85. df = DataFrame({"A": [1, 2, 3], "B": [2, 3, 4]}, index=[1, 2, 3])
  86. result = df.quantile(.5, axis=1, interpolation='nearest')
  87. expected = Series([1, 2, 3], index=[1, 2, 3], name=0.5)
  88. tm.assert_series_equal(result, expected)
  89. # cross-check interpolation=nearest results in original dtype
  90. exp = np.percentile(np.array([[1, 2, 3], [2, 3, 4]]), .5,
  91. axis=0, interpolation='nearest')
  92. expected = Series(exp, index=[1, 2, 3], name=0.5, dtype='int64')
  93. tm.assert_series_equal(result, expected)
  94. # float
  95. df = DataFrame({"A": [1., 2., 3.], "B": [2., 3., 4.]}, index=[1, 2, 3])
  96. result = df.quantile(.5, axis=1, interpolation='nearest')
  97. expected = Series([1., 2., 3.], index=[1, 2, 3], name=0.5)
  98. tm.assert_series_equal(result, expected)
  99. exp = np.percentile(np.array([[1., 2., 3.], [2., 3., 4.]]), .5,
  100. axis=0, interpolation='nearest')
  101. expected = Series(exp, index=[1, 2, 3], name=0.5, dtype='float64')
  102. assert_series_equal(result, expected)
  103. # axis
  104. result = df.quantile([.5, .75], axis=1, interpolation='lower')
  105. expected = DataFrame({1: [1., 1.], 2: [2., 2.],
  106. 3: [3., 3.]}, index=[0.5, 0.75])
  107. assert_frame_equal(result, expected)
  108. # test degenerate case
  109. df = DataFrame({'x': [], 'y': []})
  110. q = df.quantile(0.1, axis=0, interpolation='higher')
  111. assert(np.isnan(q['x']) and np.isnan(q['y']))
  112. # multi
  113. df = DataFrame([[1, 1, 1], [2, 2, 2], [3, 3, 3]],
  114. columns=['a', 'b', 'c'])
  115. result = df.quantile([.25, .5], interpolation='midpoint')
  116. # https://github.com/numpy/numpy/issues/7163
  117. expected = DataFrame([[1.5, 1.5, 1.5], [2.0, 2.0, 2.0]],
  118. index=[.25, .5], columns=['a', 'b', 'c'])
  119. assert_frame_equal(result, expected)
  120. def test_quantile_multi(self):
  121. df = DataFrame([[1, 1, 1], [2, 2, 2], [3, 3, 3]],
  122. columns=['a', 'b', 'c'])
  123. result = df.quantile([.25, .5])
  124. expected = DataFrame([[1.5, 1.5, 1.5], [2., 2., 2.]],
  125. index=[.25, .5], columns=['a', 'b', 'c'])
  126. assert_frame_equal(result, expected)
  127. # axis = 1
  128. result = df.quantile([.25, .5], axis=1)
  129. expected = DataFrame([[1.5, 1.5, 1.5], [2., 2., 2.]],
  130. index=[.25, .5], columns=[0, 1, 2])
  131. # empty
  132. result = DataFrame({'x': [], 'y': []}).quantile([0.1, .9], axis=0)
  133. expected = DataFrame({'x': [np.nan, np.nan], 'y': [np.nan, np.nan]},
  134. index=[.1, .9])
  135. assert_frame_equal(result, expected)
  136. def test_quantile_datetime(self):
  137. df = DataFrame({'a': pd.to_datetime(['2010', '2011']), 'b': [0, 5]})
  138. # exclude datetime
  139. result = df.quantile(.5)
  140. expected = Series([2.5], index=['b'])
  141. # datetime
  142. result = df.quantile(.5, numeric_only=False)
  143. expected = Series([Timestamp('2010-07-02 12:00:00'), 2.5],
  144. index=['a', 'b'],
  145. name=0.5)
  146. assert_series_equal(result, expected)
  147. # datetime w/ multi
  148. result = df.quantile([.5], numeric_only=False)
  149. expected = DataFrame([[Timestamp('2010-07-02 12:00:00'), 2.5]],
  150. index=[.5], columns=['a', 'b'])
  151. assert_frame_equal(result, expected)
  152. # axis = 1
  153. df['c'] = pd.to_datetime(['2011', '2012'])
  154. result = df[['a', 'c']].quantile(.5, axis=1, numeric_only=False)
  155. expected = Series([Timestamp('2010-07-02 12:00:00'),
  156. Timestamp('2011-07-02 12:00:00')],
  157. index=[0, 1],
  158. name=0.5)
  159. assert_series_equal(result, expected)
  160. result = df[['a', 'c']].quantile([.5], axis=1, numeric_only=False)
  161. expected = DataFrame([[Timestamp('2010-07-02 12:00:00'),
  162. Timestamp('2011-07-02 12:00:00')]],
  163. index=[0.5], columns=[0, 1])
  164. assert_frame_equal(result, expected)
  165. # empty when numeric_only=True
  166. # FIXME (gives empty frame in 0.18.1, broken in 0.19.0)
  167. # result = df[['a', 'c']].quantile(.5)
  168. # result = df[['a', 'c']].quantile([.5])
  169. def test_quantile_invalid(self):
  170. msg = 'percentiles should all be in the interval \\[0, 1\\]'
  171. for invalid in [-1, 2, [0.5, -1], [0.5, 2]]:
  172. with pytest.raises(ValueError, match=msg):
  173. self.tsframe.quantile(invalid)
  174. def test_quantile_box(self):
  175. df = DataFrame({'A': [pd.Timestamp('2011-01-01'),
  176. pd.Timestamp('2011-01-02'),
  177. pd.Timestamp('2011-01-03')],
  178. 'B': [pd.Timestamp('2011-01-01', tz='US/Eastern'),
  179. pd.Timestamp('2011-01-02', tz='US/Eastern'),
  180. pd.Timestamp('2011-01-03', tz='US/Eastern')],
  181. 'C': [pd.Timedelta('1 days'),
  182. pd.Timedelta('2 days'),
  183. pd.Timedelta('3 days')]})
  184. res = df.quantile(0.5, numeric_only=False)
  185. exp = pd.Series([pd.Timestamp('2011-01-02'),
  186. pd.Timestamp('2011-01-02', tz='US/Eastern'),
  187. pd.Timedelta('2 days')],
  188. name=0.5, index=['A', 'B', 'C'])
  189. tm.assert_series_equal(res, exp)
  190. res = df.quantile([0.5], numeric_only=False)
  191. exp = pd.DataFrame([[pd.Timestamp('2011-01-02'),
  192. pd.Timestamp('2011-01-02', tz='US/Eastern'),
  193. pd.Timedelta('2 days')]],
  194. index=[0.5], columns=['A', 'B', 'C'])
  195. tm.assert_frame_equal(res, exp)
  196. # DatetimeBlock may be consolidated and contain NaT in different loc
  197. df = DataFrame({'A': [pd.Timestamp('2011-01-01'),
  198. pd.NaT,
  199. pd.Timestamp('2011-01-02'),
  200. pd.Timestamp('2011-01-03')],
  201. 'a': [pd.Timestamp('2011-01-01'),
  202. pd.Timestamp('2011-01-02'),
  203. pd.NaT,
  204. pd.Timestamp('2011-01-03')],
  205. 'B': [pd.Timestamp('2011-01-01', tz='US/Eastern'),
  206. pd.NaT,
  207. pd.Timestamp('2011-01-02', tz='US/Eastern'),
  208. pd.Timestamp('2011-01-03', tz='US/Eastern')],
  209. 'b': [pd.Timestamp('2011-01-01', tz='US/Eastern'),
  210. pd.Timestamp('2011-01-02', tz='US/Eastern'),
  211. pd.NaT,
  212. pd.Timestamp('2011-01-03', tz='US/Eastern')],
  213. 'C': [pd.Timedelta('1 days'),
  214. pd.Timedelta('2 days'),
  215. pd.Timedelta('3 days'),
  216. pd.NaT],
  217. 'c': [pd.NaT,
  218. pd.Timedelta('1 days'),
  219. pd.Timedelta('2 days'),
  220. pd.Timedelta('3 days')]},
  221. columns=list('AaBbCc'))
  222. res = df.quantile(0.5, numeric_only=False)
  223. exp = pd.Series([pd.Timestamp('2011-01-02'),
  224. pd.Timestamp('2011-01-02'),
  225. pd.Timestamp('2011-01-02', tz='US/Eastern'),
  226. pd.Timestamp('2011-01-02', tz='US/Eastern'),
  227. pd.Timedelta('2 days'),
  228. pd.Timedelta('2 days')],
  229. name=0.5, index=list('AaBbCc'))
  230. tm.assert_series_equal(res, exp)
  231. res = df.quantile([0.5], numeric_only=False)
  232. exp = pd.DataFrame([[pd.Timestamp('2011-01-02'),
  233. pd.Timestamp('2011-01-02'),
  234. pd.Timestamp('2011-01-02', tz='US/Eastern'),
  235. pd.Timestamp('2011-01-02', tz='US/Eastern'),
  236. pd.Timedelta('2 days'),
  237. pd.Timedelta('2 days')]],
  238. index=[0.5], columns=list('AaBbCc'))
  239. tm.assert_frame_equal(res, exp)
  240. def test_quantile_nan(self):
  241. # GH 14357 - float block where some cols have missing values
  242. df = DataFrame({'a': np.arange(1, 6.0), 'b': np.arange(1, 6.0)})
  243. df.iloc[-1, 1] = np.nan
  244. res = df.quantile(0.5)
  245. exp = Series([3.0, 2.5], index=['a', 'b'], name=0.5)
  246. tm.assert_series_equal(res, exp)
  247. res = df.quantile([0.5, 0.75])
  248. exp = DataFrame({'a': [3.0, 4.0], 'b': [2.5, 3.25]}, index=[0.5, 0.75])
  249. tm.assert_frame_equal(res, exp)
  250. res = df.quantile(0.5, axis=1)
  251. exp = Series(np.arange(1.0, 6.0), name=0.5)
  252. tm.assert_series_equal(res, exp)
  253. res = df.quantile([0.5, 0.75], axis=1)
  254. exp = DataFrame([np.arange(1.0, 6.0)] * 2, index=[0.5, 0.75])
  255. tm.assert_frame_equal(res, exp)
  256. # full-nan column
  257. df['b'] = np.nan
  258. res = df.quantile(0.5)
  259. exp = Series([3.0, np.nan], index=['a', 'b'], name=0.5)
  260. tm.assert_series_equal(res, exp)
  261. res = df.quantile([0.5, 0.75])
  262. exp = DataFrame({'a': [3.0, 4.0], 'b': [np.nan, np.nan]},
  263. index=[0.5, 0.75])
  264. tm.assert_frame_equal(res, exp)
  265. def test_quantile_nat(self):
  266. # full NaT column
  267. df = DataFrame({'a': [pd.NaT, pd.NaT, pd.NaT]})
  268. res = df.quantile(0.5, numeric_only=False)
  269. exp = Series([pd.NaT], index=['a'], name=0.5)
  270. tm.assert_series_equal(res, exp)
  271. res = df.quantile([0.5], numeric_only=False)
  272. exp = DataFrame({'a': [pd.NaT]}, index=[0.5])
  273. tm.assert_frame_equal(res, exp)
  274. # mixed non-null / full null column
  275. df = DataFrame({'a': [pd.Timestamp('2012-01-01'),
  276. pd.Timestamp('2012-01-02'),
  277. pd.Timestamp('2012-01-03')],
  278. 'b': [pd.NaT, pd.NaT, pd.NaT]})
  279. res = df.quantile(0.5, numeric_only=False)
  280. exp = Series([pd.Timestamp('2012-01-02'), pd.NaT], index=['a', 'b'],
  281. name=0.5)
  282. tm.assert_series_equal(res, exp)
  283. res = df.quantile([0.5], numeric_only=False)
  284. exp = DataFrame([[pd.Timestamp('2012-01-02'), pd.NaT]], index=[0.5],
  285. columns=['a', 'b'])
  286. tm.assert_frame_equal(res, exp)
  287. def test_quantile_empty(self):
  288. # floats
  289. df = DataFrame(columns=['a', 'b'], dtype='float64')
  290. res = df.quantile(0.5)
  291. exp = Series([np.nan, np.nan], index=['a', 'b'], name=0.5)
  292. tm.assert_series_equal(res, exp)
  293. res = df.quantile([0.5])
  294. exp = DataFrame([[np.nan, np.nan]], columns=['a', 'b'], index=[0.5])
  295. tm.assert_frame_equal(res, exp)
  296. # FIXME (gives empty frame in 0.18.1, broken in 0.19.0)
  297. # res = df.quantile(0.5, axis=1)
  298. # res = df.quantile([0.5], axis=1)
  299. # ints
  300. df = DataFrame(columns=['a', 'b'], dtype='int64')
  301. # FIXME (gives empty frame in 0.18.1, broken in 0.19.0)
  302. # res = df.quantile(0.5)
  303. # datetimes
  304. df = DataFrame(columns=['a', 'b'], dtype='datetime64[ns]')
  305. # FIXME (gives NaNs instead of NaT in 0.18.1 or 0.19.0)
  306. # res = df.quantile(0.5, numeric_only=False)