test_usecols_basic.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. """
  2. Tests the usecols functionality during parsing
  3. for all of the parsers defined in parsers.py
  4. """
  5. from io import StringIO
  6. import numpy as np
  7. import pytest
  8. from pandas.errors import ParserError
  9. from pandas import (
  10. DataFrame,
  11. Index,
  12. )
  13. import pandas._testing as tm
  14. _msg_validate_usecols_arg = (
  15. "'usecols' must either be list-like "
  16. "of all strings, all unicode, all "
  17. "integers or a callable."
  18. )
  19. _msg_validate_usecols_names = (
  20. "Usecols do not match columns, columns expected but not found: {0}"
  21. )
  22. # TODO(1.4): Change to xfails at release time
  23. pytestmark = pytest.mark.usefixtures("pyarrow_skip")
  24. def test_raise_on_mixed_dtype_usecols(all_parsers):
  25. # See gh-12678
  26. data = """a,b,c
  27. 1000,2000,3000
  28. 4000,5000,6000
  29. """
  30. usecols = [0, "b", 2]
  31. parser = all_parsers
  32. with pytest.raises(ValueError, match=_msg_validate_usecols_arg):
  33. parser.read_csv(StringIO(data), usecols=usecols)
  34. @pytest.mark.parametrize("usecols", [(1, 2), ("b", "c")])
  35. def test_usecols(all_parsers, usecols):
  36. data = """\
  37. a,b,c
  38. 1,2,3
  39. 4,5,6
  40. 7,8,9
  41. 10,11,12"""
  42. parser = all_parsers
  43. result = parser.read_csv(StringIO(data), usecols=usecols)
  44. expected = DataFrame([[2, 3], [5, 6], [8, 9], [11, 12]], columns=["b", "c"])
  45. tm.assert_frame_equal(result, expected)
  46. def test_usecols_with_names(all_parsers):
  47. data = """\
  48. a,b,c
  49. 1,2,3
  50. 4,5,6
  51. 7,8,9
  52. 10,11,12"""
  53. parser = all_parsers
  54. names = ["foo", "bar"]
  55. result = parser.read_csv(StringIO(data), names=names, usecols=[1, 2], header=0)
  56. expected = DataFrame([[2, 3], [5, 6], [8, 9], [11, 12]], columns=names)
  57. tm.assert_frame_equal(result, expected)
  58. @pytest.mark.parametrize(
  59. "names,usecols", [(["b", "c"], [1, 2]), (["a", "b", "c"], ["b", "c"])]
  60. )
  61. def test_usecols_relative_to_names(all_parsers, names, usecols):
  62. data = """\
  63. 1,2,3
  64. 4,5,6
  65. 7,8,9
  66. 10,11,12"""
  67. parser = all_parsers
  68. result = parser.read_csv(StringIO(data), names=names, header=None, usecols=usecols)
  69. expected = DataFrame([[2, 3], [5, 6], [8, 9], [11, 12]], columns=["b", "c"])
  70. tm.assert_frame_equal(result, expected)
  71. def test_usecols_relative_to_names2(all_parsers):
  72. # see gh-5766
  73. data = """\
  74. 1,2,3
  75. 4,5,6
  76. 7,8,9
  77. 10,11,12"""
  78. parser = all_parsers
  79. result = parser.read_csv(
  80. StringIO(data), names=["a", "b"], header=None, usecols=[0, 1]
  81. )
  82. expected = DataFrame([[1, 2], [4, 5], [7, 8], [10, 11]], columns=["a", "b"])
  83. tm.assert_frame_equal(result, expected)
  84. def test_usecols_name_length_conflict(all_parsers):
  85. data = """\
  86. 1,2,3
  87. 4,5,6
  88. 7,8,9
  89. 10,11,12"""
  90. parser = all_parsers
  91. msg = "Number of passed names did not match number of header fields in the file"
  92. with pytest.raises(ValueError, match=msg):
  93. parser.read_csv(StringIO(data), names=["a", "b"], header=None, usecols=[1])
  94. def test_usecols_single_string(all_parsers):
  95. # see gh-20558
  96. parser = all_parsers
  97. data = """foo, bar, baz
  98. 1000, 2000, 3000
  99. 4000, 5000, 6000"""
  100. with pytest.raises(ValueError, match=_msg_validate_usecols_arg):
  101. parser.read_csv(StringIO(data), usecols="foo")
  102. @pytest.mark.parametrize(
  103. "data", ["a,b,c,d\n1,2,3,4\n5,6,7,8", "a,b,c,d\n1,2,3,4,\n5,6,7,8,"]
  104. )
  105. def test_usecols_index_col_false(all_parsers, data):
  106. # see gh-9082
  107. parser = all_parsers
  108. usecols = ["a", "c", "d"]
  109. expected = DataFrame({"a": [1, 5], "c": [3, 7], "d": [4, 8]})
  110. result = parser.read_csv(StringIO(data), usecols=usecols, index_col=False)
  111. tm.assert_frame_equal(result, expected)
  112. @pytest.mark.parametrize("index_col", ["b", 0])
  113. @pytest.mark.parametrize("usecols", [["b", "c"], [1, 2]])
  114. def test_usecols_index_col_conflict(all_parsers, usecols, index_col):
  115. # see gh-4201: test that index_col as integer reflects usecols
  116. parser = all_parsers
  117. data = "a,b,c,d\nA,a,1,one\nB,b,2,two"
  118. expected = DataFrame({"c": [1, 2]}, index=Index(["a", "b"], name="b"))
  119. result = parser.read_csv(StringIO(data), usecols=usecols, index_col=index_col)
  120. tm.assert_frame_equal(result, expected)
  121. def test_usecols_index_col_conflict2(all_parsers):
  122. # see gh-4201: test that index_col as integer reflects usecols
  123. parser = all_parsers
  124. data = "a,b,c,d\nA,a,1,one\nB,b,2,two"
  125. expected = DataFrame({"b": ["a", "b"], "c": [1, 2], "d": ("one", "two")})
  126. expected = expected.set_index(["b", "c"])
  127. result = parser.read_csv(
  128. StringIO(data), usecols=["b", "c", "d"], index_col=["b", "c"]
  129. )
  130. tm.assert_frame_equal(result, expected)
  131. def test_usecols_implicit_index_col(all_parsers):
  132. # see gh-2654
  133. parser = all_parsers
  134. data = "a,b,c\n4,apple,bat,5.7\n8,orange,cow,10"
  135. result = parser.read_csv(StringIO(data), usecols=["a", "b"])
  136. expected = DataFrame({"a": ["apple", "orange"], "b": ["bat", "cow"]}, index=[4, 8])
  137. tm.assert_frame_equal(result, expected)
  138. def test_usecols_index_col_middle(all_parsers):
  139. # GH#9098
  140. parser = all_parsers
  141. data = """a,b,c,d
  142. 1,2,3,4
  143. """
  144. result = parser.read_csv(StringIO(data), usecols=["b", "c", "d"], index_col="c")
  145. expected = DataFrame({"b": [2], "d": [4]}, index=Index([3], name="c"))
  146. tm.assert_frame_equal(result, expected)
  147. def test_usecols_index_col_end(all_parsers):
  148. # GH#9098
  149. parser = all_parsers
  150. data = """a,b,c,d
  151. 1,2,3,4
  152. """
  153. result = parser.read_csv(StringIO(data), usecols=["b", "c", "d"], index_col="d")
  154. expected = DataFrame({"b": [2], "c": [3]}, index=Index([4], name="d"))
  155. tm.assert_frame_equal(result, expected)
  156. def test_usecols_regex_sep(all_parsers):
  157. # see gh-2733
  158. parser = all_parsers
  159. data = "a b c\n4 apple bat 5.7\n8 orange cow 10"
  160. result = parser.read_csv(StringIO(data), sep=r"\s+", usecols=("a", "b"))
  161. expected = DataFrame({"a": ["apple", "orange"], "b": ["bat", "cow"]}, index=[4, 8])
  162. tm.assert_frame_equal(result, expected)
  163. def test_usecols_with_whitespace(all_parsers):
  164. parser = all_parsers
  165. data = "a b c\n4 apple bat 5.7\n8 orange cow 10"
  166. result = parser.read_csv(StringIO(data), delim_whitespace=True, usecols=("a", "b"))
  167. expected = DataFrame({"a": ["apple", "orange"], "b": ["bat", "cow"]}, index=[4, 8])
  168. tm.assert_frame_equal(result, expected)
  169. @pytest.mark.parametrize(
  170. "usecols,expected",
  171. [
  172. # Column selection by index.
  173. ([0, 1], DataFrame(data=[[1000, 2000], [4000, 5000]], columns=["2", "0"])),
  174. # Column selection by name.
  175. (
  176. ["0", "1"],
  177. DataFrame(data=[[2000, 3000], [5000, 6000]], columns=["0", "1"]),
  178. ),
  179. ],
  180. )
  181. def test_usecols_with_integer_like_header(all_parsers, usecols, expected):
  182. parser = all_parsers
  183. data = """2,0,1
  184. 1000,2000,3000
  185. 4000,5000,6000"""
  186. result = parser.read_csv(StringIO(data), usecols=usecols)
  187. tm.assert_frame_equal(result, expected)
  188. def test_empty_usecols(all_parsers):
  189. data = "a,b,c\n1,2,3\n4,5,6"
  190. expected = DataFrame(columns=Index([]))
  191. parser = all_parsers
  192. result = parser.read_csv(StringIO(data), usecols=set())
  193. tm.assert_frame_equal(result, expected)
  194. def test_np_array_usecols(all_parsers):
  195. # see gh-12546
  196. parser = all_parsers
  197. data = "a,b,c\n1,2,3"
  198. usecols = np.array(["a", "b"])
  199. expected = DataFrame([[1, 2]], columns=usecols)
  200. result = parser.read_csv(StringIO(data), usecols=usecols)
  201. tm.assert_frame_equal(result, expected)
  202. @pytest.mark.parametrize(
  203. "usecols,expected",
  204. [
  205. (
  206. lambda x: x.upper() in ["AAA", "BBB", "DDD"],
  207. DataFrame(
  208. {
  209. "AaA": {
  210. 0: 0.056674972999999997,
  211. 1: 2.6132309819999997,
  212. 2: 3.5689350380000002,
  213. },
  214. "bBb": {0: 8, 1: 2, 2: 7},
  215. "ddd": {0: "a", 1: "b", 2: "a"},
  216. }
  217. ),
  218. ),
  219. (lambda x: False, DataFrame(columns=Index([]))),
  220. ],
  221. )
  222. def test_callable_usecols(all_parsers, usecols, expected):
  223. # see gh-14154
  224. data = """AaA,bBb,CCC,ddd
  225. 0.056674973,8,True,a
  226. 2.613230982,2,False,b
  227. 3.568935038,7,False,a"""
  228. parser = all_parsers
  229. result = parser.read_csv(StringIO(data), usecols=usecols)
  230. tm.assert_frame_equal(result, expected)
  231. @pytest.mark.parametrize("usecols", [["a", "c"], lambda x: x in ["a", "c"]])
  232. def test_incomplete_first_row(all_parsers, usecols):
  233. # see gh-6710
  234. data = "1,2\n1,2,3"
  235. parser = all_parsers
  236. names = ["a", "b", "c"]
  237. expected = DataFrame({"a": [1, 1], "c": [np.nan, 3]})
  238. result = parser.read_csv(StringIO(data), names=names, usecols=usecols)
  239. tm.assert_frame_equal(result, expected)
  240. @pytest.mark.parametrize(
  241. "data,usecols,kwargs,expected",
  242. [
  243. # see gh-8985
  244. (
  245. "19,29,39\n" * 2 + "10,20,30,40",
  246. [0, 1, 2],
  247. {"header": None},
  248. DataFrame([[19, 29, 39], [19, 29, 39], [10, 20, 30]]),
  249. ),
  250. # see gh-9549
  251. (
  252. ("A,B,C\n1,2,3\n3,4,5\n1,2,4,5,1,6\n1,2,3,,,1,\n1,2,3\n5,6,7"),
  253. ["A", "B", "C"],
  254. {},
  255. DataFrame(
  256. {
  257. "A": [1, 3, 1, 1, 1, 5],
  258. "B": [2, 4, 2, 2, 2, 6],
  259. "C": [3, 5, 4, 3, 3, 7],
  260. }
  261. ),
  262. ),
  263. ],
  264. )
  265. def test_uneven_length_cols(all_parsers, data, usecols, kwargs, expected):
  266. # see gh-8985
  267. parser = all_parsers
  268. result = parser.read_csv(StringIO(data), usecols=usecols, **kwargs)
  269. tm.assert_frame_equal(result, expected)
  270. @pytest.mark.parametrize(
  271. "usecols,kwargs,expected,msg",
  272. [
  273. (
  274. ["a", "b", "c", "d"],
  275. {},
  276. DataFrame({"a": [1, 5], "b": [2, 6], "c": [3, 7], "d": [4, 8]}),
  277. None,
  278. ),
  279. (
  280. ["a", "b", "c", "f"],
  281. {},
  282. None,
  283. _msg_validate_usecols_names.format(r"\['f'\]"),
  284. ),
  285. (["a", "b", "f"], {}, None, _msg_validate_usecols_names.format(r"\['f'\]")),
  286. (
  287. ["a", "b", "f", "g"],
  288. {},
  289. None,
  290. _msg_validate_usecols_names.format(r"\[('f', 'g'|'g', 'f')\]"),
  291. ),
  292. # see gh-14671
  293. (
  294. None,
  295. {"header": 0, "names": ["A", "B", "C", "D"]},
  296. DataFrame({"A": [1, 5], "B": [2, 6], "C": [3, 7], "D": [4, 8]}),
  297. None,
  298. ),
  299. (
  300. ["A", "B", "C", "f"],
  301. {"header": 0, "names": ["A", "B", "C", "D"]},
  302. None,
  303. _msg_validate_usecols_names.format(r"\['f'\]"),
  304. ),
  305. (
  306. ["A", "B", "f"],
  307. {"names": ["A", "B", "C", "D"]},
  308. None,
  309. _msg_validate_usecols_names.format(r"\['f'\]"),
  310. ),
  311. ],
  312. )
  313. def test_raises_on_usecols_names_mismatch(all_parsers, usecols, kwargs, expected, msg):
  314. data = "a,b,c,d\n1,2,3,4\n5,6,7,8"
  315. kwargs.update(usecols=usecols)
  316. parser = all_parsers
  317. if expected is None:
  318. with pytest.raises(ValueError, match=msg):
  319. parser.read_csv(StringIO(data), **kwargs)
  320. else:
  321. result = parser.read_csv(StringIO(data), **kwargs)
  322. tm.assert_frame_equal(result, expected)
  323. @pytest.mark.parametrize("usecols", [["A", "C"], [0, 2]])
  324. def test_usecols_subset_names_mismatch_orig_columns(all_parsers, usecols):
  325. data = "a,b,c,d\n1,2,3,4\n5,6,7,8"
  326. names = ["A", "B", "C", "D"]
  327. parser = all_parsers
  328. result = parser.read_csv(StringIO(data), header=0, names=names, usecols=usecols)
  329. expected = DataFrame({"A": [1, 5], "C": [3, 7]})
  330. tm.assert_frame_equal(result, expected)
  331. @pytest.mark.parametrize("names", [None, ["a", "b"]])
  332. def test_usecols_indices_out_of_bounds(all_parsers, names):
  333. # GH#25623 & GH 41130; enforced in 2.0
  334. parser = all_parsers
  335. data = """
  336. a,b
  337. 1,2
  338. """
  339. with pytest.raises(ParserError, match="Defining usecols without of bounds"):
  340. parser.read_csv(StringIO(data), usecols=[0, 2], names=names, header=0)
  341. def test_usecols_additional_columns(all_parsers):
  342. # GH#46997
  343. parser = all_parsers
  344. usecols = lambda header: header.strip() in ["a", "b", "c"]
  345. result = parser.read_csv(StringIO("a,b\nx,y,z"), index_col=False, usecols=usecols)
  346. expected = DataFrame({"a": ["x"], "b": "y"})
  347. tm.assert_frame_equal(result, expected)
  348. def test_usecols_additional_columns_integer_columns(all_parsers):
  349. # GH#46997
  350. parser = all_parsers
  351. usecols = lambda header: header.strip() in ["0", "1"]
  352. result = parser.read_csv(StringIO("0,1\nx,y,z"), index_col=False, usecols=usecols)
  353. expected = DataFrame({"0": ["x"], "1": "y"})
  354. tm.assert_frame_equal(result, expected)