python数据处理pandas库

Connor

开始之前

说在前面,我才疏学浅,本文起到的更多是对我个人学习数据处理的总结作用。文中如有问题还请多多指教orz

在阅读文本之前,希望你已经了解并掌握

  • python基础语法
  • numpy库
  • Jupyter Notebook的使用

Jupyter

什么是Jupyter

我们正常运行py代码的时候,按一下运行键会跑完整个代码。
但是有的时候我们可能需要频繁的更改每一部分,如果重新运行的话那整个程序需要重跑一遍,会浪费很多时间。

这时通过Jupyter,我们可以只运行其中的一部分代码,并即使看到输出,即使改了某一部分代码,前面的代码也不需要重新运行,直接重新运行更改部分和之后部分就可以了。

这东西对数据处理有大用

怎么下

呃呃呃虽然但是,pycharm是完美兼容Jupyter的,我们只需要在pycharm创建一个Jupyter Notebook(即后缀名是.ipynb)的文件可以了

至于用的是vscode的话应该得下个插件(,

怎么使用?

先创建一个.ipynb的文件, 然后写点东西
![[source/images/pandas_images/image1.png]]
如果你上过人工智能导论(,那么你应该很熟悉这个界面了,点一下旁边的运行符号就可以了!有手就行
![[source/images/pandas_images/image2.png]]
就像这样。

Pandas库的使用

pandas库是一个用来进行数据处理的非常强大的库

确保你已经安装了Pandas库之后(若未安装,请在终端输入pip install pandas),运行下面这段代码

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
import pandas as pd
import numpy as np
import random

# 设置随机种子,确保结果可复现
np.random.seed(42)

# 1. 构造基础数据
n_rows = 200
cities = ['New York', 'London', 'Beijing', 'Paris', 'Tokyo', 'Sydney', 'Berlin', 'Moscow', 'Dubai', 'Singapore']
regions = ['North America', 'Europe', 'Asia', 'Europe', 'Asia', 'Oceania', 'Europe', 'Europe', 'Middle East', 'Asia']
city_to_region = dict(zip(cities, regions))

data = {
'City': [random.choice(cities) for _ in range(n_rows)],
'Year': [random.randint(2015, 2023) for _ in range(n_rows)],
'GDP_Per_Capita': np.random.normal(50000, 15000, n_rows).tolist(),
'CO2_Emissions': np.random.normal(10, 5, n_rows).tolist(),
'Population': np.random.randint(1000000, 20000000, n_rows).tolist(),
'Green_Space_Area': np.random.uniform(5, 40, n_rows).tolist(),
'Status': [random.choice(['Developed', 'Developing', 'under_review']) for _ in range(n_rows)]
}

df = pd.DataFrame(data)

# --- 2. 埋入“脏数据” ---

# 埋入空值 (NaN)
for _ in range(15):
df.loc[random.randint(0, n_rows-1), 'CO2_Emissions'] = np.nan
df.loc[random.randint(0, n_rows-1), 'Green_Space_Area'] = np.nan

# 埋入重复行
df = pd.concat([df, df.iloc[:5]], ignore_index=True)

# 埋入异常值 (比如GDP是负数,或者超级大)
df.loc[10, 'GDP_Per_Capita'] = -99999
df.loc[20, 'GDP_Per_Capita'] = 10000000

# 埋入格式不统一的字符串
df.loc[30, 'City'] = ' beijing '
df.loc[40, 'City'] = 'LONDON'

# 增加一个 Region 列,并故意留出几个错误
df['Region'] = df['City'].map(city_to_region)
df.loc[50, 'Region'] = 'Wrong_Region'

# 3. 保存为 Excel
df.to_excel('dirty_city_data.xlsx', index=False)
print("成功生成 dirty_city_data.xlsx!快去查看吧。")

这是一段用来生成dirty_city_data.xlsx文件的代码,文章接下来的内容通过处理这个文件的数据来展开

两种数据结构

pandas的用来处理数据的数据结构主要有两种,Series和DataFrame

Series

Series 是一维、带索引的数据结构
可以理解成:一列数据 或者 “带索引的一维数组 / 有序字典”

特点:

  • 每个元素都有一个 index(索引)
  • 可以存任意数据类型(数值、字符串、对象等)

示例
创建Series

1
2
3
4
5
import pandas as pd

#左边是值,右边是索引
s = pd.Series([10, 20, 30], index=['a', 'b', 'c'])
print(s)

输出的结果是

1
2
3
4
a    10
b 20
c 30
dtype: int64

前三行是一个Series存的键值对,dtype表示值的数据类型。
这里是int64,其实就是C的long long

若想访问元素,可

1
2
s['a']     # 10
s[0] # 10

两种方式都可以

DataFrame

DataFrame 是二维、带行索引和列索引的表格型数据结构
可以理解成excel,或者多行的Series

特点:

  • 二维(行 + 列)
  • 每一列本质上是一个 Series
  • 列可以是不同的数据类型

例如:
创建DataFrame

1
2
3
4
5
6
df = pd.DataFrame({
'name': ['Alice', 'Bob'],
'age': [20, 21],
'score': [88.5, 92.0]
})
print(df)

输出

1
2
3
    name  age  score
0 Alice 20 88.5
1 Bob 21 92.0

访问

1
2
3
df['age']        # 返回一个 Series
df.loc[0] # 返回一行(Series)
df.loc[0, 'age'] # 单个元素

其中,loc[]用来访问DataFrame的数据,因为DataFrame是二维的,所以需要输入横纵坐标/索引
如果只输入行索引,会返回那一行的Series

如果输入行索引和列索引,就会返回那个具体的元素。

上面的内容只需了解两种数据结构即可(。下面才是重头戏

读取excel

建议接下来把每段代码放进Jupyter Notebook的一个代码块,然后单独运行,既方便,也能直观感受到Jupyter的便利

1
2
3
4
5
import pandas as pd  
import numpy as np

fpath = "dirty_city_data.xlsx"
df = pd.read_excel(fpath)

我们就成功读取用DataFrame存下了excel并且存到了df里

文档基本情况

1
print(df.head())

输出df的前五行数据

1
print(df.shape)

输出df的行数 和 列数

1
print(df.dtypes)

输出每一列的数据类型int64, float64, object
其中string返回的都是object

1
df.info()

这个输出的就比较多了,并且这条语句不需要print()

运行之后能看到
行索引数、每列的名称和每列非空元素的个数,以及每列的数据类型、还有内存大小

1
print(df.describe())

输出每一列数据的非空元素个数,平均数,标准差,最小值,最大值,下四分位数、中位数、上四分位数、最大值(输出的也挺多

统计错误

在清洗数据之前,我们要先知道数据哪有问题

1
df.isnull().sum()

会统计每一列分别有多少个空单元格(NaN)。

1
df.duplicated().sum()

会统计整个表格中有多少行是完全一模一样的。

当然,我们也需要观察df.describe(), 刚刚甚至出现了GDP为-99999的城市和GDP为1e7的城市,这是很明显的错误数据

数据中还有由于录入错误出现不同的的 ‘ Beijing’ 和 ‘beijing’,我们的期望是要将这两个当作一个城市看待。 

清洗数据

去重

对于重复数据,我们一般选择直接扔掉一组

1
df.drop_duplicates(subset=['City', 'Year'], keep='first', inplace=True)

即可去重

其中,subset = ['City', 'Year']是指,若某些行中这两列的数据是一样的,即认为这些行是重复的。
如果不加这个参数,就认为某些行所有列的数据都一样才算重复
keep = 'first是指保留第一个
inplace = True的话是直接对原来的df进行修改,如果是False是返回新表,原表不变。

字符串去空格与统一

为了修正由于录入错误导致的 ‘ Beijing’ 和 ‘beijing’ 无法匹配的问题。

我们需要这两个函数
.str.strip()去掉字符串首尾的空白元素
.str.title()将字符串转为首字母大写,其他小写

这两个函数都不会在原来的字符串上修改,所以需要用变量接住

1
2
# 先去掉多余空格,再统一首字母大写
df['City'] = df['City'].str.strip().str.title()

其中,df['City']会返回City那一列的Series

处理缺失值 NaN

缺失值不能像重复值一样直接删掉,需要分情况讨论

df.dropna()可以直接删掉空白值所在的哪一行
如果某一列是核心指标并且缺了它就没意义了,那就删掉

1
2
# 如果 Green_Space_Area 是空的,就把这一行删了 
df.dropna(subset=['Green_Space_Area', 'Region'], inplace=True)

其中subset = ['Green_Space_Area', 'Region'],表示要处理的列, inplace同样表示是否在原来的df上直接更改

但更多时候,我们选的不是直接删掉,而是填充平均数或者中位数。
我们用df.fillna()来填充

比如,

1
2
3
4
5
med_C02 = df['CO2_Emissions'].mean() #整列的平均值
df['CO2_Emissions'] = df['CO2_Emissions'].fillna(med_C02)

med_Green_Space_Area = df['Green_Space_Area'].median() #整列的中位数
df['Green_Space_Area'] = df['Green_Space_Area'].fillna(med_Green_Space_Area)

处理异常值

df.loc[]是通过二维索引来定位元素在df中的位置的
我们可以通过df.loc[行过滤条件, 列名] = new_val来更改元素

我们刚刚在df.describe()中发现了负的GDP
我们将所有负的GDP都改成0,即

1
df.loc[df['GDP_Per_Capita'] < 0, 'GDP_Per_Capita'] = 0

其中,df['GDP_Per_Capita'] < 0返回的是一个bool Series,形如

1
2
3
4
5
0    False
1 True
2 False
3 True
dtype: bool

然后,df.loc[]只在True的地方做更改。

同理,我们也可以把是几千万的强制改成二十万

1
2
# 假设我们认为 GDP 超过 20万 都是录入错误,强行让它等于 20万
df.loc[df['GDP_Per_Capita'] > 200000, 'GDP_Per_Capita'] = 200000

错误分类统一化

.replace(old, new)可以把某列中的某个值全部更换成新值

1
2
# 把之前故意埋进去的 'Wrong_Region' 统一改成 'Asia' 
df['Region'] = df['Region'].replace('Wrong_Region', 'Asia')

我们完成了简单的清洗操作!

新增列

在 Pandas 中,新增一列最简单的方法就像给字典赋值一样:df['新列名'] = vals

比如我们想加一个'Density'列表示密度。为了方便我们就假装密度 = 人口 / 10000
我们可以这样新加列

1
df['Density'] = df['Population'] / 10000

聚合统计

我们想:把数据按“地区(Region)”分堆,然后算出每一堆的“密度(Density)”平均值。
比如算出亚洲的平均密度,欧洲的平均密度。

1
2
# 生成一个新的名为 region_density 的 Series 或 DataFrame
region_density = df.groupby('Region')['Density'].mean()

.groupby('Region')
会扫描 Region 列,把相同值的行(比如所有 ‘Asia’ 的行)放在一起。['Density']表示只对Density操作,.mean()求平均值

因为['Density']取得是一列,最后的结果是一个Series

如果想返回DataFrame,加一个中括号就可以

1
region_density = df.groupby('Region')[['Density']].mean()

这种方法返回的Region是索引,如
![[source/images/pandas_images/image3.png]]

如果我们想让Region不是索引,而是让数字作为索引。需要这么写

1
region_density = df.groupby('Region', as_index=False)['Density'].mean()

加上as_index = False,并且去掉刚才加的那个中括号
![[image4.png]]

保存结果

我们想把处理之后的df作为excel文件保存
使用.toexcel()即可

1
2
# 将 final_table 保存为 Excel 文件 
final_table.to_excel('final.xlsx', index=False)

'final.xlsx'是保存的文件名
参数index的含义是:是否保存行索引。
Pandas 默认会把最左边的行号(0, 1, 2…)也存进 Excel。
如果不设为 False,生成的 Excel 第一列会是一串数字。

  • Title: python数据处理pandas库
  • Author: Connor
  • Created at : 2026-01-20 00:30:01
  • Updated at : 2026-01-25 20:06:23
  • Link: https://redefine.ohevan.com/2026/01/20/Pandas/
  • License: This work is licensed under CC BY-NC-SA 4.0.