Panda basic

(本博客基于Kaggle教材 link:https://www.kaggle.com/learn/pandas)

Panda

Panda 是一个强大的 Python 库,主要用于数据分析。在本人的学习中,我认为Panda与SQL有异曲同工之妙,如果你直接接触过SQL你可以把其理解为一个Python版本的SQL

1
import pandas as pd # 引入 pandas 库,并起个别名 pd,方便后面使用

Panda 有两个核心概念:DataFrame 和 Series。

DataFrame:表格数据

DataFrame 就像一个表格,有行和列。

  • 列(column):表格中竖着的一列数据,可以理解为 Excel 中的一列。
  • 行(record / row):表格中横着的一行数据,可以理解为 Excel 中的一行。
1
2
# 创建一个 DataFrame
pd.DataFrame({'Yes': [50, 21], 'No': [131, 2]})

alt text

创建 DataFrame 就像创建一个字典:

  • Key:列名
  • Value:列的数据

例如:

1
2
3
4
# 创建一个 DataFrame,并指定行索引
pd.DataFrame({'Bob': ['I liked it.', 'It was awful.'],
'Sue': ['Pretty good.', 'Bland.']},
index=['Product A', 'Product B'])

Series:一列数据

Series 就像一个列表,只有一列数据。可以看作是 DataFrame 的一部分。

1
pd.Series([1, 2, 3, 4, 5]) # 创建一个 Series

Series 的索引也可以是字符串:

1
2
# 创建一个 Series,并指定索引和名称
pd.Series([30, 35, 40], index=['2015 Sales', '2016 Sales', '2017 Sales'], name='Product A')

读取数据

Panda 可以读取 CSV 文件,CSV 文件是一种常见的表格数据格式。

1
2
# 从 CSV 文件中读取数据,并指定第一列作为索引
wine_reviews = pd.read_csv("../input/wine-reviews/winemag-data-130k-v2.csv", index_col=0)

index_col=0 的作用是告诉 Panda,CSV 文件中已经有一列作为索引了,不要再自动创建新的索引。

shape 属性可以查看 DataFrame 的大小(行数和列数):

1
wine_reviews.shape # 查看 DataFrame 的大小

head() 方法可以查看 DataFrame 的前几行数据:

1
wine_reviews.head() # 查看 DataFrame 的前 5 行数据

保存数据

Panda 可以将 DataFrame 保存为 CSV 文件:

1
# df.to_csv("xxx.csv") # 将 DataFrame 保存为 CSV 文件

数据选择

选取数据

Panda 提供了多种选取数据的方法。

原生 Python 方式

可以使用 .[] 来选取数据,和 Python 中访问对象属性的方式类似。

Panda 方式:lociloc

Panda 提供了 lociloc 两种方法来选取数据。

  • loc:使用标签(label)来选取数据,例如行索引或列名。
  • iloc:使用数字(integer)来选取数据,例如行号或列号。

注意: lociloc 选取数据时都是先,与 Python 中常见的先不同。

1
# reviews.iloc[0] # 选取第一行数据
1
# reviews.iloc[:, 0] # 选取第一列数据

例如:

1
2
# reviews.loc["A",'B'] # 选取行索引为 "A",列名为 "B" 的数据
# reviews.iloc[0, 0] # 选取第一行第一列的数据

set_index() 方法可以将 DataFrame 中已有的某一列设置为新的索引:

条件选择

可以使用条件表达式来选取满足条件的数据。

1
# reviews.country == 'Italy' # 选取 'country' 列的值为 'Italy' 的行

返回:

1
2
3
0     True
1 False
...

可以使用 loc 方法结合条件表达式来选取数据:

1
# reviews.loc[reviews.country == 'Italy'] # 选取 'country' 列的值为 'Italy' 的所有行

相当于 SQL 中的 SELECT * FROM reviews WHERE country = 'Italy'

可以使用多个条件:

1
# reviews.loc[(reviews.country == 'Italy') & (reviews.points >= 90)] # 选取 'country' 列的值为 'Italy' 且 'points' 列的值大于等于 90 的行
1
# reviews.loc[(reviews.country == 'Italy') | (reviews.points >= 90)] # 选取 'country' 列的值为 'Italy' 或 'points' 列的值大于等于 90 的行
  • | 表示 “或” (or)
  • & 表示 “与” (and)

isin() 方法可以判断一列的值是否在给定的列表中:

1
# reviews.loc[reviews.country.isin(['Italy', 'France'])] # 选取 'country' 列的值为 'Italy' 或 'France' 的行

isnull()notnull() 方法可以判断一列的值是否为空:

  • isnull():如果元素是缺失值,则返回 True,否则返回 False。
  • notnull():如果元素不是缺失值,则返回 True,否则返回 False。
1
# reviews.loc[reviews.price.notnull()] # 选取 'price' 列的值不为空的所有行

赋值

可以直接给 DataFrame 添加新的列,并赋值:

1
2
# reviews['critic'] = 'everyone' # 给 'critic' 列赋值为 'everyone'
# reviews['critic']

可以根据现有列的值计算出新的列的值:

1
2
# reviews['index_backwards'] = range(len(reviews), 0, -1) # 创建一个新的列 'index_backwards',其值为 reviews 的索引倒序
# reviews['index_backwards']

Summary Functions and Maps


Summary Functions 摘要函数

  • describe(): 生成列的统计摘要(数值型与字符串型输出不同)。
    • 数值列:count, mean, std, min, 25%, 50%, 75%, max.
    • 字符串列:count, unique, top(最高频值), freq(最高频次数)。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
      reviews.points.describe()  # 数值列示例  
    reviews.taster_name.describe() # 字符串列示例
    ```

    - **`mean()`**: 计算数值列的平均值。
    ```python
    reviews.points.mean() # 输出平均评分
    ```

    - **`unique()`**: 返回列的唯一值数组。
    ```python
    reviews.taster_name.unique() # 所有品酒师名字
    ```

    - **`value_counts()`**: 统计各唯一值出现的次数。
    ```python
    reviews.taster_name.value_counts() # 品酒师评酒次数统计
    ```

    - idxmax() 返回 Series 或 DataFrame 中最大值的索引。
    ---

    ## **Maps 映射**
    - **`map()`**: 对Series中的每个元素应用函数,返回新Series。
    ```python
    # 将评分转换为与均值的差值
    review_points_mean = reviews.points.mean()
    reviews.points.map(lambda p: p - review_points_mean)
    ```

    - **`apply()`**: 对DataFrame的行或列应用函数。
    ```python
    # 转换整个DataFrame的评分列
    def remean_points(row):
    row.points -= review_points_mean
    return row
    reviews.apply(remean_points, axis='columns')
    ```

    - **向量化操作**: 使用Pandas内置运算符更高效(如`+`, `-`, `>`等)。
    ```python
    # 直接计算评分与均值的差值
    reviews.points - reviews.points.mean()

    # 合并两列(如国家与产区)
    reviews.country + " - " + reviews.region_1
    ```

    ---

    ## **注意**
    - `map()`和`apply()`返回**新对象**,不修改原始数据。
    - 向量化操作比`map()`/`apply()`更快,但复杂逻辑仍需后者。


    ## 数据分组与排序操作

    ### groupby() - 数据分组
    按指定列对数据进行分组,常用于数据聚合分析。
    ```python
    # 按国家分组并计算平均得分
    reviews.groupby('country').points.mean()

agg() - 多重统计

在一个操作中执行多个统计聚合。

1
2
3
4
5
# 同时计算多个统计量
reviews.groupby('country').agg({
'points': ['mean', 'min', 'max'],
'price': ['mean', 'median']
})

reset_index() - 重置索引

将多级索引DataFrame转换为普通列。

1
2
3
# 重置分组后的索引
grouped_data = reviews.groupby('country').mean()
grouped_data.reset_index()

排序函数

sort_values() - 按值排序

按指定列的值进行排序。

参数:

  • by: 用于排序的列名
  • ascending: 排序方向(默认True升序,False降序)
1
2
3
4
5
# 按价格降序排序
reviews.sort_values(by='price', ascending=False)

# 按多列排序
reviews.sort_values(by=['country', 'price'])

sort_index() - 按索引排序

按行索引进行排序。

1
2
# 恢复原始索引顺序
countries_reviewed.sort_index()

注意: 排序函数返回排序后的新DataFrame,不会修改原始数据。要修改原始数据,需要使用inplace=True参数。

数据类型和缺失值处理

数据类型操作

dtype 属性

查看单个列的数据类型。

1
2
# 查看价格列的数据类型
reviews.price.dtype # 输出: dtype('float64')

dtypes 属性

查看DataFrame中所有列的数据类型。

1
2
# 显示所有列的数据类型
reviews.dtypes

astype() - 类型转换

将列转换为指定的数据类型。

1
2
# 将分数列转换为浮点型
reviews.points.astype('float64')

缺失值处理

检测缺失值

  • pd.isnull(): 检测是否为缺失值(NaN)
  • pd.notnull(): 检测是否不是缺失值
1
2
# 筛选国家信息缺失的行
reviews[pd.isnull(reviews.country)]

fillna() - 填充缺失值

用指定的值替换NaN。

1
2
# 将region_2中的缺失值替换为"未知"
reviews.region_2.fillna("未知")

replace() - 替换值

替换特定的非空值。

1
2
# 替换Twitter用户名
reviews.taster_twitter_handle.replace("@kerinokeefe", "@kerino")

注意事项

  • 字符串列的数据类型显示为object
  • NaN在Pandas中总是以float64类型存储
  • 处理缺失值的函数默认返回新的副本,使用inplace=True可以直接修改原数据

数据重命名和合并操作

重命名操作

rename() - 重命名列或索引

1
2
3
4
5
# 重命名列
reviews.rename(columns={'points': 'score'})

# 重命名索引
reviews.rename(index={0: 'first', 1: 'second'}) # 实际的指引 类似 row[0] 变成 row['first']

rename_axis() - 重命名轴

1
2
# 重命名行和列的轴名称
reviews.rename_axis("wines", axis='rows').rename_axis("fields", axis='columns') # 也就是row[0 ,1,2... ] 这整个的名字 变成 rows[0,1,2,3,....]

set_index() - 设置索引

1
2
3
4
5
# 将指定列设置为索引
reviews.set_index('title')

# 设置多级索引
reviews.set_index(['country', 'region'])

对比 SQL

特性 Pandas set_index() MultiIndex SQL CREATE INDEX Composite Index
作用 修改DataFrame结构,设置行索引 创建独立的索引对象,优化查询
数据结构 索引是DataFrame的一部分 索引是独立的元数据
多重索引 支持多重索引(MultiIndex) 支持复合索引
更新方式 修改索引通常需要重建DataFrame 数据库自动维护索引更新
性能影响 Pandas索引修改的计算开销(如内存占用) 操作耗时(因维护索引)
主要用途 数据分析、标签选择、对齐和分组 查询性能优化

数据合并操作

concat() - 数据拼接

将多个DataFrame或Series对象连接在一起。

1
2
3
4
5
# 纵向拼接(默认)
pd.concat([df1, df2])

# 横向拼接
pd.concat([df1, df2], axis=1)

join() - 基于索引合并

根据索引将两个DataFrame合并。

1
2
3
4
5
# 基本连接
left.join(right)

# 处理重复列名
left.join(right, lsuffix='_LEFT', rsuffix='_RIGHT')

注意事项

  • rename()set_index()默认返回新的DataFrame
  • 使用inplace=True参数可以直接修改原始数据
  • 合并操作前建议检查数据结构,避免出现意外结果
  • 处理重复列名时,建议使用合适的后缀