pandas数据处理(一)
Pandas 名字衍生自术语 "panel data"(面板数据)和 "Python data analysis"(Python 数据分析)
参考: https://pandas.pydata.org/ http://c.biancheng.net/pandas/plot.html
1. 简介
Pandas 的主要数据结构是 Series (一维数据)与 DataFrame(二维数据)。
Series 是一种类似于一维数组的对象,它由一组数据(各种Numpy数据类型)以及一组与之相关的数据标签(即索引)组成。
DataFrame 是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型值)。DataFrame 既有行索引也有列索引,它可以被看做由 Series 组成的字典(共同用一个索引)。
2. 安装以及简单使用
- 安装
pip install pandas
- 简单使用
# author: qlq
# date: 2022/8/17 18:09
# desc:
import pandas as pd
print(pd.__version__)
mydataset = {
'sites': ["Google", "Runoob", "Wiki"],
'number': [1, 2, 3]
}
myvar = pd.DataFrame(mydataset)
print(myvar)
结果:
1.4.3
sites number
0 Google 1
1 Runoob 2
2 Wiki 3
3. Series
Series 类似表格中的一个列(column),类似于一维数组,可以保存任何数据类型。
Series 由索引(index)和列组成,函数如下:
pandas.Series( data, index, dtype, name, copy)
参数说明:
data:一组数据(ndarray 类型)。
index:数据索引标签,如果不指定,默认从 0 开始。
dtype:数据类型,默认会自己判断。
name:设置名称。
copy:拷贝数据,默认为 False。
简单使用:
import pandas as pd
a = [1, 2, 3]
myvar = pd.Series(a)
print(myvar)
'''
0 1
1 2
2 3
dtype: int64
'''
# 0, 1, 2 列可以称为索引。 1, 2, 3 是数据。dtype: int64 是数据类型
'''
从上图可知,如果没有指定索引,索引值就从 0 开始,我们可以根据索引值读取数据:
我们可以指定索引值,如下实例:
'''
a2 = ["Google", "Runoob", "Wiki"]
myvar2 = pd.Series(a2, index = ["x", "y", "z"])
print(myvar2)
'''
x Google
y Runoob
z Wiki
dtype: object
'''
print(myvar2["y"])
'''
Runoob
'''
'''
可以使用 key/value 对象,类似字典来创建 Series:
'''
sites = {1: "Google", 2: "Runoob", 3: "Wiki"}
myvar3 = pd.Series(sites)
print(myvar3)
'''
1 Google
2 Runoob
3 Wiki
dtype: object
'''
'''
从上图可知,字典的 key 变成了索引值。如果我们只需要字典中的一部分数据,只需要指定需要数据的索引即可,如下实例:
'''
sites2 = {1: "Google", 2: "Runoob", 3: "Wiki"}
myvar4 = pd.Series(sites2, index = [1, 2])
print(myvar4)
'''
1 Google
2 Runoob
dtype: object
'''
'''
设置 Series 名称参数:
'''
sites3 = {1: "Google", 2: "Runoob", 3: "Wiki"}
myvar5 = pd.Series(sites3, index = [1, 2], name="RUNOOB-Series-TEST" )
print(myvar5)
'''
1 Google
2 Runoob
Name: RUNOOB-Series-TEST, dtype: object
'''
4. DataFrame
DataFrame 是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型值)。DataFrame 既有行索引也有列索引,它可以被看做由 Series 组成的字典(共同用一个索引)。
如下图:
构造方法如下:
pandas.DataFrame( data, index, columns, dtype, copy)
参数解释:
data:一组数据(ndarray、series, map, lists, dict 等类型)。
index:索引值,或者可以称为行标签。
columns:列标签,默认为 RangeIndex (0, 1, 2, …, n) 。
dtype:数据类型。
copy:拷贝数据,默认为 False。
简单使用:
# Pandas DataFrame 是一个二维的数组结构,类似二维数组。
import pandas as pd
data = [['Google',10],['Runoob',12],['Wiki',13]]
df = pd.DataFrame(data,columns=['Site','Age'],dtype=float)
print(df)
'''
常见属性和方法:
T 行和列转置。
axes 返回一个仅以行轴标签和列轴标签为成员的列表。
dtypes 返回每列数据的数据类型。
empty DataFrame中没有数据或者任意坐标轴的长度为0,则返回True。
ndim 轴的数量,也指数组的维数。
shape 返回一个元组,表示了 DataFrame 维度。
size DataFrame中的元素数量。
values 使用 numpy 数组表示 DataFrame 中的元素值。
head() 返回前 n 行数据。
tail() 返回后 n 行数据。
shift() 将行或列移动指定的步幅长度
'''
print(df.axes)
print(df.index)
print(df.ndim)
print(df.size)
print(df.values)
print("======1")
# 使用 ndarrays 创建,ndarray 的长度必须相同, 如果传递了 index,则索引的长度应等于数组的长度。如果没有传递索引,则默认情况下,索引将是range(n),其中n是数组长度
data1 = {'Site':['Google', 'Runoob', 'Wiki'], 'Age':[10, 12, 13]}
df1 = pd.DataFrame(data1)
print(df1)
print("======2")
# 可以使用字典(key/value),其中字典的 key 为列名。没有对应的部分数据为 NaN。
data2 = [{'a': 1, 'b': 2},{'a': 5, 'b': 10, 'c': 20}]
df2 = pd.DataFrame(data2)
print(df2)
print("======3")
# 可以使用 loc 属性返回指定行的数据,如果没有设置索引,第一行索引为 0,第二行索引为 1,以此类推
data3 = {
"calories": [420, 380, 390],
"duration": [50, 40, 45]
}
# 数据载入到 DataFrame 对象
df3 = pd.DataFrame(data3)
print(df3)
# 返回第一行
print(df3.loc[0])
# 返回第二行
print(df3.loc[1])
# 返回第一行和第二行
print(df3.loc[[0, 1]])
print("======4")
# 指定索引值,使用 loc 属性返回指定索对应到某一行
data4 = {
"calories": [420, 380, 390],
"duration": [50, 40, 45]
}
df4 = pd.DataFrame(data4, index = ["day1", "day2", "day3"])
print(df4)
# 指定索引
print(df4.loc["day2"])
结果:
Site Age
0 Google 10.0
1 Runoob 12.0
2 Wiki 13.0
[RangeIndex(start=0, stop=3, step=1), Index(['Site', 'Age'], dtype='object')]
RangeIndex(start=0, stop=3, step=1)
2
6
[['Google' 10.0]
['Runoob' 12.0]
['Wiki' 13.0]]
======1
Site Age
0 Google 10
1 Runoob 12
2 Wiki 13
======2
a b c
0 1 2 NaN
1 5 10 20.0
======3
calories duration
0 420 50
1 380 40
2 390 45
calories 420
duration 50
Name: 0, dtype: int64
calories 380
duration 40
Name: 1, dtype: int64
calories duration
0 420 50
1 380 40
======4
calories duration
day1 420 50
day2 380 40
day3 390 45
calories 380
duration 40
Name: day2, dtype: int64
5. 操作csv、excel
比如nba.csv 格式如下:
Name,Team,Number,Position,Age,Height,Weight,College,Salary
Avery Bradley,Boston Celtics,0.0,PG,25.0,6-2,180.0,Texas,7730337.0
Jae Crowder,Boston Celtics,99.0,SF,25.0,6-6,235.0,Marquette,6796117.0
John Holland,Boston Celtics,30.0,SG,27.0,6-5,205.0,Boston University,
R.J. Hunter,Boston Celtics,28.0,SG,22.0,6-5,185.0,Georgia State,1148640.0
,,,,,,,,
测试代码:
# desc:
import pandas as pd
df = pd.read_csv('E:/nba.csv')
# to_string() 用于返回 DataFrame 类型的数据,如果不使用该函数,则输出结果为数据的前面 5 行和末尾 5 行,中间部分以 ... 代替
print(df.to_string())
print("======1")
# info() 方法返回表格的一些基本信息:
print(df.info())
print("======2")
# head( n ) 和 tail(n) 查看指定开头和结尾数据。 默认n=5
print(df.head())
print("======3")
print(df.tail())
# to_XXX 转储文件
df.to_csv("E:/nba1.csv")
df.to_excel("E:/nba1.xlsx")
结果:
Name Team Number Position Age Height Weight College Salary
0 Avery Bradley Boston Celtics 0.0 PG 25.0 6-2 180.0 Texas 7730337.0
1 Jae Crowder Boston Celtics 99.0 SF 25.0 6-6 235.0 Marquette 6796117.0
2 John Holland Boston Celtics 30.0 SG 27.0 6-5 205.0 Boston University NaN
3 R.J. Hunter Boston Celtics 28.0 SG 22.0 6-5 185.0 Georgia State 1148640.0
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN
======1
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Name 4 non-null object
1 Team 4 non-null object
2 Number 4 non-null float64
3 Position 4 non-null object
4 Age 4 non-null float64
5 Height 4 non-null object
6 Weight 4 non-null float64
7 College 4 non-null object
8 Salary 3 non-null float64
dtypes: float64(4), object(5)
memory usage: 488.0+ bytes
None
======2
Name Team Number ... Weight College Salary
0 Avery Bradley Boston Celtics 0.0 ... 180.0 Texas 7730337.0
1 Jae Crowder Boston Celtics 99.0 ... 235.0 Marquette 6796117.0
2 John Holland Boston Celtics 30.0 ... 205.0 Boston University NaN
3 R.J. Hunter Boston Celtics 28.0 ... 185.0 Georgia State 1148640.0
4 NaN NaN NaN ... NaN NaN NaN
[5 rows x 9 columns]
======3
Name Team Number ... Weight College Salary
0 Avery Bradley Boston Celtics 0.0 ... 180.0 Texas 7730337.0
1 Jae Crowder Boston Celtics 99.0 ... 235.0 Marquette 6796117.0
2 John Holland Boston Celtics 30.0 ... 205.0 Boston University NaN
3 R.J. Hunter Boston Celtics 28.0 ... 185.0 Georgia State 1148640.0
4 NaN NaN NaN ... NaN NaN NaN
[5 rows x 9 columns]
同理也有操作excel的相关API
import pandas as pd
df = pd.read_excel('E:/nba1.xlsx')
# to_string() 用于返回 DataFrame 类型的数据,如果不使用该函数,则输出结果为数据的前面 5 行和末尾 5 行,中间部分以 ... 代替
print(df.to_string())
6. 操作JSON
nested_list.json 代码如下:
{
"school_name": "ABC primary school",
"class": "Year 1",
"students": [
{
"id": "A001",
"name": "Tom",
"math": 60,
"physics": 66,
"chemistry": 61
},
{
"id": "A002",
"name": "James",
"math": 89,
"physics": 76,
"chemistry": 51
},
{
"id": "A003",
"name": "Jenny",
"math": 79,
"physics": 90,
"chemistry": 78
}]
}
简单使用:
# desc:
import json
import pandas as pd
df = pd.read_json('E:/nested_list.json')
print(df.to_string())
print("======1")
json_path = 'E:/nested_list.json'
# 使用 Python JSON 模块载入数据
# 展平数据
with open(json_path,'r') as f:
data = json.loads(f.read())
df_nested_list = pd.json_normalize(data, record_path =['students'])
print(df_nested_list)
print("======2")
# 使用 Python JSON 模块载入数据
with open(json_path,'r') as f:
data = json.loads(f.read())
# 展平数据。
# json_normalize() 使用了参数 record_path 并设置为 ['students'] 用于展开内嵌的 JSON 数据 students
# 使用 meta 参数来显示这些元数据
df_nested_list = pd.json_normalize(
data,
record_path =['students'],
meta=['school_name', 'class']
)
print(df_nested_list)
结果:
school_name class students
0 ABC primary school Year 1 {'id': 'A001', 'name': 'Tom', 'math': 60, 'physics': 66, 'chemistry': 61}
1 ABC primary school Year 1 {'id': 'A002', 'name': 'James', 'math': 89, 'physics': 76, 'chemistry': 51}
2 ABC primary school Year 1 {'id': 'A003', 'name': 'Jenny', 'math': 79, 'physics': 90, 'chemistry': 78}
======1
id name math physics chemistry
0 A001 Tom 60 66 61
1 A002 James 89 76 51
2 A003 Jenny 79 90 78
======2
id name math physics chemistry school_name class
0 A001 Tom 60 66 61 ABC primary school Year 1
1 A002 James 89 76 51 ABC primary school Year 1
2 A003 Jenny 79 90 78 ABC primary school Year 1
7. 数据清洗
主要包括空值处理、错误数据处理、重复数据处理。
例如数据如下 property-data.csv
上表包含了四种空数据:
- n/a
- NA
- —
- na
1. 空值处理
使用 dropna() 方法,语法格式如下:
DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
axis:默认为 0,表示逢空值剔除整行,如果设置参数 axis=1 表示逢空值去掉整列。
how:默认为 'any' 如果一行(或一列)里任何一个数据有出现 NA 就去掉整行,如果设置 how='all' 一行(或列)都是 NA 才去掉这整行。
thresh:设置需要多少非空值的数据才可以保留下来的。
subset:设置想要检查的列。如果是多个列,可以使用列名的 list 作为参数。
inplace:如果设置 True,将计算得到的值直接覆盖之前的值并返回 None,修改的是源数据。
1. 检测空值
Pandas 把 n/a 和 NA 当作空数据,na 不是空数据。 可以通过自己指定然后设置为空的值。
import pandas as pd
csv_path = 'E:/property-data.csv'
df = pd.read_csv(csv_path)
print (df['NUM_BEDROOMS'])
# isnull() 判断各个单元格是否为空
# 把 n/a 和 NA 当作空数据,na 不是空数据
print (df['NUM_BEDROOMS'].isnull())
# 自定义为空值的值
print("======1")
missing_values = ["n/a", "na", "--"]
df1 = pd.read_csv(csv_path, na_values = missing_values)
print (df1['NUM_BEDROOMS'])
print (df1['NUM_BEDROOMS'].isnull())
结果:
0 3
1 3
2 NaN
3 1
4 3
5 NaN
6 2
7 1
8 na
Name: NUM_BEDROOMS, dtype: object
0 False
1 False
2 True
3 False
4 False
5 True
6 False
7 False
8 False
Name: NUM_BEDROOMS, dtype: bool
======1
0 3.0
1 3.0
2 NaN
3 1.0
4 3.0
5 NaN
6 2.0
7 1.0
8 NaN
Name: NUM_BEDROOMS, dtype: float64
0 False
1 False
2 True
3 False
4 False
5 True
6 False
7 False
8 True
Name: NUM_BEDROOMS, dtype: bool
2. 删除包含空值的行
import pandas as pd
csv_path = 'E:/property-data.csv'
# 删除包含空数据的行
# 默认情况下,dropna() 方法返回一个新的 DataFrame,不会修改源数据。 如果要修改源数据 DataFrame, 可以使用 inplace = True 参数:
df = pd.read_csv(csv_path)
new_df = df.dropna()
print(new_df.to_string())
结果:
PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0 100001000.0 104.0 PUTNAM Y 3 1 1000
1 100002000.0 197.0 LEXINGTON N 3 1.5 --
8 100009000.0 215.0 TREMONT Y na 2 1800
3. 移除指定列有空值的行
import pandas as pd
csv_path = 'E:/property-data.csv'
df = pd.read_csv(csv_path)
df.dropna(subset=['ST_NUM'], inplace = True)
print(df.to_string())
结果:
PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0 100001000.0 104.0 PUTNAM Y 3 1 1000
1 100002000.0 197.0 LEXINGTON N 3 1.5 --
3 100004000.0 201.0 BERKELEY 12 1 NaN 700
4 NaN 203.0 BERKELEY Y 3 2 1600
5 100006000.0 207.0 BERKELEY Y NaN 1 800
7 100008000.0 213.0 TREMONT Y 1 1 NaN
8 100009000.0 215.0 TREMONT Y na 2 1800
4. fillna 方法替换空值
import pandas as pd
csv_path = 'E:/property-data.csv'
df = pd.read_csv(csv_path)
df.fillna('12345', inplace = True)
# 也可以指定列
# df['PID'].fillna(12345, inplace = True)
print(df.to_string())
结果:
PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0 100001000.0 104.0 PUTNAM Y 3 1 1000
1 100002000.0 197.0 LEXINGTON N 3 1.5 --
2 100003000.0 12345 LEXINGTON N 12345 1 850
3 100004000.0 201.0 BERKELEY 12 1 12345 700
4 12345 203.0 BERKELEY Y 3 2 1600
5 100006000.0 207.0 BERKELEY Y 12345 1 800
6 100007000.0 12345 WASHINGTON 12345 2 HURLEY 950
7 100008000.0 213.0 TREMONT Y 1 1 12345
8 100009000.0 215.0 TREMONT Y na 2 1800
5. 均值、中位数、众数
mean()、median() 和 mode() 方法计算列的均值(所有值加起来的平均值)、中位数值(排序后排在中间的数)和众数(出现频率最高的数)
一般用上面的数来替换空值。
import pandas as pd
csv_path = 'E:/property-data.csv'
df = pd.read_csv(csv_path)
# 均值
print(df["ST_NUM"].mean())
# 中位数
print(df["ST_NUM"].median())
# 众数
print(df["ST_NUM"].mode())
结果:
191.42857142857142
203.0
0 104.0
1 197.0
2 201.0
3 203.0
4 207.0
5 213.0
6 215.0
2. 清洗错误数据
1. 定位数据然后修改
import pandas as pd
person = {
"name": ['Google', 'Runoob' , 'Taobao'],
"age": [50, 40, 12345] # 12345 年龄数据是错误的
}
df = pd.DataFrame(person)
df.loc[2, 'age'] = 30 # 修改数据
print(df.to_string())
结果:
name age
0 Google 50
1 Runoob 40
2 Taobao 30
2. 通过条件修改
import pandas as pd
person = {
"name": ['Google', 'Runoob' , 'Taobao'],
"age": [50, 200, 12345]
}
# 将 age 大于 120 的设置为 120:
df = pd.DataFrame(person)
for x in df.index:
if df.loc[x, "age"] > 120:
df.loc[x, "age"] = 120
print(df.to_string())
3. 删除错误的行数据
import pandas as pd
person = {
"name": ['Google', 'Runoob' , 'Taobao'],
"age": [50, 200, 12345]
}
# 将 age 大于 120 的数据删除
df = pd.DataFrame(person)
for x in df.index:
if df.loc[x, "age"] > 120:
df.drop(x, inplace = True)
print(df.to_string())
3. 重复数据处理
清洗重复数据,可以使用 duplicated() 和 drop_duplicates() 方法
如果对应的数据是重复的,duplicated() 会返回 True,否则返回 False。
- 检测重复数据
import pandas as pd
person = {
"name": ['Google', 'Runoob', 'Runoob', 'Taobao'],
"age": [50, 40, 40, 23]
}
df = pd.DataFrame(person)
print(df.to_string())
print("======1")
print(df.duplicated())
结果:
name age
0 Google 50
1 Runoob 40
2 Runoob 40
3 Taobao 23
======1
0 False
1 False
2 True
3 False
dtype: bool
- 删除重复数据
import pandas as pd
person = {
"name": ['Google', 'Runoob', 'Runoob', 'Taobao', 'JD'],
"age": [50, 40, 40, 23, 50]
}
df = pd.DataFrame(person)
print(df.to_string())
print("======1")
# 按全部的列去重
df.drop_duplicates(inplace = True)
print(df.to_string())
print("======1")
# 按指定的列进行去重
df.drop_duplicates(subset= ['age'], inplace = True)
print(df.to_string())
结果:
name age
0 Google 50
1 Runoob 40
2 Runoob 40
3 Taobao 23
4 JD 50
======1
name age
0 Google 50
1 Runoob 40
3 Taobao 23
4 JD 50
======1
name age
0 Google 50
1 Runoob 40
3 Taobao 23