【Python】DS的基础学习笔记11:Pandas库

Pandas库

引子

Numpy 在向量化的数值计算中表现优异
但是在处理更灵活、复杂的数据任务:
如为数据添加标签、处理缺失值、分组和透视表等方面
Numpy显得力不从心
而基于Numpy构建的Pandas库,提供了使得数据分析变得更快更简单的高级数据结构和操作工具

11.1 对象创建

11.1.1 Pandas Series 对象

Series 是带标签数据的一维数组

Series 对象的创建

通用结构: pd.Series(data, index=index, dtype=dtype)
data:数据,可以是列表、字典或Numpy数组
index:索引,为可选参数
dtype:数据类型,为可选参数

1 用列表创建
  • index缺省,默认为整数序列
import pandas as pd


data = pd.Series([1.5, 3, 4.5, 6])
print(data)

0 1.5
1 3.0
2 4.5
3 6.0
dtype: float64

  • 增加index
data = pd.Series([1.5, 3, 4.5, 6], index=["a", "b", "c", "d"])
print(data)

a 1.5
b 3.0
c 4.5
d 6.0
dtype: float64

  • 增加数据类型
    缺省则从传入数据自动判断
data = pd.Series([1, 2, 3, 4], index=["a", "b", "c", "d"], dtype=float)
print(data)

a 1.0
b 2.0
c 3.0
d 4.0
dtype: float64

注意:数据支持多种数据类型

data = pd.Series([1, 2, "3", 4], index=["a", "b", "c", "d"])
print(data)

a 1
b 2
c 3
d 4
dtype: object

print(data["a"])
print(data["c"])

1
3

数据类型可被强制改变

data = pd.Series([1, 2, "3", 4], index=["a", "b", "c", "d"], dtype=float)
print(data)

a 1.0
b 2.0
c 3.0
d 4.0
dtype: float64

print(data["c"])

3.0

如果不可强制转换,则会报错

data = pd.Series([1, 2, "a", 4], index=["a", "b", "c", "d"], dtype=float)
print(data)

强制转换报错

2 用一维Numpy数组创建
import pandas as pd
import numpy as np

x = np.arange(5)
y = pd.Series(x)
print(y)

0 0
1 1
2 2
3 3
4 4
dtype: int32

3 用字典创建
  • 默认以键为index,值为data
population_dict = {"BeiJing": 2154,
                   "ShangHai": 2424,
                   "ShenZhen": 1303,
                   "HangZhou": 981 }
population = pd.Series(population_dict)
print(population)

BeiJing 2154
ShangHai 2424
ShenZhen 1303
HangZhou 981
dtype: int64

  • 字典创建,如果指定index,则会到字典中的键中筛选,找不到的,值设为NaN
population = pd.Series(population_dict, index=["BeiJing", "HangZhou", "c", "d"])
print(population)

BeiJing 2154.0
HangZhou 981.0
c NaN
d NaN
dtype: float64

4 data为标量的情况
print(pd.Series(5, index=[100, 200, 300]))

100 5
200 5
300 5
dtype: int64

11.1.2 Pandas DataFrame对象

DataFrame 是带标签数据的多维数组

DataFrame对象的创建

通用结构:pd.DataFrame(data, index=index, columns=columns)
data:数据,可以是列表,字典或Numpy数组
index:索引,为可选参数
columns:列标签,为可选参数

1 通过Series对象创建
population_dict = {"BeiJing": 2154,
                   "ShangHai": 2424,
                   "ShenZhen": 1303,
                   "HangZhou": 981}
population = pd.Series(population_dict)
print(pd.DataFrame(population))

运行结果

print(pd.DataFrame(population, columns=["population"]))

运行结果

2 通过Series对象字典创建
population_dict = {"BeiJing": 2154,
                   "ShangHai": 2424,
                   "ShenZhen": 1303,
                   "HangZhou": 981}
population = pd.Series(population_dict)
GDP_dict = {"BeiJing": 30320,
            "ShangHai": 32680,
            "ShenZhen": 24222,
            "HangZhou": 13468}
GDP = pd.Series(GDP_dict)
print(pd.DataFrame({"population": population,
                    "GDP": GDP}))

运行结果
注意:数量不够的会自动补齐

print(pd.DataFrame({"population": population,
                    "GDP": GDP,
                    "Country": "China"}))

运行结果

3 通过字典列表对象创建
  • 字典索引作为index, 字典键作为columns
data = [{"a": i, "b": 2*i} for i in range(3)]
print(data)
print(pd.DataFrame(data))

运行结果

  • 不存在的键,会默认值为NaN
data = [{"a": 1, "b": 1}, {"b":3, "c": 4}]
print(pd.DataFrame(data))

运行结果

4 通过Numpy二维数组创建
print(pd.DataFrame(np.random.randint(10, size=(3, 2)), columns=["foo", "bar"], index=["a", "b", "c"]))

运行结果

11.2 DataFrame的性质

11.2.1 属性

data = pd.DataFrame({"population":population, "GDP": GDP})
print(data)

示例图
1. df.values 返回numpy数组表示的数据

print(data.values)

[[ 2154 30320]
[ 2424 32680]
[ 1303 24222]
[ 981 13468]]

2. df.index 返回行索引

print(data.index)

Index([‘BeiJing’, ‘ShangHai’, ‘ShenZhen’, ‘HangZhou’], dtype=‘object’)

3. df.columns 返回列索引

print(data.columns)

Index([‘population’, ‘GDP’], dtype=‘object’)

4. df.shape 形状

print(data.shape)

(4, 2)

5. pd.size 大小

print(data.size)

8

6. pd.dtypes 返回每列数据类型

print(data.dtypes)

population int64
GDP int64
dtype: object

11.2.2 索引

示例图
1. 获取列

  • 字典式
print(data["population"])

BeiJing 2154
ShangHai 2424
ShenZhen 1303
HangZhou 981
Name: population, dtype: int64

print(data[["GDP", "population"]])  # 多个列获取用列表形式

运行结果

  • 对象属性式
print(data.GDP)

BeiJing 30320
ShangHai 32680
ShenZhen 24222
HangZhou 13468
Name: GDP, dtype: int64

2. 获取行

  • 绝对索引 df.loc
print(data.loc["BeiJing"])

population 2154
GDP 30320
Name: BeiJing, dtype: int64

print(data.loc[["BeiJing", "HangZhou"]])

运行结果

  • 相对索引
print(data.iloc[0])

population 2154
GDP 30320
Name: BeiJing, dtype: int64

print(data.iloc[[1, 3]])

运行结果

3. 获取标量

print(data.loc["BeiJing", "GDP"])

30320

print(data.iloc[0, 1])

30320

print(data.values[0][1])

30320

4. Series对象的索引

print(type(data.GDP))

<class ‘pandas.core.series.Series’>

print(GDP["BeiJing"])

30320

11.2.3 切片

dates = pd.date_range(start='2019-01-01', periods=6)
print(dates)

DatetimeIndex([‘2019-01-01’, ‘2019-01-02’, ‘2019-01-03’, ‘2019-01-04’,
‘2019-01-05’, ‘2019-01-06’],
dtype=‘datetime64[ns]’, freq=‘D’)

df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=["A", "B", "C", "D"])
print(df)

运行结果
1. 行切片

print(df["2019-01-01": "2019-01-03"])
print(df.loc["2019-01-01": "2019-01-03"])
print(df.iloc[0:3])  # 不包含结束位置

运行结果

2. 列切片

print(df.loc[:, "A": "C"])
print(df.iloc[:, 0: 3])

运行结果
3. 多种多样的取值

  • 行、列同时切片
print(df.loc["2019-01-02": "2019-01-03", "C": "D"])  # 行列同时切片
print(df.iloc[1: 3, 2:])

运行结果

  • 行切片,列分散取值
print(df.loc["2019-01-04": "2019-01-06", ["A", "C"]])  # 行切片,列分散取值
print(df.iloc[3:, [0, 2]])

运行结果

  • 行分散取值,列切片
print(df.loc[["2019-01-04", "2019-01-06"], "C": "D"])  # 行分散取值,列切片
print(df.iloc[[3, 5], 2:])

运行结果

  • 行、列均分散取值
print(df.loc[["2019-01-04", "2019-01-06"], ["C", "D"]])  # 行、列均分散取值
print(df.iloc[[3, 5], [2, 3]])

运行结果

11.2.4 布尔索引

print(df)

运行结果

print(df > 0)

运行结果

print(df[df > 0])

运行结果

print(df.A > 0)

运行结果

print(df[df.A > 0])

运行结果

  • isin()方法
df2 = df.copy()
df2['E'] = ['one', 'one', 'two', 'three', 'four', 'three']
print(df2)

运行结果

ind = df2['E'].isin(["two", "four"])
print(ind)
print(df2[ind])

运行结果
运行结果

11.2.5 赋值

print(df)

运行结果

  • DataFrame 增加新列
s1 = pd.Series([1, 2, 3, 4, 5, 6], index=pd.date_range('20190101', periods=6))
print(s1)

2019-01-01 1
2019-01-02 2
2019-01-03 3
2019-01-04 4
2019-01-05 5
2019-01-06 6
Freq: D, dtype: int64

df['E'] = s1
print(df)

运行结果

  • 修改赋值
df.loc["2019-01-01", "A"] = 0
print(df)

运行结果

df.iloc[0, 1] = 0
print(df)

运行结果

df["D"] = np.array([5]*len(df))  # 可简化为df["D"] = 5
print(df)

运行结果

  • 修改index和columns
df.index = [i for i in range(len(df))]
df.columns = [i for i in range(df.shape[1])]
print(df)

运行结果

11.3 数值运算及统计分析

11.3.1 数据的查看

dates = pd.date_range(start='2019-01-01', periods=6)
df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=["A", "B", "C", "D"])
print(df)

运行结果
1. 查看前面的行

print(df.head())  # 默认5行

运行结果

print(df.head(2))

运行结果
2. 查看后面的行

print(df.tail())  # 默认5行

运行结果

print(df.tail(3))

运行结果
3. 查看总体信息
为了查看总体信息,我们先将其中一个元素改为NaN.

df.iloc[0, 3] = np.nan
print(df)

运行结果

print(df.info())

运行结果

11.3.2 Numpy通用函数同样适用于Pandas

1 向量化运算
x = pd.DataFrame(np.arange(4).reshape(1, 4))
print(x)

运行结果

print(x + 5)

运行结果

print(np.exp(x))

运行结果

y = pd.DataFrame(np.arange(4, 8).reshape(1, 4))
print(x * y)

运行结果

2 矩阵化运算
np.random.seed(42)
x = pd.DataFrame(np.random.randint(10, size=(10, 10)))
print(x)

运行结果

  • 转置
z = x.T
print(z)

运行结果

  • 矩阵乘法
np.random.seed(1)
y = pd.DataFrame(np.random.randint(10, size=(10, 10)))
print(x.dot(y))

运行结果
我们可以通过%timeit方法来比较下两种乘法所需时间

%timeit x.dot(y)
%timeit np.dot(x, y)

可以发现np.dot(x, y)所需时间更短

  • 执行相同运算,Numpy与Pandas的对比

一般来说,纯粹的计算在Numpy里执行更快
Numpy更侧重于计算,Pandas更侧重于数据分析

3 广播运算
np.random.seed(42)
x = pd.DataFrame(np.random.randint(10, size=(3, 3)), columns=list("ABC"))
print(x)

运行结果

  • 按行传播
print(x.iloc[0])

A 6
B 3
C 7
Name: 0, dtype: int32

print(x/x.iloc[0])

运行结果

  • 按列传播
print(x.div(x.A, axis=0))  # add sub div mul

运行结果
在这里axis设为1,表示按列传播,也可以显式写出axis=0表示按行传播。

11.3.3 新的用法

1 索引对齐
np.random.seed(42)
A = pd.DataFrame(np.random.randint(0, 20, size=(2, 2)), columns=list("AB"))
B = pd.DataFrame(np.random.randint(0, 10, size=(3, 3)), columns=list("ABC"))
print(A)
print(B)

运行结果

  • Pandas会自动对齐两个对象的索引,没有的值用np.nan表示
print(A+B)

运行结果

  • 缺省值可用fill-value来填充
print(A.add(B, fill_value=0))

运行结果

2 统计相关
  • 数据种类统计
y = np.random.randint(3, size=20)
print(y)

[2 0 2 2 0 0 2 1 2 2 2 2 0 2 1 0 1 1 1 1]

print(np.unique(y))

[0 1 2]

from collections import Counter
print(Counter(y))

Counter({2: 9, 1: 6, 0: 5})

y1 = pd.DataFrame(y, columns=["A"])
print(y1)

运行结果

print(np.unique(y1))

[0 1 2]

print(y1["A"].value_counts())

2 9
1 6
0 5
Name: A, dtype: int64

  • 产生新的结果,并进行排序
population_dict = {"BeiJing": 2154,
                   "ShangHai": 2424,
                   "ShenZhen": 1303,
                   "HangZhou": 981}
population = pd.Series(population_dict)
GDP_dict = {"BeiJing": 30320,
            "ShangHai": 32680,
            "ShenZhen": 24222,
            "HangZhou": 13468}
GDP = pd.Series(GDP_dict)
city_info = pd.DataFrame({"population": population, "GDP": GDP})
print(city_info)

运行结果

city_info["per_GDP"] = city_info["GDP"]/city_info["population"]
print(city_info)

运行结果
递增排序

print(city_info.sort_values(by="per_GDP"))

运行结果
递减排序

print(city_info.sort_values(by="per_GDP", ascending=False))

运行结果
按轴进行排序

data = pd.DataFrame(np.random.randint(20, size=(3, 4)), index=[2, 1, 0], columns=list("CBAD"))
print(data)

运行结果

行排序

print(data.sort_index())

运行结果
列排序

print(data.sort_index(axis=1))

运行结果

  • 统计方法
df = pd.DataFrame(np.random.normal(2, 4, size=(6, 4)), columns=list("ABCD"))
print(df)

运行结果
非空个数

df.count()

A 6
B 6
C 6
D 6
dtype: int64

求和(默认对列求和)

df.sum()

A 13.951465
B 5.381398
C 8.792280
D 5.701582
dtype: float64

df.sum(axis=1)  # 对行求和

0 18.116673
1 15.513429
2 4.575753
3 -7.834093
4 -4.075646
5 7.530610
dtype: float64

最大值 最小值

df.min()  # 默认各列最小值

A -2.051324
B -5.653121
C -4.899671
D -3.698993
dtype: float64

df.max(axis=1)  # 换轴后各行最大值 

0 8.092119
1 8.316851
2 4.170240
3 2.967849
4 3.256989
5 7.862595
dtype: float64

print(df.idxmax())  # 最大值坐标

A 5
B 2
C 1
D 0
dtype: int64

均值

df.mean()

A 2.325244
B 0.896900
C 1.465380
D 0.950264
dtype: float64

方差

df.var()

A 11.887325
B 11.911567
C 21.841270
D 22.569365
dtype: float64

标准差

df.std()

A 3.447800
B 3.451314
C 4.673464
D 4.750723
dtype: float64

中位数

df.median()

A 2.015618
B 1.271919
C 1.208221
D -0.056035
dtype: float64

众数

data = pd.DataFrame(np.random.randint(5, size=(10, 2)), columns=list("AB"))
print(data)

运行结果

data.mode()

运行结果
75%分位数

df.quantile(0.75)

A 3.732105
B 2.804478
C 4.010594
D 3.836574
Name: 0.75, dtype: float64

一网打尽

df.describe()

运行结果
字符类型也有describe

data_2 = pd.DataFrame([["a", "a", "c", "d"],
                       ["c", "a", "c", "b"],
                       ["a", "a", "d", "c"]], columns=list("ABCD"))
print(data_2)
print(data_2.describe())

运行结果
相关性系数和协方差

print(df.corr())

运行结果

print(df.corrwith(df["A"]))

运行结果
自定义输出
apply(method)的用法:使用method的方法默认对每一列进行相应的操作

df.apply(np.cumsum)

运行结果

print(df.apply(np.cumsum, axis=1))

运行结果

df.apply(sum)

A 13.951465
B 5.381398
C 8.792280
D 5.701582
dtype: float64

df.apply(lambda x: x.max()-x.min())

A 9.913920
B 9.823361
C 13.216523
D 11.791112
dtype: float64

def my_describe(x):
    return pd.Series([x.count(), x.mean(), x.max(), x.idxmin(), x.std()], \
                     index=["Count", "mean", "max", "idxmin", "std"])


print(df.apply(my_describe))

运行结果

11.4 缺失值处理

11.4.1 发现缺失值

import pandas as pd
import numpy as np

data = pd.DataFrame(np.array([[1, np.nan, 2],
                              [np.nan, 3, 4],
                              [5, 6, None]]), columns=["A", "B", "C"])
print(data)

运行结果
注意:有None、字符串等,数据类型全部变为object,它比int和float更消耗资源

data.dtypes

A object
B object
C object
dtype: object

data.isnull()

运行结果

data.notnull()

运行结果

11.4.2 删除缺失值

data = pd.DataFrame(np.array([[1, np.nan, 2, 3],
                              [np.nan, 4, 5, 6],
                              [7, 8, np.nan, 9],
                              [10, 11, 12, 13]]), columns=["A", "B", "C", "D"])
print(data)

运行结果
注意:np.nan是一种特殊的浮点数

data.dtypes

运行结果

1. 删除整行

data.dropna()

运行结果
2. 删除整列

data.dropna(axis="columns")

运行结果

data["D"] = np.nan
print(data)

运行结果

data.dropna(axis="columns", how="all")  # 所有元素均缺失时才删除,any指有缺失就删

运行结果

11.4.3 填充缺失值

data

data.fillna(value=5)

运行结果

  • 用均值进行替换
fill = data.mean()
print(data.fillna(value=fill))

运行结果
如果用全部平均值替代,可以先stack摊平后取平均值

fill = data.stack().mean()
print(data.fillna(value=fill))

运行结果

11.5 合并数据

  • 构造一个生产DataFrame的函数
def make_df(cols, ind):
    """一个简单的DataFrame"""
    data = {c: [str(c)+str(i) for i in ind] for c in cols}
    print(data)
    return pd.DataFrame(data, ind)


make_df("ABC", range(3))

运行结果

  • 垂直合并
    若行标签有重叠,会保留重叠行标签
df_1 = make_df("AB", [1, 2])
df_2 = make_df("AB", [3, 4])
print(df_1)
print(df_2)

运行结果

print(pd.concat([df_1, df_2]))

运行结果

  • 水平合并
    若列标签有重叠,则会保留重叠列标签
df_3 = make_df("AB", [0, 1])
df_4 = make_df("CD", [0, 1])
print(df_3)
print(df_4)

运行结果

print(pd.concat([df_3, df_4], axis=1))

水平拼接

  • 索引重叠
    当标签重叠时,我们有时希望标签重新排列,则需要添加参数ignore_index=True
df_5 = make_df("AB", [1, 2])
df_6 = make_df("AB", [1, 2])
print(df_5)
print(df_6)
print(pd.concat([df_5, df_6], ignore_index=True))

运行结果
列重叠同理,加上参数axis=1即可

  • 对齐合并merge()
    当存在对应相同的数值(共同列)时可以用merge()合并
df_9 = make_df("AB", [1, 2])
df_10 = make_df("BC", [1, 2])
print(df_9)
print(df_10)

运行结果
我们可以看到B列在df_9与df_10中对应相等,我们希望合并时B列不变

print(pd.merge(df_9, df_10))

运行结果
【例】合并城市信息

population_dict = {"city": ("BeiJing", "HangZhou", "ShenZhen"),
                   "pop": (2154, 981, 1303)}
population = pd.DataFrame(population_dict)
print(population)

运行结果

GDP_dict = {"city": ("BeiJing", "ShangHai", "HangZhou"),
            "GDP": (30320, 32680, 13468)}
GDP = pd.DataFrame(GDP_dict)
print(GDP)

运行结果

city_info = pd.merge(population, GDP)
print(city_info)

运行结果
若不想抛弃上海与深圳,则需要添加参数

city_info = pd.merge(population, GDP, how="outer")
print(city_info)

运行结果

11.6 分组和数据透视表

df = pd.DataFrame({"key": ["A", "B", "C", "C", "B", "A"],
                   "data1": range(6),
                   "data2": np.random.randint(0, 10, size=6)})
print(df)

运行结果

11.6.1 分组

  • 延迟计算(先存起来等待处理)
df.groupby("key")

<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001EDFF4444C0>

df.groupby("key").sum()

求和

df.groupby("key").mean()

求平均值
那么groupby到底是什么呢?

for i in df.groupby("key"):
    print(str(i))

groupby实质

  • 按列取值
df.groupby("key")["data2"].sum()

key
A 15
B 9
C 11
Name: data2, dtype: int32

  • 按组迭代
for data, group in df.groupby("key"):
    print("{0:5} shape={1}".format(data, group.shape))

运行结果

  • 调用方法
df.groupby("key")["data1"].describe()

运行结果

  • 支持更复杂的操作
df.groupby("key").aggregate(["min", "median", "max"])

运行结果

  • 过滤
np.random.seed(1)
df = pd.DataFrame({"key": ["A", "B", "C", "C", "B", "A"],
                   "data1": range(6),
                   "data2": np.random.randint(0, 10, size=6)})
print(df)


def filter_func(x):
    return x["data2"].std() > 3


print(df.groupby("key")["data2"].std())
print(df.groupby("key").filter(filter_func))

运行结果

  • 转换
df = pd.DataFrame({"key": ["A", "B", "C", "C", "B", "A"],
                   "data1": range(6),
                   "data2": np.random.randint(0, 10, size=6)})
print(df)
print(df.groupby("key").transform(lambda x: x - x.mean()))

转换

  • apply方法
def norm_by_data2(x):
    x["data1"] /= x["data2"].sum()
    return x

print(df.groupby("key").apply(norm_by_data2))

运行结果

  • 将列表、数组设为分组键
print(df)
L = [0, 1, 0, 1, 2, 0]
print(df.groupby(L).sum())

运行结果

  • 用字典将索引映射到分组
df2 = df.set_index("key")
print(df2)
mapping = {"A": "first", "B": "constant", "C": "constant"}
print(df2.groupby(mapping).sum())

运行结果

  • 任意Python函数
print(df2.groupby(str.lower).mean())

运行结果

  • 多个有效值组成的列表
print(df2.groupby([str.lower, mapping]).mean())

运行结果
【例1】行星观测数据处理

import seaborn as sns


planets = sns.load_dataset('planets')
print(planets.shape)  # 获取形状
print(planets.head())  # 查看前五行
print(planets.describe())  # 统计信息

运行结果
现在我们希望通过分组实现不同观测方法(method)下不同时代(decade,十年为单位)的观测数量。
首先,我们应该定义时代(decade)。

decade = 10 * (planets["year"]//10)
print(decade.head())
decade = decade.astype(str) + "s"
decade.name = "decade"
print(decade.head())

运行结果
定义好之后,我们对method,decade进行分组。

print(planets.groupby(["method", decade]).sum())

运行结果
实际上,我们只需要number这一列数据,所以我们可以把number单独提出来,然后利用unstack展开使其更美观,最后用fillna将缺失值填充为0即可。

print(planets.groupby(["method", decade])["number"].sum().unstack().fillna(0))

运行结果

11.6.2 数据透视表

【例2】泰坦尼克号乘客数据分析

import seaborn as sns


titanic = sns.load_dataset("titanic")
print(titanic.head())
print(titanic.describe())

运行结果
现在我们想得到不同性别的生存率。

print(titanic.groupby("sex")["survived"].mean())

sex
female 0.742038
male 0.188908
Name: survived, dtype: float64

索引"servived"用一个中括号的表示形式是Series,而两个中括号则是DataFrame.

print(titanic.groupby("sex")[["survived"]].mean())

运行结果
更具体地,我们想看到不同性别下不同舱的生存情况。

print(titanic.groupby(["sex", "class"])["survived"].aggregate("mean").unstack())

运行结果
我们发现单凭groupby写起来也比较复杂,可读性不佳,但Pandas里面提供了一种数据透视表的方法。我们一起看一下,如何用数据透视表实现相同功能。

print(titanic.pivot_table("survived", index="sex", columns="class"))

运行结果
我们可以发现直接用pivot_table方法默认返回数据平均值。
我们也可以添加其他参数,来得到不同的结果。
aggfunc来更改方法,margins来设置总览。

print(titanic.pivot_table("survived", index="sex", columns="class", aggfunc="mean", margins=True))

运行结果
当我们利用pivot_table来处理数据时,希望处理多类数据,可在aggfuc中分别选择对应方法。比如该例中我们不仅想得到生存个数,还需要票价均值。

print(titanic.pivot_table(index="sex", columns="class", aggfunc={"survived": "sum", "fare": "mean"}))

运行结果

11.7 其他

  1. 向量化字符串操作
  2. 处理时间序列
  3. 多级索引:用于多维数组
base_data = np.array([[1771, 11115],
                      [2154, 30320],
                      [2141, 13070],
                      [2424, 32680],
                      [1077, 7806],
                      [1303, 24222],
                      [798, 4789],
                      [981, 13486]])
data = pd.DataFrame(base_data, index=[
    ["BeiJing", "BeiJing", "ShangHai", "ShangHai", "ShenZhen", "ShenZhen", "HangZhou", "HangZhou"],
    [2008, 2018] * 4], columns=["population", "GDP"])
print(data)

多级索引
修改行索引名称

data.index.names = ["city", "year"]
print(data)

运行结果
列数据的取值

print(data["GDP"])

运行结果
取值某个城市GDP

print(data.loc["ShangHai", "GDP"])

运行结果
取值某个城市某年情况

print(data.loc["ShangHai", 2018])

运行结果

  1. 高性能的Pandas:eval()
df1, df2, df3, df4 = (pd.DataFrame(np.random.random((10000,100))) for i in range(4))
%timeit (df1+df2)/(df3+df4)

17.6 ms ± 120 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

  • 减少了复合代数式计算中间过程的内存分配,运行速度有所改善
%timeit pd.eval("(df1+df2)/(df3+df4)")

10.5 ms ± 153 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

可以比较下运算结果是相同的

np.allclose((df1+df2)/(df3+df4), pd.eval("(df1+df2)/(df3+df4)"))

True

  • 实现列间运算
df = pd.DataFrame(np.random.random((1000, 3)), columns=list("ABC"))
df.head()

运行结果

df["D"] = pd.eval("(df.A+df.B)/(df.C-1)")
df.head()

运行结果

  • 使用局部变量
column_mean = df.mean(axis=1)
res = df.eval("A+@column_mean")
res.head()

运行结果

  1. 高性能的Pandas:query()
df.head()

运行结果

%timeit df[(df.A < 0.5) & (df.B > 0.5)]

1.11 ms ± 9.38 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.query("(A < 0.5)&(B > 0.5)")

2.55 ms ± 199 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

时间反而变长了,究其原因,是因为数据量过小,导致调用该方法本身的时间成本过高

  1. eval()与query()使用时机
    小数组时,普通方法反而更快
    因此,在数据量较大的情况下,再调用eval与query来提升运行速度
df.values.nbytes

32000

df1.values.nbytes

8000000

以上,便是第十一节深入探索内容,Pandas是一个更侧重于数据分析的高级工具。
下一节将深入理解Matplotlib库。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值