How do I check a table's rows, columns and data types in pandas?
Measure the table in three lines: how many rows and columns it has, what type each column is and what dates it covers.
Free course. Your Maestro, an AI, .
You know what a row is now. The second question measures the table: how many rows and columns it has, what type each column is and what period its dates cover. It takes three lines of code and saves you surprises later, after you've already calculated something with the wrong column.
Run the exercise. data.shape answers with two numbers: rows first, then columns. data.dtypes tells you what type of data pandas thinks each column holds.
Your turn
Run the cell and read the type of each column. Then replace data.dtypes with data.info(), which also counts how many non-empty values each column has. You're done when you can say which columns have fewer than 311 values.
Data: viajes-rueda, 311 rows
| Row | Remove | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | ||||||||||
| 2 | ||||||||||
| 3 | ||||||||||
| 4 | ||||||||||
| 5 | ||||||||||
| 6 | ||||||||||
| 7 | ||||||||||
| 8 | ||||||||||
| 9 | ||||||||||
| 10 | ||||||||||
| 11 | ||||||||||
| 12 | ||||||||||
| 13 | ||||||||||
| 14 | ||||||||||
| 15 | ||||||||||
| 16 | ||||||||||
| 17 | ||||||||||
| 18 | ||||||||||
| 19 | ||||||||||
| 20 |
Enter saves; Esc undoes; empty is a missing value
Tab indents; Esc then Tab leaves
The table has 311 rows and 9 columns. Here's how to read the types pandas reports:
| Type | What it holds | Rueda columns |
|---|---|---|
int64 | whole numbers | viaje_id |
float64 | numbers with decimals | duracion_min, distancia_km |
str | text | stations, tipo_usuario, bici_id |
datetime64[us] | date and time | inicio |
Int64 | whole numbers that allow gaps | anio_nacimiento |
That last one, with a capital I, is the pandas type for integers that can have holes. That type allows missing values; its presence doesn't prove that any are missing. data.info() confirms it in its Non-Null Count column: three columns have 303 values and anio_nacimiento only 238. The next module is all about that.
Numbers that measure and numbers that label
A numeric column isn't necessarily a quantity. Before moving on, decide.
Check yourself: All three columns are numeric. Which one doesn't make sense to average?
pandas will compute the average of viaje_id without complaint: 40,365. It means nothing. It's like averaging phone numbers. The computer doesn't know what each column represents; you do, or you have to ask someone who does.
When you check the types, sort the columns into two groups:
- They measure something:
duracion_min(minutes) anddistancia_km(kilometers). It makes sense to look at their minimum, their maximum, their median and how they're distributed. - They label something:
viaje_idandbici_id. What's useful is counting: how many distinct values there are, which ones repeat.
anio_nacimiento sits in between. It's a number that measures something, but what you usually care about is age, and an average birth year of 1983 says less than "half are between 30 and 54 years old." You'll look at it in module 3.
Sometimes the problem runs the other way: a label gets read as a number and breaks. A ZIP code like 03100 read as a number becomes 3100. That kind of problem when reading a file is the subject of another free Maestro course, on CSV files that open wrong; here it's enough to notice it and write it down.
If your table has a column and you can't tell whether it measures or labels, ask your Maestro.
What period does it cover?
If the table has dates, the next thing to know is the range: from when to when. A "monthly" report built from two weeks of data can't be compared with anything.
Your turn
Run the cell to see the first and the last date. Then add data["inicio"].dt.date.value_counts().sort_index() at the end to count the trips on each day. You're done when you know whether any day has no trips.
Data: viajes-rueda, 311 rows
| Row | Remove | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | ||||||||||
| 2 | ||||||||||
| 3 | ||||||||||
| 4 | ||||||||||
| 5 | ||||||||||
| 6 | ||||||||||
| 7 | ||||||||||
| 8 | ||||||||||
| 9 | ||||||||||
| 10 | ||||||||||
| 11 | ||||||||||
| 12 | ||||||||||
| 13 | ||||||||||
| 14 | ||||||||||
| 15 | ||||||||||
| 16 | ||||||||||
| 17 | ||||||||||
| 18 | ||||||||||
| 19 | ||||||||||
| 20 |
Enter saves; Esc undoes; empty is a missing value
Tab indents; Esc then Tab leaves
The table runs from Monday, March 2, 2026 at 8:11 a.m. to Sunday, March 15 at 11:51 p.m.: records occur on every date from March 2 to 15 (between 14 and 32 a day). This does not prove that all trips are present or that the extract covers whole days. A day with no rows could mean no activity, an extraction limit, or a recording problem: ask what coverage was expected.
There's one more detail. The last trip starts at 11:51 p.m. on the last day, almost at midnight. If the table was exported right around then, that night's trips may not have finished yet. It's a suspicion, not a fact, and that's what the log is for:
Observation: there are records from March 2 to 15; the last trip starts at 11:51 p.m. on the 15th. Evidence:
min()andmax()ofinicio. Question: what time was it exported? Had that night's trips already finished?
In the next module you'll see that the suspicion was well founded.
If you're not sure what to write in your log, ask your Maestro to review your entry.
Tip: All in one line
data.info() gives you the number of rows, the type of each column and how many non-empty values it has, all at once. It's a good first line for any new table.
Try it
A question about another table, to see whether the idea sticks.
Check yourself: In a pharmacy's customer table, the column codigo_postal shows up as int64 and the ZIP code 03100 looks like 3100. What do you write in your log?