数据科学必备Pandas数据集操作详解

在对已有数据集不知道从何下手处理的时候,或者领导要求从这份数据中统计一些相关的内容信息的话,那么 Python 中的 Pandas 可以帮助你处理这些复杂的数据信息,不管数据是大是小都可以拆分成可操作的部分,并进行处理获得想要的结果。

通过本文可以学习到:

  • 使用 Series 和 DataFrame 对象。
  • .loc、.iloc的使用和索引运算符对数据进行子集的操作。
  • 通过查询、分组和聚合数据。
  • 处理缺失、无效和不一致的数据。
  • 在 Jupyter 笔记本中可视化您的数据集。

在这里插入图片描述

环境的配置

首先是熟悉 Python 的内置数据结构,尤其是列表和字典。可以参考前面的内容。

Python基础必备技巧之列表List和元组Tuple

Python基础必备技巧之字典Dictionary

Pandas 预览数据

下载 NBA 的数据进行后续的操作。

import requests

proxies = {
    
    
	'http': 'http://localhost:19180', 
	'https': 'http://localhost:19180'
}

download_url = "https://raw.githubusercontent.com/fivethirtyeight/data/master/nba-elo/nbaallelo.csv"

response = requests.get(download_url, proxies=proxies, verify=False)
with open("nba_all_elo.csv", "wb") as f:
    f.write(response.content)
print("Download ready.")

查看的数据基本信息。

import pandas as pd
# 读取数据
nba = pd.read_csv("nba_all_elo.csv")

# 数据类型
type(nba) 
<class 'pandas.core.frame.DataFrame'>

# 行数
len(nba) 
126314

# 行、列数
nba.shape  
(126314, 23)

数据的预览。

# 查看前5行数据
nba.head()

在这里插入图片描述
会看到一列省略号 (…) 表示缺失的数据。屏幕足够宽的话不会显示这个。可以进行设置为滚动条显示。

pd.set_option("display.max.columns", 2)

# 显示最后5行数据
nba.tail()

在这里插入图片描述

Pandas 检查数据

显示数据类型

了解数据的第一步是发现它包含的不同数据类型。虽然可以将任何内容放入列表中,但列包含特定数据类型的值。当用 Pandas 和 Python 比较数据结构时,会发现 Pandas 更快!

显示所有列及其数据类型。

nba.info()

在这里插入图片描述
可以看到数据类型 int64、float64 和 object。Pandas 使用 NumPy 库来处理这些类型。

显示基础统计

显示所有数字列的一些基本描述性统计信息。

nba.describe()

在这里插入图片描述
使用 include 参数,可以查看其他数据类型。不会计算object列的平均值或标准差,只显示一些描述性统计信息。

import numpy as np
nba.describe(include=object)

在这里插入图片描述

探索数据集

探索性数据分析可以回答有关数据集的问题。

例如可以检查特定值在列中出现的频率。

nba["team_id"].value_counts()
BOS    5997
NYK    5769
LAL    5078
...
SDS      11

nba["fran_id"].value_counts()
Name: team_id, Length: 104, dtype: int64
Lakers          6024
Celtics         5997
Knicks          5769
...
Huskies           60
Name: fran_id, dtype: int64

数据中发现 Lakers 总共有6024场比赛,但是LAL(洛杉矶湖人)对应的只有5078场比赛,那么数据是不是有什么问题?

nba.loc[nba["fran_id"] == "Lakers", "team_id"].value_counts()

LAL    5078
MNL     946
Name: team_id, dtype: int64

经过探索后发现居然还有一支队伍叫 MNL(明尼阿波利斯湖人队) 。经过百度发现这俩队是一个队伍,是前后继承的关系。

date_game 的值转换为数据 datetime 类型。然后可以使用 min 和 max 聚合函数,找到明尼阿波利斯湖人队的第一场和最后一场比赛信息数据。

nba["date_played"] = pd.to_datetime(nba["date_game"])
nba.loc[nba["team_id"] == "MNL", "date_played"].min()
Timestamp('1948-11-04 00:00:00')
nba.loc[nba['team_id'] == 'MNL', 'date_played'].max()
Timestamp('1960-03-26 00:00:00')
nba.loc[nba["team_id"] == "MNL", "date_played"].agg(("min", "max"))
min   1948-11-04
max   1960-03-26
Name: date_played, dtype: datetime64[ns]

这就解释了为什么可能不认识这支球队的原因,很多不是篮球迷都不知道。

Pandas 数据结构

Series 对象

Python 最基本的数据结构是list,Series根据列表创建一个新对象。

revenues = pd.Series([1, 2, 3])
revenues
0    1
1    2
2    3
dtype: int64

type(revenues.values)
<class 'numpy.ndarray'>

Series 操作同 List,区别在于可以设置显式索引值。

data = pd.Series(
    [1, 2, 3],
    index=["A", "B", "C"]
)
>>> data
A    1
B    2
C    3
dtype: int64

也可以通过字典的方式构建 Series 。

data = pd.Series({
    
    "A": 1, "B": 2})
data
A    1
B    2
dtype: int64

Series 也支持 .keys()in 关键字。

>>> data.keys()
Index(['A', 'B'], dtype='object')
>>> "A" in data 
True
>>> "C" in data 
False

DataFrame 对象

DataFrame 可以通过在构造函数中提供字典来将这些对象组合成一个。字典键将成为列名,值应包含Series对象。

A_ = pd.Series([1, 2, 3],index=["A", "B", "C"])
B_ = pd.Series({
    
    "A": 11, "B": 22})
data = pd.DataFrame({
    
    
	"A": A_,
	"B": B_
})

data
   A     B
A  1  11.0
B  2  22.0
C  3   NaN

新 DataFrame 索引是两个Series索引的并集。

data.index
Index(['A', 'B', 'C'], dtype='object')

DataFrame也将其值存储在 NumPy 数组中。

data.values
array([[1, 11.0],
       [2, 22.0],
       [3, nan]])

DataFrame 轴操作。

data.axes
[Index(['A', 'B', 'C'], dtype='object'), Index(['A', 'B'], dtype='object')]

data.axes[0]
Index(['A', 'B', 'C'], dtype='object')

data.axes[1]
Index(['A', 'B'], dtype='object')

DataFrame也是一个类字典的数据结构,也支持 .keys()in 关键字。

data.keys()
Index(['A', 'B'], dtype='object')

Series元素操作

使用索引运算符

支持关键字和索引数字操作。

A_
A    1
B    2
C    3
dtype: int64

A_['A']
1

A_[0]
1

支持 list 的切片操作。

A_[-1]
3

A_[1:]
B    2
C    3
dtype: int64

.loc和.iloc

处理标签索引是数字的情况。

colors = pd.Series(
    ["red", "purple", "blue", "green", "yellow"],
    index=[1, 2, 3, 5, 8]
)

colors
1       red
2    purple
3      blue
5     green
8    yellow
dtype: object
  • .loc 指标签索引。
  • .iloc 指位置索引。
colors.loc[1]
'red'

colors.iloc[1]
'purple'

.loc 指向图像右侧的标签索引。同时.iloc指向图片左侧的位置索引。
在这里插入图片描述
.iloc 返回具有隐式索引的元素。

colors.iloc[1:3]
2    purple
3      blue
dtype: object

.loc 返回显式索引在 3 到 8 之间的元素。

colors.loc[3:8]
3      blue
5     green
8    yellow
dtype: object

.iloc 支持负位置索引传递。

colors.iloc[-2]
'green'

DataFrame 元素访问

使用索引运算符

将 DataFrame 视为其 Series 值为的字典。

import pandas as pd

A_ = pd.Series([1, 2, 3],index=["A", "B", "C"])
B_ = pd.Series({
    
    "A": 11, "B": 22})
data = pd.DataFrame({
    
    
	"A": A_,
	"B": B_
})

data["A"]
A    1
B    2
C    3
Name: A, dtype: int64


type(data["A"])
<class 'pandas.core.series.Series'>

也支持 . 符号访问。

data["A"]
A    1
B    2
C    3
Name: A, dtype: int64

有可能出现函数方法和列名重复的情况。

toys = pd.DataFrame([
    {
    
    "name": "ball", "shape": "sphere"},
    {
    
    "name": "Rubik's cube", "shape": "cube"}
])

toys["shape"]
0    sphere
1      cube
Name: shape, dtype: object

toys.shape
(2, 2)

.loc和.iloc

DataFrame 也提供 .loc 和 .iloc 数据访问方法。

data.loc["A"]
A     1.0
B    11.0
Name: A, dtype: float64

data.loc["A": "B"]
	A	B
A	1	11.0
B	2	22.0

data.iloc[1]
A     2.0
B    22.0
Name: B, dtype: float64

查询数据集

可以根据索引访问庞大数据集的子集,意味着可以根据索引来查询数据。

筛选2010年以后的数据信息。

current_decade = nba[nba["year_id"] > 2010]
current_decade.shape

可以选择特定字段不为空的行。

games_with_notes = nba[nba["notes"].notnull()]
games_with_notes.shape
(5424, 24)

针对字符传数据可以使用字符串内置函数进行处理。

ers = nba[nba["fran_id"].str.endswith("ers")]
ers.shape
(27797, 24)

多条件搜索使用 & 符号。

nba[
    (nba["_iscopy"] == 0) &
    (nba["pts"] > 100) &
    (nba["opp_pts"] > 100) &
    (nba["team_id"] == "BLB")
]

在这里插入图片描述

分组和聚合数据

Pandas 库提供了分组和聚合函数进行各种数据的统计操作。

Series 有 20 多种不同的方法来计算描述性统计量。

A_.sum()
6

A_.min()
1

DataFrame 可以有多个列可以进行聚合分组操作。

根据 fran_id 聚合,求和 pts 列数据。

nba.groupby("fran_id", sort=False)["pts"].sum()
fran_id
Huskies           3995
Knicks          582497
Stags            20398
Falcons           3797
Capitols         22387
...

列操作

创建原 df 的副本DataFrame 使用。

df = nba.copy()
df.shape
(126314, 24)

根据现有列定义新列,并且可以进行相同的列操作。

df["difference"] = df.pts - df.opp_pts
df.shape
(126314, 25)

df["difference"].max()
68

列名可以重新自定义。

renamed_df = df.rename(
    columns={
    
    "game_result": "result", "game_location": "location"}
)

也可以删除不需要的行或者列。

df.shape
(126314, 25)
elo_columns = ["elo_i", "elo_n", "opp_elo_i", "opp_elo_n"]
# 这里需要指定 axis = 1 为列,axis = 0 为行
df.drop(elo_columns, inplace=True, axis=1)
df.shape
(126314, 21)

数据类型重新定义

这里重新定义的数据类型是根据列全部重新定义。

df.info()

在这里插入图片描述
重新定义时间列函数,转化成日期格式。

df["date_game"] = pd.to_datetime(df["date_game"])

重新定义object数据类型。

df["game_location"] = pd.Categorical(df["game_location"])
df["game_location"].dtype
CategoricalDtype(categories=['A', 'H', 'N'], ordered=False)

也可以直接赋值操作。

df["game_id"] = df["game_id"].astype('object')

清理数据

缺失值

观察notes列包含 5424 个缺失值。

nba.info()

在这里插入图片描述

处理包含缺失值的记录的最简单方法是忽略或者删除。

rows_without_missing_data = nba.dropna()
rows_without_missing_data.shape
(5424, 24)

缺失值也可以进行填充。

data_with_default_notes = nba.copy()
data_with_default_notes["notes"].fillna(
    value="no notes at all",
    inplace=True
)

无效值

无效值可能比缺失值更难处理,也会为后续的数据分析操作造成各种不可未知的麻烦。

这个需要根据自己对业务的理解剔除相关不合理的或者异常的数据。

不一致的值

可以定义一些互斥的查询条件,并验证这些条件不会同时出现。

判断比赛得分和比赛结果的例子。

nba[(nba["pts"] > nba["opp_pts"]) & (nba["game_result"] != 'W')].empty
True
nba[(nba["pts"] < nba["opp_pts"]) & (nba["game_result"] != 'L')].empty
True

幸运的是这两个查询都返回一个空的DataFrame证明不存在不一致的数据。

数据集的拼接

使用 .concat() 拼接2个DataFrame。

further_city_data = pd.DataFrame(
    {
    
    "revenue": [7000, 3400], "employee_count":[2, 2]},
    index=["New York", "Barcelona"]
)

city_data = pd.DataFrame({
    
    
    "revenue": pd.Series([4200, 8000, 6500],index=["Amsterdam", "Toronto", "Tokyo"]),
    "employee_count": pd.Series({
    
    "Amsterdam": 5, "Tokyo": 8})
})

all_city_data = pd.concat([city_data, further_city_data], sort=False)
all_city_data
           revenue	employee_count
Amsterdam	4200	5.0
Tokyo	    6500	8.0
Toronto	    8000	NaN
New York	7000	2.0
Barcelona	3400	2.0

还可以通过提供参数 axis=1 追加列。

city_countries = pd.DataFrame({
    
    
	"country": ["Holland", "Japan", "Holland", "Canada", "Spain"],
	"capital": [1, 1, 0, 0, 0]},
	index=["Amsterdam", "Tokyo", "Rotterdam", "Toronto", "Barcelona"]
)
cities = pd.concat([all_city_data, city_countries], axis=1, sort=False)
cities
           revenue  employee_count  country  capital
Amsterdam   4200.0             5.0  Holland      1.0
Tokyo       6500.0             8.0    Japan      1.0
Toronto     8000.0             NaN   Canada      0.0
New York    7000.0             2.0      NaN      NaN
Barcelona   3400.0             2.0    Spain      0.0
Rotterdam      NaN             NaN  Holland      0.0

使用 join 参数设置进行拼接。

pd.concat([all_city_data, city_countries], axis=1, join="inner")
           revenue  employee_count  country  capital
Amsterdam     4200             5.0  Holland        1
Tokyo         6500             8.0    Japan        1
Toronto       8000             NaN   Canada        0
Barcelona     3400             2.0    Spain        0

使用 merge() 参数设置进行拼接。

countries = pd.DataFrame({
    
    
	"population_millions": [17, 127, 37],
	"continent": ["Europe", "Asia", "North America"]
}, index= ["Holland", "Japan", "Canada"])

pd.merge(cities, countries, left_on="country", right_index=True)

           revenue	employee_count	country	capital	population_millions	continent
Amsterdam	4200.0	5.0	Holland	1.0	17	Europe
Rotterdam	NaN	NaN	Holland	0.0	17	Europe
Tokyo	    6500.0	8.0	Japan	1.0	127	Asia
Toronto	    8000.0	NaN	Canada	0.0	37	North America

DataFrame 可视化

Series 和 DataFrame对象都有一个 .plot() 方法绘制可视化图。

绘制某只队伍全部赛季的比赛得分的趋势图。

nba[nba["fran_id"] == "Knicks"].groupby("year_id")["pts"].sum().plot()

在这里插入图片描述
绘制比赛次数最多的队伍的柱状图,取前 N 个队伍。

nba["fran_id"].value_counts().head(10).plot(kind="bar")

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_20288327/article/details/124076687