Pandas Introduction#

pandas is the standard Python library for working with tabular (structured) data. It provides fast, flexible data structures — primarily Series and DataFrame — that make data manipulation, cleaning, and analysis straightforward.

Tip

If you have ever worked with spreadsheets (Excel, Google Sheets), think of a DataFrame as a programmable spreadsheet.

import pandas as pd

Series vs DataFrame#

A Series is a one-dimensional labeled array — essentially a single column of data with an index.

A DataFrame is a two-dimensional labeled data structure — a table with rows and columns, where each column is a Series.

# A Series
temperatures = pd.Series([22.1, 23.4, 21.8, 24.0], name="Temperature")
temperatures
0    22.1
1    23.4
2    21.8
3    24.0
Name: Temperature, dtype: float64
type(temperatures)
pandas.Series

Creating DataFrames#

DataFrames can be created from Python dictionaries, lists of lists, or many other sources.

From a dictionary#

data = {
    "room": ["Living Room", "Bedroom", "Kitchen", "Office"],
    "temperature": [22.1, 20.5, 23.4, 21.8],
    "humidity": [45.0, 50.2, 38.7, 42.1]
}

df = pd.DataFrame(data)
df
room temperature humidity
0 Living Room 22.1 45.0
1 Bedroom 20.5 50.2
2 Kitchen 23.4 38.7
3 Office 21.8 42.1

From a list of lists#

rows = [
    ["Living Room", 22.1, 45.0],
    ["Bedroom", 20.5, 50.2],
    ["Kitchen", 23.4, 38.7],
    ["Office", 21.8, 42.1]
]

df2 = pd.DataFrame(rows, columns=["room", "temperature", "humidity"])
df2
room temperature humidity
0 Living Room 22.1 45.0
1 Bedroom 20.5 50.2
2 Kitchen 23.4 38.7
3 Office 21.8 42.1

Basic Indexing#

There are several ways to select data from a DataFrame.

Select a single column (returns a Series)#

df["temperature"]
0    22.1
1    20.5
2    23.4
3    21.8
Name: temperature, dtype: float64

Note

Selecting a single column with df["col"] returns a Series.

Select multiple columns (returns a DataFrame)#

df[["room", "temperature"]]
room temperature
0 Living Room 22.1
1 Bedroom 20.5
2 Kitchen 23.4
3 Office 21.8

Note

Selecting multiple columns with df[["col1", "col2"]] returns a DataFrame.

Label-based indexing with .loc[]#

.loc[] selects rows and columns by label (index value and column name).

# Select row with index label 0
df.loc[0]
room           Living Room
temperature           22.1
humidity              45.0
Name: 0, dtype: object
# Select rows 0 to 2, columns "room" and "temperature"
df.loc[0:2, ["room", "temperature"]]
room temperature
0 Living Room 22.1
1 Bedroom 20.5
2 Kitchen 23.4

Position-based indexing with .iloc[]#

.iloc[] selects rows and columns by integer position (like array indexing).

# Select the first two rows, first two columns
df.iloc[0:2, 0:2]
room temperature
0 Living Room 22.1
1 Bedroom 20.5
# Select a specific cell: row 1, column 2
df.iloc[1, 2]
np.float64(50.2)

Data Types and Info#

Understanding data types is important because certain operations only work with specific types.

df.dtypes
room               str
temperature    float64
humidity       float64
dtype: object
df.info()
<class 'pandas.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 3 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   room         4 non-null      str    
 1   temperature  4 non-null      float64
 2   humidity     4 non-null      float64
dtypes: float64(2), str(1)
memory usage: 228.0 bytes

Basic Properties#

# Number of rows and columns
df.shape
(4, 3)
# Column names
df.columns
Index(['room', 'temperature', 'humidity'], dtype='str')
# Index
df.index
RangeIndex(start=0, stop=4, step=1)

Loading a Real CSV File#

Let’s load a real data set to explore. The file flatTempHum.csv contains hourly temperature and humidity measurements from four flats.

Note

The CSV file uses ; as separator, which is common in European data files.

url = "https://raw.githubusercontent.com/retomarek/edap/main/edap/sampleData/flatTempHum.csv"

df = pd.read_csv(url, sep=";")
df.head()
time FlatA_Hum FlatA_Temp FlatB_Hum FlatB_Temp FlatC_Hum FlatC_Temp FlatD_Hum FlatD_Temp
0 2018-10-03 00:00:00 53.0 24.43 38.8 22.40 44.0 24.5 49.0 24.43
1 2018-10-03 01:00:00 53.0 24.40 38.8 22.40 44.0 24.5 49.0 24.40
2 2018-10-03 02:00:00 53.0 24.40 39.3 22.40 44.7 24.5 48.3 24.38
3 2018-10-03 03:00:00 53.0 24.40 40.3 22.40 45.0 24.5 48.0 24.33
4 2018-10-03 04:00:00 53.3 24.40 41.0 22.37 45.2 24.5 47.7 24.30
df.shape
(17181, 9)
df.dtypes
time              str
FlatA_Hum     float64
FlatA_Temp    float64
FlatB_Hum     float64
FlatB_Temp    float64
FlatC_Hum     float64
FlatC_Temp    float64
FlatD_Hum     float64
FlatD_Temp    float64
dtype: object

Note

The time column is text (dtype object in pandas 2, str in pandas 3). It should be converted to datetime for time-based operations — this is covered in the Datetime Handling chapter.

df.info()
<class 'pandas.DataFrame'>
RangeIndex: 17181 entries, 0 to 17180
Data columns (total 9 columns):
 #   Column      Non-Null Count  Dtype  
---  ------      --------------  -----  
 0   time        17181 non-null  str    
 1   FlatA_Hum   16484 non-null  float64
 2   FlatA_Temp  16484 non-null  float64
 3   FlatB_Hum   16470 non-null  float64
 4   FlatB_Temp  16470 non-null  float64
 5   FlatC_Hum   16497 non-null  float64
 6   FlatC_Temp  16497 non-null  float64
 7   FlatD_Hum   16354 non-null  float64
 8   FlatD_Temp  16354 non-null  float64
dtypes: float64(8), str(1)
memory usage: 1.2 MB
df.describe()
FlatA_Hum FlatA_Temp FlatB_Hum FlatB_Temp FlatC_Hum FlatC_Temp FlatD_Hum FlatD_Temp
count 16484.000000 16484.000000 16470.000000 16470.000000 16497.000000 16497.000000 16354.000000 16354.000000
mean 54.336599 23.786531 49.666697 23.404749 48.895339 23.964698 49.299156 24.134841
std 6.300389 1.273444 6.903822 1.470354 6.487768 1.360014 6.524641 1.308097
min 23.500000 19.100000 25.000000 20.530000 22.500000 21.380000 20.500000 18.120000
25% 51.000000 22.800000 44.700000 22.320000 44.300000 22.880000 44.300000 23.030000
50% 54.800000 23.480000 50.000000 23.000000 49.200000 23.600000 49.000000 23.700000
75% 58.300000 24.600000 54.500000 24.100000 53.800000 24.800000 54.000000 25.200000
max 76.500000 28.880000 73.300000 29.120000 69.800000 28.800000 69.800000 28.030000
df.columns
Index(['time', 'FlatA_Hum', 'FlatA_Temp', 'FlatB_Hum', 'FlatB_Temp',
       'FlatC_Hum', 'FlatC_Temp', 'FlatD_Hum', 'FlatD_Temp'],
      dtype='str')
# Select only temperature columns
temp_cols = [col for col in df.columns if "Temp" in col]
df[temp_cols].head()
FlatA_Temp FlatB_Temp FlatC_Temp FlatD_Temp
0 24.43 22.40 24.5 24.43
1 24.40 22.40 24.5 24.40
2 24.40 22.40 24.5 24.38
3 24.40 22.40 24.5 24.33
4 24.40 22.37 24.5 24.30
# Access specific rows and columns
df.loc[0:4, ["time", "FlatA_Temp", "FlatB_Temp"]]
time FlatA_Temp FlatB_Temp
0 2018-10-03 00:00:00 24.43 22.40
1 2018-10-03 01:00:00 24.40 22.40
2 2018-10-03 02:00:00 24.40 22.40
3 2018-10-03 03:00:00 24.40 22.40
4 2018-10-03 04:00:00 24.40 22.37