Python Pandas 基础教程 – wiki基地


Python Pandas 基础教程:数据分析的得力助手

数据是现代世界的基石,而如何高效地处理、清洗、分析和转换数据,是数据科学、机器学习乃至日常工作中不可或缺的技能。在 Python 的数据生态系统中,Pandas 库无疑是处理结构化数据的首选工具。它提供了一系列高性能、易用的数据结构和数据分析工具,极大地简化了数据处理的流程。

本篇文章将带你深入了解 Pandas 的基础知识,包括其核心数据结构、数据创建、数据选择、数据清洗、数据加载与保存等常用操作。我们将通过丰富的代码示例,让你亲手实践,逐步掌握这个强大的工具。

1. 什么是 Pandas?为什么选择 Pandas?

Pandas 是一个开源的 Python 库,专注于提供快速、灵活且富有表现力的数据结构,旨在使处理“关系型”或“带标签”的数据变得简单直观。它是基于 NumPy 构建的,但提供了比 NumPy 更高级的数据处理功能,尤其擅长处理表格化数据(类似于电子表格或数据库中的表格)。

为什么选择 Pandas?

  • 强大的数据结构: 提供了 SeriesDataFrame 这两种核心数据结构,能够优雅地处理各种类型的数据。
  • 便捷的数据操作: 支持灵活的索引、切片、合并、重塑、分组、聚合等操作。
  • 处理缺失数据: 提供了完善的缺失数据处理机制。
  • 文件 I/O 支持: 可以轻松读取和写入多种数据格式,如 CSV、Excel、SQL 数据库、JSON 等。
  • 集成性好: 与 NumPy、Matplotlib、Scikit-learn 等其他 Python 科学计算库紧密集成。
  • 高性能: 底层由高度优化的 C 代码实现,处理大规模数据时效率较高。

可以说,Pandas 是进行数据清洗(Data Cleaning)、数据转换(Data Transformation)、数据探索(Data Exploration)和数据预处理(Data Preprocessing)的瑞士军刀。

2. 安装 Pandas

在开始之前,你需要确保已经安装了 Python 和 pip 包管理器。安装 Pandas 非常简单,只需在终端或命令提示符中运行以下命令:

bash
pip install pandas openpyxl # openpyxl 用于读写 Excel 文件

如果你使用的是 Anaconda Python 发行版,Pandas 通常已经预装好了,你可以直接使用。如果未安装,可以使用 conda 进行安装:

bash
conda install pandas openpyxl

安装完成后,你可以在 Python 脚本或交互式环境中导入 Pandas:

python
import pandas as pd

我们通常使用 pd 作为 Pandas 的别名,这是一个约定俗成的做法。

3. Pandas 的核心数据结构:Series 和 DataFrame

Pandas 主要提供了两种核心数据结构:SeriesDataFrame。理解它们是掌握 Pandas 的关键。

3.1 Series (序列)

Series 是一种一维的带标签数组(labeled array)。它可以存储任何数据类型(整数、浮点数、字符串、Python 对象等),并且每个元素都有一个与之关联的标签,称为索引(index)。如果没有显式指定索引,Pandas 会自动创建一个从 0 开始的默认整数索引。

特点:

  • 一维结构。
  • 带标签的轴(索引)。
  • 可以存储同构或异构数据(但在实践中通常存储同构数据)。

创建 Series:

可以通过多种方式创建 Series:

  1. 从 Python 列表或 NumPy 数组创建:

    “`python
    import pandas as pd
    import numpy as np

    从列表创建,使用默认整数索引

    s1 = pd.Series([10, 20, 30, 40, 50])
    print(“Series s1:”)
    print(s1)

    输出:

    0 10

    1 20

    2 30

    3 40

    4 50

    dtype: int64

    从 NumPy 数组创建,并指定索引

    data = np.array([‘a’, ‘b’, ‘c’, ‘d’])
    index_labels = [‘label1’, ‘label2’, ‘label3’, ‘label4’]
    s2 = pd.Series(data, index=index_labels)
    print(“\nSeries s2:”)
    print(s2)

    输出:

    label1 a

    label2 b

    label3 c

    label4 d

    dtype: object

    从 NumPy 数组创建,使用默认索引

    s3 = pd.Series(np.linspace(0, 1, 5)) # 0到1之间等间隔的5个值
    print(“\nSeries s3:”)
    print(s3)
    “`

  2. 从 Python 字典创建:

    字典的键将成为 Series 的索引,值将成为 Series 的数据。

    “`python
    data_dict = {‘apple’: 1.5, ‘banana’: 2.0, ‘cherry’: 3.0}
    s4 = pd.Series(data_dict)
    print(“\nSeries s4 (from dict):”)
    print(s4)

    输出:

    apple 1.5

    banana 2.0

    cherry 3.0

    dtype: float64

    从字典创建,但指定索引的顺序(未指定的键将得到 NaN 值)

    s5 = pd.Series(data_dict, index=[‘banana’, ‘apple’, ‘grape’])
    print(“\nSeries s5 (from dict with specified index order):”)
    print(s5)

    输出:

    banana 2.0

    apple 1.5

    grape NaN

    dtype: float64

    ``
    注意这里的
    NaN`(Not a Number),它代表缺失值,是 Pandas 中常用的缺失数据标记。

Series 的属性:

一些常用的 Series 属性:

  • s.values: 返回 Series 的数据(NumPy 数组)。
  • s.index: 返回 Series 的索引对象。
  • s.dtype: 返回 Series 中元素的 数据类型。
  • s.size: 返回 Series 中元素的数量。
  • s.name: Series 的名称(可选)。
  • s.index.name: Series 索引的名称(可选)。

“`python
print(“\ns4 attributes:”)
print(“Values:”, s4.values)
print(“Index:”, s4.index)
print(“Dtype:”, s4.dtype)
print(“Size:”, s4.size)

s4.name = “水果价格”
s4.index.name = “水果名称”
print(“\nSeries s4 after setting names:”)
print(s4)
print(“Name:”, s4.name)
print(“Index Name:”, s4.index.name)
“`

Series 的基本操作(索引与切片):

Series 的索引和切片操作与 NumPy 数组和 Python 列表类似,但可以使用标签或整数位置进行访问。

“`python

访问单个元素 (通过标签或位置)

print(“\nAccessing Series elements:”)
print(“s4[‘apple’]:”, s4[‘apple’]) # 通过标签
print(“s4[0]:”, s4[0]) # 通过整数位置

切片 (通过标签或位置)

print(“\nSlicing Series:”)
print(“s4[‘banana’:’cherry’] (inclusive label slice):”)
print(s4[‘banana’:’cherry’]) # 通过标签切片,右侧标签包含在内

print(“\ns1[1:3] (exclusive integer slice):”)
print(s1[1:3]) # 通过整数位置切片,右侧索引不包含在内

使用列表进行多元素选择

print(“\nSelecting multiple elements with a list:”)
print(“s4[[‘apple’, ‘cherry’]]:”)
print(s4[[‘apple’, ‘cherry’]])

使用布尔数组选择

print(“\nBoolean indexing:”)
print(“s1 > 25:”)
print(s1[s1 > 25]) # 选择值大于25的元素
“`

3.2 DataFrame (数据框)

DataFrame 是 Pandas 中最重要也是最常用的数据结构。它是一个二维的带标签数据结构,可以被看作是 Series 的容器,共享同一个索引。可以理解为一个表格,有行和列,每一列可以是不同的数据类型(但同一列的数据类型通常是相同的)。

特点:

  • 二维结构。
  • 有行索引(Index)和列索引(Columns)。
  • 每列可以存储不同的数据类型。
  • 类似于电子表格或 SQL 表。

创建 DataFrame:

DataFrame 的创建方式非常灵活:

  1. 从 Python 字典创建 (最常见):

    字典的键作为列名,值作为列的数据(通常是列表、NumPy 数组或 Series)。

    “`python
    data = {
    ‘城市’: [‘北京’, ‘上海’, ‘广州’, ‘深圳’, ‘成都’],
    ‘人口’: [2154, 2428, 1530, 1303, 1633], # 单位: 万
    ‘面积’: [16411, 6340, 7434, 1973, 14312], # 单位: 平方公里
    ‘GDP’: [30320, 32680, 22859, 24221, 15342] # 单位: 亿人民币
    }
    df = pd.DataFrame(data)
    print(“\nDataFrame df (from dict):”)
    print(df)

    输出类似表格的数据:

    城市 人口 面积 GDP

    0 北京 2154 16411 30320

    1 上海 2428 6340 32680

    2 广州 1530 7434 22859

    3 深圳 1303 1973 24221

    4 成都 1633 14312 15342

    “`

  2. 从字典列表创建:

    列表中的每个字典代表一行数据。

    python
    data_list = [
    {'Name': 'Alice', 'Age': 25, 'City': 'New York'},
    {'Name': 'Bob', 'Age': 30, 'City': 'London'},
    {'Name': 'Charlie', 'Age': 35, 'City': 'Paris'}
    ]
    df_list = pd.DataFrame(data_list)
    print("\nDataFrame df_list (from list of dicts):")
    print(df_list)

  3. 从 NumPy 二维数组创建:

    需要指定列名和索引。

    python
    np_data = np.random.rand(4, 3) # 4行3列的随机数据
    df_np = pd.DataFrame(np_data, columns=['col1', 'col2', 'col3'], index=['row1', 'row2', 'row3', 'row4'])
    print("\nDataFrame df_np (from NumPy array):")
    print(df_np)

DataFrame 的属性:

一些常用的 DataFrame 属性:

  • df.index: 返回 DataFrame 的行索引。
  • df.columns: 返回 DataFrame 的列索引 (列名)。
  • df.values: 返回 DataFrame 的数据(NumPy 二维数组)。
  • df.shape: 返回 DataFrame 的形状 (行数, 列数) 元组。
  • df.dtypes: 返回每列的数据类型。
  • df.info(): 打印 DataFrame 的简要信息,包括索引、列、非空值数量和内存使用情况。
  • df.describe(): 生成描述性统计信息,包括计数、均值、标准差、最小值、最大值和四分位数(仅限数值列)。
  • df.head(n=5): 显示前 n 行数据 (默认为 5)。
  • df.tail(n=5): 显示后 n 行数据 (默认为 5)。

“`python
print(“\ndf attributes:”)
print(“Index:”, df.index)
print(“Columns:”, df.columns)
print(“Values:\n”, df.values)
print(“Shape:”, df.shape)
print(“Dtypes:”, df.dtypes)

print(“\ndf.info():”)
df.info()

print(“\ndf.describe():”)
print(df.describe())

print(“\ndf.head(3):”)
print(df.head(3))
“`

4. 数据选择与索引 (DataFrame)

从 DataFrame 中选择数据是日常操作中最频繁的部分。Pandas 提供了多种强大的方式来选择行、列或单个元素。

4.1 选择列

选择一列会返回一个 Series,选择多列会返回一个 DataFrame。

“`python

选择单列 (返回 Series)

cities = df[‘城市’]
print(“\nSelecting single column ‘城市’:”)
print(cities)
print(type(cities)) #

选择多列 (返回 DataFrame)

city_pop_area = df[[‘城市’, ‘人口’, ‘面积’]]
print(“\nSelecting multiple columns [‘城市’, ‘人口’, ‘面积’]:”)
print(city_pop_area)
print(type(city_pop_area)) #
``
注意,选择单列使用
df[‘列名’]语法,选择多列使用df[[‘列名1’, ‘列名2’, …]]` 语法,即列名列表作为索引。

4.2 选择行 (loc vs iloc)

这是 Pandas 索引中最容易混淆但也最重要的部分。理解 lociloc 的区别至关重要。

  • loc: 基于标签(label-based) 的索引。使用行索引的标签和列索引的标签来选择数据。
  • iloc: 基于整数位置(integer-based) 的索引。使用行和列的整数位置(从 0 开始)来选择数据。

使用 loc (基于标签):

“`python

设置 ‘城市’ 列为索引以便演示标签索引

df_indexed = df.set_index(‘城市’)
print(“\nDataFrame with ‘城市’ as index:”)
print(df_indexed)

选择单行 (通过行标签)

beijing_data = df_indexed.loc[‘北京’]
print(“\nSelecting row with label ‘北京’ using loc:”)
print(beijing_data) # 返回 Series

选择多行 (通过行标签列表)

beijing_shanghai = df_indexed.loc[[‘北京’, ‘上海’]]
print(“\nSelecting rows with labels [‘北京’, ‘上海’] using loc:”)
print(beijing_shanghai) # 返回 DataFrame

选择行标签范围 (包含右边界)

guangzhou_shenzhen = df_indexed.loc[‘广州’:’深圳’]
print(“\nSelecting rows from ‘广州’ to ‘深圳’ using loc (inclusive slice):”)
print(guangzhou_shenzhen) # 返回 DataFrame

选择特定行和特定列 (通过标签)

beijing_pop_gdp = df_indexed.loc[‘北京’, [‘人口’, ‘GDP’]]
print(“\nSelecting row ‘北京’ and columns [‘人口’, ‘GDP’] using loc:”)
print(beijing_pop_gdp) # 返回 Series

选择行标签范围和列标签范围 (包含右边界)

partial_data = df_indexed.loc[‘上海’:’深圳’, ‘人口’:’GDP’]
print(“\nSelecting rows ‘上海’ to ‘深圳’ and columns ‘人口’ to ‘GDP’ using loc:”)
print(partial_data) # 返回 DataFrame

选择所有行和特定列

all_rows_pop_area = df_indexed.loc[:, [‘人口’, ‘面积’]]
print(“\nSelecting all rows and columns [‘人口’, ‘面积’] using loc:”)
print(all_rows_pop_area) # 返回 DataFrame
“`

使用 iloc (基于整数位置):

iloc 的语法类似于 NumPy 数组的切片,右侧边界是不包含的。

“`python
print(“\nUsing iloc (integer-based indexing) on original df:”)
print(df) # 使用原始的 df,其行索引是默认的整数 0, 1, 2…

选择单行 (通过行整数位置)

first_row = df.iloc[0]
print(“\nSelecting row at integer position 0 using iloc:”)
print(first_row) # 返回 Series (北京的数据)

选择多行 (通过行整数位置列表)

first_two_rows = df.iloc[[0, 1]]
print(“\nSelecting rows at integer positions [0, 1] using iloc:”)
print(first_two_rows) # 返回 DataFrame (北京、上海的数据)

选择行整数位置范围 (不包含右边界)

middle_rows = df.iloc[1:4]
print(“\nSelecting rows from integer position 1 to 3 using iloc (exclusive slice):”)
print(middle_rows) # 返回 DataFrame (上海、广州、深圳的数据)

选择特定行和特定列 (通过整数位置)

guangzhou_pop_area_iloc = df.iloc[2, [1, 2]]
print(“\nSelecting row at integer position 2 and columns at integer positions [1, 2] using iloc:”)
print(guangzhou_pop_area_iloc) # 返回 Series (广州的人口和面积)

选择行整数位置范围和列整数位置范围 (不包含右边界)

partial_data_iloc = df.iloc[1:4, 1:3]
print(“\nSelecting rows from 1 to 3 and columns from 1 to 2 using iloc:”)
print(partial_data_iloc) # 返回 DataFrame (上海、广州、深圳的人口和面积)

选择所有行和特定列

all_rows_pop_area_iloc = df.iloc[:, [1, 2]]
print(“\nSelecting all rows and columns at integer positions [1, 2] using iloc:”)
print(all_rows_pop_area_iloc) # 返回 DataFrame (所有城市的人口和面积)
“`

总结 lociloc

语法 索引类型 行切片行为 列切片行为 主要用途
df.loc[] 标签 包含右边界 包含右边界 使用明确的行/列标签选择数据
df.iloc[] 整数位置 不包含右边界 (同列表) 不包含右边界 (同列表) 使用整数位置选择数据

4.3 布尔索引 (Filtering)

布尔索引是一种非常强大的数据选择方式,可以根据条件过滤 DataFrame 中的行。

“`python

选择人口大于 2000 万的城市

pop_greater_than_2000 = df[df[‘人口’] > 2000]
print(“\nCities with population > 2000:”)
print(pop_greater_than_2000)

组合条件 (使用 & 表示 AND, | 表示 OR, ~ 表示 NOT)

选择人口大于 1500 万 且 GDP 大于 25000 亿的城市

high_pop_gdp = df[(df[‘人口’] > 1500) & (df[‘GDP’] > 25000)]
print(“\nCities with pop > 1500 AND GDP > 25000:”)
print(high_pop_gdp)

选择面积小于 5000 平方公里 或 GDP 小于 20000 亿的城市

small_area_low_gdp = df[(df[‘面积’] < 5000) | (df[‘GDP’] < 20000)]
print(“\nCities with area < 5000 OR GDP < 20000:”)
print(small_area_low_gdp)

使用 isin() 方法选择在特定列表中的值

cities_to_select = [‘北京’, ‘深圳’]
selected_cities_isin = df[df[‘城市’].isin(cities_to_select)]
print(“\nCities in [‘北京’, ‘深圳’] using isin():”)
print(selected_cities_isin)
“`
布尔索引返回的 DataFrame 包含满足条件的原始行的所有列。

5. 数据修改与添加

修改 DataFrame 中的数据或添加新列也很容易。

5.1 修改元素或块

可以使用 lociloc 来修改特定的元素、行或列。

“`python
print(“\nOriginal df:”)
print(df)

修改单个元素 (例如,将北京的人口修改为 2200 万)

需要使用 df.loc[] 来确保修改的是原始 DataFrame

df.loc[df[‘城市’] == ‘北京’, ‘人口’] = 2200
print(“\nModified df (北京人口 updated):”)
print(df)

修改整列 (例如,将所有城市的 GDP 乘以 10000 转换为元)

df[‘GDP_元’] = df[‘GDP’] * 10000 # 也可以直接添加新列

修改一个范围的值 (例如,将索引 1 到 3 的城市的面积修改为 0)

注意 iloc 的右边界是不包含的

df.iloc[1:4, 2] = 0
print(“\nModified df (iloc slicing for area):”)
print(df)

将 DataFrame 恢复到接近原始状态以便后续演示

df = pd.DataFrame(data)
“`

5.2 添加新列

添加新列非常简单,只需像访问字典一样给一个不存在的列名赋值即可。

“`python

添加一个新列 ‘密度’ (人口/面积)

df[‘密度’] = df[‘人口’] / df[‘面积’]
print(“\nDataFrame after adding ‘密度’ column:”)
print(df)

添加一个基于现有列的条件列

df[‘规模’] = np.where(df[‘人口’] > 2000, ‘大型城市’, ‘中小型城市’)
print(“\nDataFrame after adding ‘规模’ column (using np.where):”)
print(df)

添加一个常量列

df[‘国家’] = ‘中国’
print(“\nDataFrame after adding ‘国家’ column (constant value):”)
print(df)
``
NumPy 的
np.where(condition, value_if_true, value_if_false)` 函数在创建条件列时非常有用。

5.3 删除列或行

使用 drop() 方法可以删除指定的列或行。需要注意的是,drop() 默认返回一个新的 DataFrame,原始 DataFrame 不会被修改。如果要修改原始 DataFrame,需要设置 inplace=True 参数。

“`python

删除列 (例如,删除 ‘国家’ 列)

axis=1 表示操作沿着列进行

df_dropped_country = df.drop(‘国家’, axis=1)
print(“\nDataFrame after dropping ‘国家’ column (new DataFrame):”)
print(df_dropped_country)
print(“\nOriginal df remains unchanged:”)
print(df)

如果想直接修改原始 DataFrame,使用 inplace=True

df.drop(‘国家’, axis=1, inplace=True)
print(“\nOriginal df after inplace drop of ‘国家’:”)
print(df)

删除多列

df.drop([‘密度’, ‘规模’], axis=1, inplace=True)
print(“\nOriginal df after inplace drop of multiple columns:”)
print(df)

删除行 (例如,删除索引为 0 和 2 的行,即北京和广州)

axis=0 表示操作沿着行进行 (这是默认值,可以省略)

df_dropped_rows = df.drop([0, 2], axis=0)

或者 df_dropped_rows = df.drop([0, 2])

print(“\nDataFrame after dropping rows 0 and 2 (new DataFrame):”)
print(df_dropped_rows)

如果行索引是标签,也可以使用标签删除

df_indexed = df.set_index(‘城市’)
df_dropped_labels = df_indexed.drop([‘上海’, ‘深圳’])
print(“\nDataFrame with city index after dropping rows ‘上海’ and ‘深圳’:”)
print(df_dropped_labels)
“`

6. 处理缺失数据 (Missing Data)

现实世界的数据很少是完美的,经常包含缺失值。Pandas 使用 NaN (Not a Number) 来表示数值类型的缺失值,对于对象类型(如字符串),有时也使用 NoneNaN

6.1 检测缺失值

  • isnull(): 返回一个布尔型 DataFrame,其中缺失值为 True
  • notnull(): 返回一个布尔型 DataFrame,其中非缺失值为 True

“`python

创建一个包含缺失值的 DataFrame

data_with_nan = {
‘A’: [1, 2, np.nan, 4],
‘B’: [5, np.nan, np.nan, 8],
‘C’: [9, 10, 11, 12],
‘D’: [np.nan, 14, 15, 16]
}
df_nan = pd.DataFrame(data_with_nan)
print(“\nDataFrame with NaN values:”)
print(df_nan)

print(“\ndf_nan.isnull():”)
print(df_nan.isnull())

print(“\ndf_nan.notnull():”)
print(df_nan.notnull())

检查每列的缺失值数量

print(“\nNumber of missing values per column:”)
print(df_nan.isnull().sum())

检查总共的缺失值数量

print(“\nTotal number of missing values:”)
print(df_nan.isnull().sum().sum())
“`

6.2 删除缺失值

dropna() 方法可以删除包含缺失值的行或列。

“`python

删除包含任何缺失值的行 (默认 axis=0, how=’any’)

df_dropped_rows_nan = df_nan.dropna()
print(“\nDataFrame after dropping rows with any NaN:”)
print(df_dropped_rows_nan)

删除所有值都是缺失值的行

df_dropped_all_nan_rows = df_nan.dropna(how=’all’)
print(“\nDataFrame after dropping rows with all NaN:”)
print(df_dropped_all_nan_rows) # 在当前例子中,结果和 df_nan 相同,因为没有全 NaN 的行

删除包含任何缺失值的列 (axis=1)

df_dropped_cols_nan = df_nan.dropna(axis=1)
print(“\nDataFrame after dropping columns with any NaN:”)
print(df_dropped_cols_nan) # C 列被保留

删除所有值都是缺失值的列

df_dropped_all_nan_cols = df_nan.dropna(axis=1, how=’all’)
print(“\nDataFrame after dropping columns with all NaN:”)
print(df_dropped_all_nan_cols) # 在当前例子中,结果和 df_nan 相同,因为没有全 NaN 的列

使用 thresh 参数指定至少需要有多少非缺失值才保留

保留至少有 3 个非缺失值的行

df_thresh = df_nan.dropna(thresh=3)
print(“\nDataFrame after dropping rows with less than 3 non-NaN values:”)
print(df_thresh) # 第1行(索引0)和第4行(索引3)被保留
“`

6.3 填充缺失值

fillna() 方法可以用指定的值或方法填充缺失值。

“`python

用常量值填充所有 NaN

df_filled_zero = df_nan.fillna(0)
print(“\nDataFrame after filling NaN with 0:”)
print(df_filled_zero)

用列的均值填充 NaN

mean_A = df_nan[‘A’].mean()
df_filled_mean = df_nan.fillna({‘A’: mean_A, ‘B’: df_nan[‘B’].mean()}) # 可以为不同列指定不同值
print(“\nDataFrame after filling NaN with column mean:”)
print(df_filled_mean)

向前填充 (用前一个有效值填充 NaN)

df_filled_ffill = df_nan.fillna(method=’ffill’)
print(“\nDataFrame after forward filling NaN:”)
print(df_filled_ffill)

向后填充 (用后一个有效值填充 NaN)

df_filled_bfill = df_nan.fillna(method=’bfill’)
print(“\nDataFrame after backward filling NaN:”)
print(df_filled_bfill)

使用 inplace=True 直接修改原始 DataFrame

df_nan.fillna(value=df_nan.mean(), inplace=True) # 用每列的均值填充
print(“\nOriginal df_nan after inplace filling with mean:”)
print(df_nan)
“`

7. 数据加载与保存

Pandas 提供了方便的函数来从各种文件格式读取数据,以及将 DataFrame 写入文件。

7.1 读取数据

常用的读取函数包括:

  • pd.read_csv(): 读取 CSV 文件。
  • pd.read_excel(): 读取 Excel 文件。
  • pd.read_sql(): 从数据库读取数据。
  • pd.read_json(): 读取 JSON 文件。

读取 CSV 文件:

假设你有一个名为 data.csv 的文件,内容如下:

csv
Name,Age,City
Alice,25,New York
Bob,30,London
Charlie,35,Paris
David,,Tokyo

注意 David 的年龄是缺失的。

“`python

创建一个模拟的 data.csv 文件

csv_content = “””Name,Age,City
Alice,25,New York
Bob,30,London
Charlie,35,Paris
David,,Tokyo
“””
with open(‘data.csv’, ‘w’) as f:
f.write(csv_content)

读取 CSV 文件

try:
df_csv = pd.read_csv(‘data.csv’)
print(“\nDataFrame read from data.csv:”)
print(df_csv)
print(“\ndf_csv info:”)
df_csv.info() # Notice Age column might be float due to NaN
except FileNotFoundError:
print(“Error: data.csv not found.”)

常用的 read_csv 参数:

sep: 分隔符 (默认为 ‘,’)

header: 指定哪一行作为列头 (默认为 0, 即第一行)

index_col: 指定哪一列作为行索引

names: 指定列名 (如果文件没有列头)

skiprows: 跳过文件开头的行

na_values: 指定哪些值应该被视为 NaN

``
在上面的例子中,因为 David 的年龄是空的,
read_csv会将其识别为缺失值,并且由于缺失值的存在,'Age' 列的数据类型会被推断为浮点型 (float64`)。

读取 Excel 文件:

假设你有一个名为 data.xlsx 的文件,包含一个名为 Sheet1 的工作表。

“`python

创建一个模拟的 data.xlsx 文件

try:
df_to_excel = pd.DataFrame({
‘Product’: [‘A’, ‘B’, ‘C’],
‘Price’: [10, 20, 30],
‘Stock’: [100, 50, np.nan] # 含缺失值
})
df_to_excel.to_excel(‘data.xlsx’, sheet_name=’Sheet1′, index=False) # index=False 表示不写入行索引
print(“\nCreated dummy data.xlsx”)

# 读取 Excel 文件
df_excel = pd.read_excel('data.xlsx', sheet_name='Sheet1')
print("\nDataFrame read from data.xlsx:")
print(df_excel)
print("\ndf_excel info:")
df_excel.info() # Notice Stock column might be float due to NaN

except FileNotFoundError:
print(“Error: data.xlsx not found.”)
except ImportError:
print(“Please install openpyxl to read/write Excel files: pip install openpyxl”)

常用的 read_excel 参数:

sheet_name: 指定要读取的工作表名称或索引 (默认为第一个工作表)

header: 指定哪一行作为列头

index_col: 指定哪一列作为行索引

usecols: 指定要读取的列

na_values: 指定哪些值应该被视为 NaN

“`

7.2 保存数据

常用的保存函数包括:

  • df.to_csv(): 将 DataFrame 写入 CSV 文件。
  • df.to_excel(): 将 DataFrame 写入 Excel 文件。
  • df.to_sql(): 将 DataFrame 写入数据库。
  • df.to_json(): 将 DataFrame 写入 JSON 文件。

保存到 CSV 文件:

“`python

将 DataFrame 保存到 CSV 文件

df.to_csv(‘output.csv’, index=False) # index=False 表示不将行索引写入文件
print(“\nDataFrame saved to output.csv (without index).”)

将 DataFrame 保存到 CSV 文件,包含索引

df.to_csv(‘output_with_index.csv’, index=True)
print(“DataFrame saved to output_with_index.csv (with index).”)

常用的 to_csv 参数:

path_or_buf: 文件路径或缓冲区

sep: 分隔符 (默认为 ‘,’)

header: 是否写入列头 (默认为 True)

index: 是否写入行索引 (默认为 True)

na_rep: 用什么字符串表示缺失值 (默认为空字符串)

“`

保存到 Excel 文件:

“`python
try:
# 将 DataFrame 保存到 Excel 文件
df.to_excel(‘output.xlsx’, sheet_name=’CityData’, index=False)
print(“\nDataFrame saved to output.xlsx (without index).”)

# 将 DataFrame 保存到 Excel 文件,包含索引
df.to_excel('output_with_index.xlsx', sheet_name='CityData', index=True)
print("DataFrame saved to output_with_index.xlsx (with index).")

# 保存多个 DataFrame 到同一个 Excel 文件的不同工作表
with pd.ExcelWriter('multi_sheet_output.xlsx') as writer:
    df.to_excel(writer, sheet_name='CityData', index=False)
    df_nan.to_excel(writer, sheet_name='NanData', index=False)
print("Multiple DataFrames saved to multi_sheet_output.xlsx.")

except ImportError:
print(“Please install openpyxl to read/write Excel files: pip install openpyxl”)

常用的 to_excel 参数:

excel_writer: ExcelWriter 对象或文件路径

sheet_name: 工作表名称 (默认为 ‘Sheet1’)

header: 是否写入列头 (默认为 True)

index: 是否写入行索引 (默认为 True)

na_rep: 用什么字符串表示缺失值 (默认为空字符串)

“`

8. 基本统计与分组聚合

Pandas 提供了丰富的统计函数和强大的分组(groupby)功能,用于数据汇总和分析。

8.1 基本统计函数

DataFrame 和 Series 都有很多内置的统计方法,例如:

  • count(): 非空值的数量。
  • mean(): 均值。
  • median(): 中位数。
  • sum(): 总和。
  • std(): 标准差。
  • min(): 最小值。
  • max(): 最大值。
  • value_counts(): 计算 Series 中唯一值的数量(常用于分类数据)。
  • unique(): 获取 Series 中的唯一值数组。

“`python
print(“\nBasic Statistics on df:”)
print(df) # 原始 df 只有 城市, 人口, 面积, GDP 列

print(“\nPopulation mean:”, df[‘人口’].mean())
print(“GDP sum:”, df[‘GDP’].sum())
print(“Area standard deviation:”, df[‘面积’].std())
print(“Min GDP:”, df[‘GDP’].min())
print(“Max GDP:”, df[‘GDP’].max())

添加 ‘规模’ 列以便演示 value_counts

df[‘规模’] = np.where(df[‘人口’] > 2000, ‘大型城市’, ‘中小型城市’)
print(“\nValue counts for ‘规模’ column:”)
print(df[‘规模’].value_counts())

print(“\nUnique values in ‘规模’ column:”)
print(df[‘规模’].unique())
“`

8.2 分组聚合 (groupby)

groupby() 方法是 Pandas 中进行“分而治之”操作的关键。它将 DataFrame 按照某个(或多个)列的值分成不同的组,然后可以对每个组独立地应用一个聚合函数(如求和、求均值、计数等)。

典型的 groupby 操作流程是:

  1. Split (拆分): 根据某个键(列)将数据拆分成组。
  2. Apply (应用): 对每个组独立地应用一个函数(通常是聚合函数、转换函数或过滤函数)。
  3. Combine (合并): 将各个组的结果合并成一个新的 DataFrame 或 Series。

“`python

创建一个包含分类数据的 DataFrame

data_sales = {
‘Category’: [‘水果’, ‘水果’, ‘蔬菜’, ‘蔬菜’, ‘水果’, ‘蔬菜’],
‘Item’: [‘苹果’, ‘香蕉’, ‘胡萝卜’, ‘菠菜’, ‘橙子’, ‘土豆’],
‘Price’: [5, 3, 2, 4, 6, 3],
‘Quantity’: [10, 15, 20, 10, 12, 18]
}
df_sales = pd.DataFrame(data_sales)
print(“\nSales DataFrame:”)
print(df_sales)

按 ‘Category’ 分组,计算每种类别的总销售额 (Price * Quantity)

df_sales[‘Sales’] = df_sales[‘Price’] * df_sales[‘Quantity’]
print(“\nSales DataFrame with Sales column:”)
print(df_sales)

按类别分组,计算每个类别的总销售额

sales_by_category = df_sales.groupby(‘Category’)[‘Sales’].sum()
print(“\nTotal Sales by Category:”)
print(sales_by_category) # 返回 Series

按类别分组,计算每个类别的总数量和平均价格

summary_by_category = df_sales.groupby(‘Category’).agg({
‘Quantity’: ‘sum’,
‘Price’: ‘mean’
})
print(“\nSummary (Total Quantity, Average Price) by Category:”)
print(summary_by_category) # 返回 DataFrame

按多个列分组

data_multi = {
‘Year’: [2020, 2020, 2021, 2021, 2020, 2021],
‘Region’: [‘North’, ‘South’, ‘North’, ‘South’, ‘North’, ‘South’],
‘Sales’: [100, 150, 120, 180, 110, 170]
}
df_multi = pd.DataFrame(data_multi)
print(“\nMulti-level Grouping DataFrame:”)
print(df_multi)

按 Year 和 Region 分组,计算总销售额

sales_by_year_region = df_multi.groupby([‘Year’, ‘Region’])[‘Sales’].sum()
print(“\nTotal Sales by Year and Region:”)
print(sales_by_year_region) # 返回 MultiIndex Series

如果想让分组的键作为列,可以使用 as_index=False

sales_by_year_region_df = df_multi.groupby([‘Year’, ‘Region’], as_index=False)[‘Sales’].sum()
print(“\nTotal Sales by Year and Region (as DataFrame):”)
print(sales_by_year_region_df)
``groupby()` 是 Pandas 中进行数据分析和报表生成的强大工具,值得深入学习。

9. 综合示例:简单的数据分析流程

让我们把上面学到的一些基础知识串联起来,完成一个简单的数据分析流程:加载数据 -> 数据清洗 -> 数据探索 -> 基本分析。

假设我们有一个 CSV 文件 sales_data.csv

csv
OrderID,Product,Category,Price,Quantity,OrderDate,CustomerSegment,Discount,Region,DeliveryDate
1001,Laptop,Electronics,1200,1,2023-01-05,Corporate,0.1,North,2023-01-10
1002,Mouse,Electronics,25,2,2023-01-05,Consumer,0,South,2023-01-08
1003,Keyboard,Electronics,75,1,2023-01-06,Corporate,0.1,North,2023-01-11
1004,Desk,Furniture,300,1,2023-01-06,Home Office,0.15,South,2023-01-15
1005,Chair,Furniture,150,2,2023-01-07,Consumer,0,North,2023-01-12
1006,Monitor,Electronics,250,1,2023-01-07,Home Office,0.1,South,2023-01-12
1007,Bookcase,Furniture,450,1,2023-01-08,Corporate,0.15,North,2023-01-18
1008,Headphones,Electronics,100,3,2023-01-08,Consumer,0.05,South,2023-01-10
1009,Desk Lamp,Furniture,50,2,2023-01-09,Home Office,0,North,2023-01-14
1010,Webcam,Electronics,80,1,2023-01-09,Corporate,0.05,South,2023-01-11
1011,Table,Furniture,200,1,2023-01-10,Consumer,0.1,North,2023-01-15
1012,Notebook,Office Supplies,3,10,2023-01-10,Corporate,0,South,2023-01-12
1013,Pen,Office Supplies,1,50,2023-01-11,Consumer,0,North,2023-01-13
1014,Stapler,Office Supplies,5,5,2023-01-11,Home Office,0.05,South,2023-01-14
1015,Eraser,Office Supplies,0.5,20,2023-01-12,Corporate,0,North,2023-01-13

“`python

创建模拟的 sales_data.csv 文件

csv_sales_content = “””OrderID,Product,Category,Price,Quantity,OrderDate,CustomerSegment,Discount,Region,DeliveryDate
1001,Laptop,Electronics,1200,1,2023-01-05,Corporate,0.1,North,2023-01-10
1002,Mouse,Electronics,25,2,2023-01-05,Consumer,0,South,2023-01-08
1003,Keyboard,Electronics,75,1,2023-01-06,Corporate,0.1,North,2023-01-11
1004,Desk,Furniture,300,1,2023-01-06,Home Office,0.15,South,2023-01-15
1005,Chair,Furniture,150,2,2023-01-07,Consumer,0,North,2023-01-12
1006,Monitor,Electronics,250,1,2023-01-07,Home Office,0.1,South,2023-01-12
1007,Bookcase,Furniture,450,1,2023-01-08,Corporate,0.15,North,2023-01-18
1008,Headphones,Electronics,100,3,2023-01-08,Consumer,0.05,South,2023-01-10
1009,Desk Lamp,Furniture,50,2,2023-01-09,Home Office,0,North,2023-01-14
1010,Webcam,Electronics,80,1,2023-01-09,Corporate,0.05,South,2023-01-11
1011,Table,Furniture,200,1,2023-01-10,Consumer,0.1,North,2023-01-15
1012,Notebook,Office Supplies,3,10,2023-01-10,Corporate,0,South,2023-01-12
1013,Pen,Office Supplies,1,50,2023-01-11,Consumer,0,North,2023-01-13
1014,Stapler,Office Supplies,5,5,2023-01-11,Home Office,0.05,South,2023-01-14
1015,Eraser,Office Supplies,0.5,20,2023-01-12,Corporate,0,North,2023-01-13
“””
with open(‘sales_data.csv’, ‘w’) as f:
f.write(csv_sales_content)

1. 加载数据

try:
df_sales_analysis = pd.read_csv(‘sales_data.csv’)
print(“Original Sales Data:”)
print(df_sales_analysis.head())
print(“\nData Info:”)
df_sales_analysis.info() # Check data types and non-null counts
except FileNotFoundError:
print(“Error: sales_data.csv not found.”)
exit() # Exit if data file not found

2. 数据清洗/预处理

检查缺失值 (本例数据没有缺失值,但这是一个重要步骤)

print(“\nMissing values per column:”)
print(df_sales_analysis.isnull().sum())

确保日期列是日期时间类型 (通常 read_csv 会自动识别,但最好显式转换)

df_sales_analysis[‘OrderDate’] = pd.to_datetime(df_sales_analysis[‘OrderDate’])
df_sales_analysis[‘DeliveryDate’] = pd.to_datetime(df_sales_analysis[‘DeliveryDate’])
print(“\nData Info after converting dates:”)
df_sales_analysis.info()

计算实际销售额 = 价格 * 数量 * (1 – 折扣)

df_sales_analysis[‘ActualSales’] = df_sales_analysis[‘Price’] * df_sales_analysis[‘Quantity’] * (1 – df_sales_analysis[‘Discount’])
print(“\nDataFrame with ActualSales column:”)
print(df_sales_analysis.head())

计算送货天数

df_sales_analysis[‘DeliveryDays’] = (df_sales_analysis[‘DeliveryDate’] – df_sales_analysis[‘OrderDate’]).dt.days
print(“\nDataFrame with DeliveryDays column:”)
print(df_sales_analysis.head())

3. 数据探索与分析

按产品类别统计总销售额

sales_by_category = df_sales_analysis.groupby(‘Category’)[‘ActualSales’].sum().sort_values(ascending=False)
print(“\nTotal Actual Sales by Category:”)
print(sales_by_category)

按客户细分统计平均送货天数

avg_delivery_by_segment = df_sales_analysis.groupby(‘CustomerSegment’)[‘DeliveryDays’].mean()
print(“\nAverage Delivery Days by Customer Segment:”)
print(avg_delivery_by_segment)

找出销售额最高的产品

top_selling_product = df_sales_analysis.loc[df_sales_analysis[‘ActualSales’].idxmax()]
print(“\nTop Selling Product:”)
print(top_selling_product)

按区域和类别统计总销售额,并将结果重塑为交叉表 (可选,但常用)

sales_pivot = df_sales_analysis.pivot_table(index=’Region’, columns=’Category’, values=’ActualSales’, aggfunc=’sum’)
print(“\nTotal Actual Sales Pivot Table (Region vs Category):”)
print(sales_pivot)

过滤出特定日期范围的数据 (例如,1月8号之后的数据)

after_jan_8 = df_sales_analysis[df_sales_analysis[‘OrderDate’] >= ‘2023-01-08’]
print(“\nOrders placed on or after 2023-01-08:”)
print(after_jan_8)

按区域过滤,并计算该区域的总销售额

north_sales = df_sales_analysis[df_sales_analysis[‘Region’] == ‘North’][‘ActualSales’].sum()
print(f”\nTotal Actual Sales in North Region: {north_sales:.2f}”)

4. 保存结果

将按类别统计的销售额保存到 CSV 文件

sales_by_category.to_csv(‘sales_by_category.csv’, header=[‘TotalSales’])
print(“\nSales by category saved to sales_by_category.csv.”)

将分析后的 DataFrame 保存到 Excel 文件

df_sales_analysis.to_excel(‘analyzed_sales_data.xlsx’, index=False)
print(“Analyzed sales data saved to analyzed_sales_data.xlsx.”)

“`
这个例子展示了如何使用 Pandas 读取数据、进行简单的日期处理、创建新列、执行分组聚合以及过滤数据,最后将结果保存。这构成了一个非常基础但完整的数据分析工作流。

10. 总结与下一步

恭喜你!你已经学习了 Python Pandas 的基础知识,包括:

  • Pandas 的用途和安装。
  • 核心数据结构 SeriesDataFrame 的创建和属性。
  • 使用标签 (loc) 和整数位置 (iloc) 选择数据。
  • 布尔索引进行数据过滤。
  • 添加、修改和删除列与行。
  • 检测和处理缺失数据。
  • 读取和保存 CSV、Excel 等文件。
  • 执行基本的统计计算和分组聚合。

这只是 Pandas 功能的冰山一角。Pandas 还有许多更高级和强大的特性,例如:

  • 数据合并 (merge, join, concat)。
  • 数据重塑 (pivot, melt, stack, unstack)。
  • 时间序列分析功能。
  • 窗口函数 (rolling, expanding)。
  • 分类数据 (Categorical Data) 处理。
  • 与其他库的集成(如 Matplotlib 进行可视化)。

掌握这些基础知识后,下一步可以尝试:

  • 找一些实际数据集(如 Kaggle 上的数据集)进行练习。
  • 深入学习 mergeconcat 用于组合数据。
  • 学习时间序列相关的操作,如果你的数据包含时间信息。
  • 学习如何使用 Pandas 结合 Matplotlib 或 Seaborn 进行数据可视化。

持续的实践是掌握 Pandas 最好的方法。希望这篇详细的基础教程能为你打开 Pandas 世界的大门,助你在数据分析的道路上更加高效和得心应手!

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部