Pandas read_table(): Read TSV Files and Validate Imports

Use read_table() to import tab-separated or other delimited files. Define the separator, heading and field types, then inspect records before analysis.

Read a tab-separated student table 🔝

read_table() defaults to the tab delimiter. Tabs separate fields; line endings separate records. The method is supported in current Pandas. read_csv() with sep="\t" is an equivalent way to read TSV data. The extension alone does not determine the separator.

import pandas as pd
import tempfile
from pathlib import Path
from io import StringIO, BytesIO
student_csv = 'id,name,class,mark,gender\n1,John Deo,Four,75,female\n2,Max Ruin,Three,85,male\n3,Arnold,Three,55,male\n4,Krish Star,Four,60,female\n5,John Mike,Four,60,female\n6,Alex John,Four,55,male\n7,My John Rob,Fifth,78,male\n8,Asruid,Five,85,male\n9,Tes Qry,Six,78,male\n10,Big John,Four,55,female\n11,Ronald,Six,89,female\n12,Recky,Six,94,female\n13,Kty,Seven,88,female\n14,Bigy,Seven,88,female\n15,Tade Row,Four,88,male\n16,Gimmy,Four,88,male\n17,Tumyu,Six,54,male\n18,Honny,Five,75,male\n19,Tinny,Nine,18,male\n20,Jackly,Nine,65,female\n21,Babby John,Four,69,female\n22,Reggid,Seven,55,female\n23,Herod,Eight,79,male\n24,Tiddy Now,Seven,78,male\n25,Giff Tow,Seven,88,male\n26,Crelea,Seven,79,male\n27,Big Nose,Three,81,female\n28,Rojj Base,Seven,86,female\n29,Tess Played,Seven,55,male\n30,Reppy Red,Six,79,female\n31,Marry Toeey,Four,88,male\n32,Binn Rott,Seven,90,female\n33,Kenn Rein,Six,96,female\n34,Gain Toe,Seven,69,male\n35,Rows Noump,Six,88,female\n'
students = pd.read_csv(StringIO(student_csv))
students = students.rename(columns={"class": "class1", "gender": "sex"})
student_tsv = students.to_csv(sep="\t", index=False)
df = pd.read_table(StringIO(student_tsv))
print(df.head())
print("Rows:", len(df))
equivalent = pd.read_csv(StringIO(student_tsv), sep="\t")
assert equivalent.equals(df)

Expected output

   id        name class1  mark     sex
0   1    John Deo   Four    75  female
1   2    Max Ruin  Three    85    male
2   3      Arnold  Three    55    male
3   4  Krish Star   Four    60  female
4   5   John Mike   Four    60  female
Rows: 35

Read a local TSV file 🔝

Use the actual file path. Relative paths use the current working directory. On Windows, a raw path such as r"D:\student.tsv" avoids accidental escape sequences. The notebook writes and reads a temporary file; see student sample data.

with tempfile.TemporaryDirectory(dir=Path.cwd()) as folder:
    target = Path(folder) / "student.tsv"
    target.write_text(student_tsv, encoding="utf-8")
    loaded = pd.read_table(target, encoding="utf-8")
    print("Same records:", loaded.equals(df))
    assert loaded.equals(df)
# Local file: pd.read_table(r"D:\student.tsv")

Expected output

Same records: True

Example 1: use a custom delimiter 🔝

sep overrides the default tab delimiter. Here the semicolon-separated text is embedded so the example needs no data.txt upload.

text = "Name;Age;ID\nRavi;30;001\nRaju;40;002\n"
people = pd.read_table(StringIO(text), sep=";", dtype={"ID": "string"})
print(people)
assert people["ID"].tolist() == ["001", "002"]

Expected output

   Name  Age   ID
0  Ravi   30  001
1  Raju   40  002

Example 2: skip specific physical lines 🔝

skiprows=[0, 2] skips the first and third physical lines. In this sample they are a report title and an unwanted record. Keep the heading line or specify header/names explicitly.

text = "Practice report\nName\tAge\nIgnore\t99\nRavi\t30\nRaju\t40\n"
skipped = pd.read_table(StringIO(text), skiprows=[0, 2])
print(skipped)
assert skipped["Name"].tolist() == ["Ravi", "Raju"]

Expected output

   Name  Age
0  Ravi   30
1  Raju   40

Example 3: select columns and limit rows 🔝

usecols selects fields; its list order does not guarantee output order. Select columns again when a particular order matters. nrows limits data rows.

text = "ID\tName\tAge\n001\tRavi\t30\n002\tRaju\t40\n003\tAlex\t25\n"
selected = pd.read_table(StringIO(text), usecols=["Name", "Age"], nrows=2)
print(selected.loc[:, ["Name", "Age"]])
assert selected.shape == (2, 2)

Expected output

   Name  Age
0  Ravi   30
1  Raju   40

Example 4: define missing markers 🔝

na_values adds markers when keep_default_na=True. With False, only your declared markers are treated as missing. Per-column rules help retain legitimate text such as the region code NA. See missing-value checks.

text = "Name\tAge\tRegion\nRavi\t30\tNA\nRaju\t?\tEU\nAlex\tNA\tNA\n"
missing = pd.read_table(StringIO(text), na_values={"Age": ["NA", "?"]}, keep_default_na=False)
print(missing)
assert missing["Age"].isna().sum() == 2
assert missing["Region"].tolist() == ["NA", "EU", "NA"]

Expected output

   Name   Age Region
0  Ravi  30.0     NA
1  Raju   NaN     EU
2  Alex   NaN     NA

Example 5: parse dates and inspect failures 🔝

For known valid dates, use parse_dates and date_format. For mixed or invalid dates, retain text and apply to_datetime() with an explicit format and review policy.

text = "ID\tDate\n1\t2026-01-02\n2\t2026-01-03\n"
dated = pd.read_table(StringIO(text), parse_dates=["Date"], date_format="%Y-%m-%d")
print(dated)
assert dated.iloc[0]["Date"] == pd.Timestamp("2026-01-02")
raw_dates = pd.read_table(StringIO("ID\tDate\n1\t2026-01-02\n2\tbad\n"))
parsed = pd.to_datetime(raw_dates["Date"], format="%Y-%m-%d", errors="coerce")
print("Invalid date IDs:", raw_dates.loc[parsed.isna(), "ID"].tolist())

Expected output

   ID       Date
0   1 2026-01-02
1   2 2026-01-03
Invalid date IDs: [2]

Example 6: choose an index column 🔝

index_col uses a field as row labels. IDs with leading zeros need a string dtype during reading. For later changes, use set_index() or reset_index().

text = "ID\tName\tAge\n001\tRavi\t30\n002\tRaju\t40\n"
indexed = pd.read_table(StringIO(text), index_col="ID", dtype={"ID": "string"})
print(indexed)
assert indexed.index.tolist() == ["001", "002"]

Expected output

     Name  Age
ID            
001  Ravi   30
002  Raju   40

Example 7: specify encoding for bytes 🔝

encoding controls file or binary-buffer decoding. A StringIO buffer is already text. Keep decoding errors visible so incorrect encoding can be diagnosed.

binary = BytesIO("Name\tAge\nJosé\t30\n".encode("utf-8-sig"))
decoded = pd.read_table(binary, encoding="utf-8-sig")
print(decoded)
assert decoded.iloc[0]["Name"] == "José"

Expected output

   Name  Age
0  José   30

Example 8: handle malformed lines deliberately 🔝

The default error policy stops on lines with too many fields. on_bad_lines="skip" discards them, so compare counts and retain the source. This option does not validate numeric values; short rows may produce missing fields.

text = "ID\tAmount\n1\t5\n2\t8\textra\n3\t9\n"
try:
    pd.read_table(StringIO(text))
except pd.errors.ParserError:
    print("Extra field detected: default import stopped.")
skipped = pd.read_table(StringIO(text), on_bad_lines="skip")
print(skipped)
print("Kept rows:", len(skipped))
assert skipped["ID"].tolist() == [1, 3]

Expected output

Extra field detected: default import stopped.
   ID  Amount
0   1       5
1   3       9
Kept rows: 2

Example 9: process records in chunks 🔝

chunksize returns a reader yielding DataFrames. Accumulate results without retaining every chunk. Chunking limits each read; later operations still determine total memory use.

row_count = 0
mark_total = 0
with pd.read_table(StringIO(student_tsv), chunksize=3, usecols=["id", "mark"]) as reader:
    for chunk in reader:
        row_count += len(chunk)
        mark_total += chunk["mark"].sum()
print("Rows:", row_count, "Marks:", mark_total)
assert row_count == len(students) and mark_total == students["mark"].sum()

Expected output

Rows: 35 Marks: 2613

Example 10: define field types 🔝

Use string for identifiers and nullable Int64 for integer fields that may be missing. Invalid numeric text still needs validation. See dtype inspection and astype().

text = "ID\tName\tAge\n001\tRavi\t30\n002\tRaju\t\n"
typed = pd.read_table(StringIO(text), dtype={"ID": "string", "Age": "Int64"})
print(typed)
print(typed.dtypes)
assert typed["ID"].tolist() == ["001", "002"]
assert typed["Age"].isna().sum() == 1

Expected output

    ID  Name   Age
0  001  Ravi    30
1  002  Raju  <NA>
ID      string
Name       str
Age      Int64
dtype: object

Read a headerless file or replace headings 🔝

Use header=None and names for a headerless file. When replacing an existing heading, add header=0; otherwise the old heading is read as a data record.

text = "001\tRavi\t30\n002\tRaju\t40\n"
headerless = pd.read_table(StringIO(text), header=None, names=["ID", "Name", "Age"], dtype={"ID": "string"})
print(headerless)
renamed = pd.read_table(StringIO(student_tsv), header=0,
    names=["student_id", "student_name", "student_class", "score", "gender"])
print(renamed.head(2))
assert len(renamed) == len(students)

Expected output

    ID  Name  Age
0  001  Ravi   30
1  002  Raju   40
   student_id student_name student_class  score  gender
0           1     John Deo          Four     75  female
1           2     Max Ruin         Three     85    male

Keep quoted tabs inside a field 🔝

A tab inside a properly quoted field belongs to that value. Splitting each line manually on tabs would misread it. Choose separator and quoting rules to match the producer.

text = 'ID\tNote\n1\t"blue\tpen"\n2\tplain\n'
quoted = pd.read_table(StringIO(text))
print("First note:", repr(quoted.iloc[0]["Note"]))
print("Shape:", quoted.shape)
assert quoted.iloc[0]["Note"] == "blue\tpen" and quoted.shape == (2, 2)

Expected output

First note: 'blue\tpen'
Shape: (2, 2)

Practical workflow: validate a TSV sales extract 🔝

For this synthetic report, require an ID, non-negative numeric amount and valid ISO date. Preserve raw records and retain rejected rows for review. Use the Data Cleaning hub for related checks.

sales_tsv = "ID\tDate\tAmount\n001\t2026-01-02\t5.25\n002\t2026-01-03\t20\n003\tbad\t8\n004\t2026-01-04\tpending\n"
raw = pd.read_table(StringIO(sales_tsv), dtype="string", keep_default_na=False)
clean = raw.copy()
clean["ID"] = raw["ID"].str.strip()
clean["Date"] = pd.to_datetime(raw["Date"], format="%Y-%m-%d", errors="coerce")
clean["Amount"] = pd.to_numeric(raw["Amount"], errors="coerce")
valid = clean["ID"].ne("") & clean["Date"].notna() & clean["Amount"].ge(0).fillna(False)
accepted = clean.loc[valid].copy()
review = raw.loc[~valid].copy()
print(accepted)
print("Review IDs:", review["ID"].tolist())
print("Accepted revenue:", accepted["Amount"].sum())
assert accepted["ID"].tolist() == ["001", "002"]
assert accepted["Amount"].sum() == 25.25
assert len(accepted) + len(review) == len(raw)

Expected output

    ID       Date  Amount
0  001 2026-01-02    5.25
1  002 2026-01-03    20.0
Review IDs: ['003', '004']
Accepted revenue: 25.25

Export TSV and check its contents again 🔝

Pandas uses to_csv() with sep="\t" to write TSV. Use index=False to omit disposable row labels, then preserve ID types when reloading. See export options.

exported = accepted.to_csv(sep="\t", index=False, date_format="%Y-%m-%d")
print(exported.rstrip())
checked = pd.read_table(StringIO(exported), dtype={"ID": "string"})
assert checked["ID"].tolist() == ["001", "002"]
assert checked["Amount"].sum() == 25.25
# Optional Colab download:
# accepted.to_csv("accepted_sales.tsv", sep="\t", index=False, date_format="%Y-%m-%d")
# from google.colab import files
# files.download("accepted_sales.tsv")

Expected output

ID	Date	Amount

001	2026-01-02	5.25

002	2026-01-03	20.0

Common questions 🔝

Is read_table() deprecated? It is supported in current Pandas. How does it differ from read_csv()? Its default separator is a tab rather than a comma. Does a .tsv extension force tab parsing? The separator setting controls parsing. Why did everything become one column? Check the delimiter. Why did zeros disappear from IDs? Declare a string dtype before inference. Does skipping bad lines clean invalid values? No; validate fields separately. Does chunksize return a DataFrame? It returns a reader yielding DataFrames. Can I read compressed text? Supported filename extensions allow compression inference. Can I parse space-separated text? Use an appropriate separator, such as a whitespace regex, when consistent with the file format.

Exercise: read high student marks 🔝

Read only id, name and mark from student_tsv. Select students with marks at least 90 and export those records without an index.

Exercise solution 🔝

Reload the exported result to check that the expected row count is retained.

scores = pd.read_table(StringIO(student_tsv), usecols=["id", "name", "mark"])
answer = scores.loc[scores["mark"].ge(90)]
answer_tsv = answer.to_csv(sep="\t", index=False)
print(answer_tsv.rstrip())
reloaded = pd.read_table(StringIO(answer_tsv))
assert len(reloaded) == int(scores["mark"].ge(90).sum())

Expected output

id	name	mark

12	Recky	94

32	Binn Rott	90

33	Kenn Rein	96

Practice in Google Colab 🔝

Open in Google Colab View on GitHub
Run the examples in order, change TSV values and import options, then inspect accepted records and review rows. Save your own copy to keep edits. All sample tables are included in the notebook.

Reference: Pandas read_table documentation.




Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
✖
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
© 2000-2026 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer