DataFrame: 二维数据,类似Excel或数据库表。
Series: 一维数据,既可以是一列,也可以是一行。处理方式类似于dict。
注意,创建时需要数据值(value)及其索引 index
(类似key)。
pd.Series([1, "a", 5.2, 7], index=["a", "b", "c", "d"])
## 2. 直接使用dict创建
pd.Series({"a": 1, "b": 2})
series["a"] = "new"
series[["a", "b"]] ## 查询多个值
Dataframe是一个表格型的数据结构
Series
组成的字典创建 Datarame
最常用的方法,包括读取纯文本文件、excel、mysql数据库等。
基本使用:
使用多个字典序列创建DataFrame
data = {
"state": ["a", "b", "c", "d"],
"year": [2001, 2002, 2003, 2004],
"pop": [1.6, 3.2, 7.9, 2.1]
}
df = pd.DataFrame(data)
查询数据类型
df.dtypes
查询列索引、行索引
df.columns
df.index
pd.Series
pd.DataFrame
查询列
df["a"]
df[["a", "b"]]
查询行
df.loc[1]
df.loc[1:3] ## 通过切片的方式获取多行。注意:不同于list切片,loc[1:3]包含末尾元素`3`
需要认识到,pandas的索引方式,是有限索引行,然后再列。你无法做到loc某一列。如果非要,可以考虑直接提取Series,然后进行操作。
DataFrame.at
Access a single value for a row/column label pair.
DataFrame.iat
Access a single value for a row/column pair by integer position.
DataFrame.loc
Access a group of rows and columns by label(s).
DataFrame.iloc
Access a group of rows and columns by integer position(s).
>>> df = pd.DataFrame([[1, 2], [4, 5], [7, 8]],
... index=[‘cobra‘, ‘viper‘, ‘sidewinder‘],
... columns=[‘max_speed‘, ‘shield‘])
>>> df
max_speed shield
cobra 1 2
viper 4 5
sidewinder 7 8
## 3. 选取元素
>>> df.loc[‘cobra‘, ‘shield‘]
2
## 4. 选取行返回一个series
>>> df.loc[‘viper‘]
max_speed 4
shield 5
Name: viper, dtype: int64
## 5. 选取行列返回DataFrame
>>> df.loc[[‘viper‘, ‘sidewinder‘]]
max_speed shield
viper 4 5
sidewinder 7 8
With a callable, useful in method chains. The x passed to the lambda is the DataFrame being sliced. This selects the rows whose index label even.
>>> df.iloc[lambda x: x.index % 2 == 0]
a b c d
0 1 2 3 4
2 1000 2000 3000 4000
With a boolean array whose length matches the columns.
>>> df.iloc[:, [True, False, True, False]]
a c
0 1 3
1 100 300
2 1000 3000
new_df = pd.concat([df, pd.DataFrame(columns=["h_low", "h_high", "s_low", "s_high", "v_low", "v_high"])])
new_df.h_low[idx] = 123 ## 数据赋值
DataFrame.drop(labels=None,axis=0,index=None,columns=None, inplace=False)
参数说明:
因此,删除行列有两种方式:
## 6. df=pd.read_excel(‘data_1.xlsx‘)
df=df.drop([‘学号‘,‘语文‘], axis=1)
df=df.drop([1,2], axis=0)
df2.to_csv("triage_new.csv")
常用函数如下
用于演示的数据如下:
In [15]: data
Out[15]:
company salary age
0 NaN 43 21
1 A 8 41
2 A 28 26
3 C 42 28
4 A 33 26
5 C 20 18
6 A 48 43
7 B 25 23
8 B 39 18
DataFrame.head(), Series.head()
返回DataFrame的前N行。当数据量较大时,使用 .head()
可以快速对数据有个大致了解。
DataFrame.info(), Series.info()
打印所用数据的一些基本信息,包括索引和列的数据类型和占用的内存大小。
data.info()
<class ‘pandas.core.frame.DataFrame‘>
RangeIndex: 9 entries, 0 to 8
Data columns (total 3 columns):
company 8 non-null object
salary 9 non-null int32
age 9 non-null int32
dtypes: int32(2), object(1)
memory usage: 224.0+ bytes
DataFrame.describe(), Series.describe()
主要用途:生成描述性统计汇总,包括数据的计数和百分位数,有助于了解大致的数据分布。
## 默认生成数值列的描述性统计
## 使用 include = ‘all‘生成所有列
In [18]: data.describe()
Out[18]:
salary age
count 9.000000 9.000000
mean 31.777778 27.111111
std 12.804079 9.143911
min 8.000000 18.000000
25% 25.000000 21.000000
50% 33.000000 26.000000
75% 42.000000 28.000000
max 48.000000 43.000000
Series.value_counts()
统计分类变量中每个类的数量,比如company中各个公司都有多少人
主要参数:
In [19]: data[‘company‘].value_counts()
Out[19]:
A 4
B 2
C 2
Name: company, dtype: int64
返回占比情况
In [20]: data[‘company‘].value_counts(normalize=True)
Out[20]:
A 0.50
B 0.25
C 0.25
Name: company, dtype: float64
升序排列
In [21]: data[‘company‘].value_counts(ascending=True)
Out[21]:
C 2
B 2
A 4
Name: company, dtype: int64
DataFrame.sort_index(), Series.sort_index()
对数据按照索引进行排序
主要参数:
## 按索引降序排列
In [27]: data.sort_index(ascending=False)
Out[27]:
company salary age
8 B 39 18
7 B 25 23
6 A 48 43
5 C 20 18
4 A 33 26
3 C 42 28
2 A 28 26
1 A 8 41
0 NaN 43 21
DataFrame.sort_values(), Series.sort_values()
对DataFrame而言,按照某列进行排序(用by参数控制),对Series按数据列进行排序。
主要参数:
In [28]: data.sort_values(by=‘salary‘)
Out[28]:
company salary age
1 A 8 41
5 C 20 18
7 B 25 23
2 A 28 26
4 A 33 26
8 B 39 18
3 C 42 28
0 NaN 43 21
6 A 48 43
数据清洗
判断数据是否为缺失值,是的话返回True,否的话返回False
In [22]: data.isna()
Out[22]:
company salary age
0 True False False
1 False False False
2 False False False
3 False False False
4 False False False
5 False False False
6 False False False
7 False False False
8 False False False
大多数情况下数据量较大,不可能直接isna()后一个一个看是否是缺失值。any()和isna()结合使用可以判断某一列是否有缺失值。
In [23]: data.isna().any()
Out[23]:
company True
salary False
age False
dtype: bool
删掉含有缺失值的数据。
In [24]: data.dropna()
Out[24]:
company salary age
1 A 8 41
2 A 28 26
3 C 42 28
4 A 33 26
5 C 20 18
6 A 48 43
7 B 25 23
8 B 39 18
填充缺失数据
主要参数:
In [26]: data.fillna(‘B‘)
Out[26]:
company salary age
0 B 43 21
1 A 8 41
2 A 28 26
3 C 42 28
4 A 33 26
5 C 20 18
6 A 48 43
7 B 25 23
8 B 39 18
用缺失值后面的值来填充(这里NaN后面是‘A‘)
In [25]: data.fillna(method=‘bfill‘)
Out[25]:
company salary age
0 A 43 21
1 A 8 41
2 A 28 26
3 C 42 28
4 A 33 26
5 C 20 18
6 A 48 43
7 B 25 23
8 B 39 18
Series.astype(), DataFrame.astype()
修改字段的数据类型,数据量大的情况下可用于减小数据占用的内存,多用于Series。
## 把age字段转为int类型
In [12]: data["age"] = data["age"].astype(int)
In [13]: data
Out[13]:
company gender salary age
0 B female 30 40
1 A female 36 31
2 B female 35 28
3 B female 9 18
4 B female 16 43
5 A male 46 22
6 B female 15 28
7 B female 33 40
8 C male 19 32
DataFrame.rename(), Series.rename()
多用于修改DataFrame的列名
主要参数:
## 将‘age‘更改为员工编号‘number‘,并作用于原对象
In [15]: data.rename(columns={‘age‘:‘number‘},inplace=True)
In [16]: data
Out[16]:
company gender salary number
0 B female 30 40
1 A female 36 31
2 B female 35 28
3 B female 9 18
4 B female 16 43
5 A male 46 22
6 B female 15 28
7 B female 33 40
8 C male 19 32
DataFrame.set_index()
将DataFrame中的某一(多)个字段设置为索引
In [19]: data.set_index(‘number‘,inplace=True)
In [20]: data
Out[20]:
company gender salary
number
40 B female 30
31 A female 36
28 B female 35
18 B female 9
43 B female 16
22 A male 46
28 B female 15
40 B female 33
32 C male 19
Series.reset_index(), DataFrame.reset_index()
主要用途:重置索引,默认重置后的索引为0~len(df)-1
主要参数:
## drop = True,重置索引,并把原有的索引丢弃
In [22]: data.reset_index(drop=True)
Out[22]:
company gender salary
0 B female 30
1 A female 36
2 B female 35
3 B female 9
4 B female 16
5 A male 46
6 B female 15
7 B female 33
8 C male 19
## drop = False,重置索引
## 原索引列‘number‘作为新字段进入DataFrame
In [23]: data.reset_index(drop=False,inplace=True)
In [24]: data
Out[24]:
number company gender salary
0 40 B female 30
1 31 A female 36
2 28 B female 35
3 18 B female 9
4 43 B female 16
5 22 A male 46
6 28 B female 15
7 40 B female 33
8 32 C male 19
DataFrame.drop_duplicates(), Series.drop_duplicates()
主要用途:去掉重复值,作用和SQL中的distinct类似
In [26]: data[‘company‘].drop_duplicates()
Out[26]:
0 B
1 A
8 C
Name: company, dtype: object
DataFrame.drop(), Series.drop()
主要用途:常用于删掉DataFrame中的某些字段
主要参数:
## 删掉‘gender‘列
In [27]: data.drop(columns = [‘gender‘])
Out[27]:
number company salary
0 40 B 30
1 31 A 36
2 28 B 35
3 18 B 9
4 43 B 16
5 22 A 46
6 28 B 15
7 40 B 33
8 32 C 19
DataFrame.isin(), Series.isin()
主要用途:常用于构建布尔索引,对DataFrame的数据进行条件筛选
## 筛选出A公司和C公司的员工记录
In [29]: data.loc[data[‘company‘].isin([‘A‘,‘C‘])]
Out[29]:
number company gender salary
1 31 A female 36
5 22 A male 46
8 32 C male 19
pd.cut()
主要用途:将连续变量离散化,比如将人的年龄划分为各个区间
主要参数:
## 把薪水分成5个区间
In [33]: pd.cut(data.salary,bins = 5)
Out[33]:
0 (23.8, 31.2]
1 (31.2, 38.6]
2 (31.2, 38.6]
3 (8.963, 16.4]
4 (8.963, 16.4]
5 (38.6, 46.0]
6 (8.963, 16.4]
7 (31.2, 38.6]
8 (16.4, 23.8]
Name: salary, dtype: category
Categories (5, interval[float64]): [(8.963, 16.4] < (16.4, 23.8] < (23.8, 31.2] < (31.2, 38.6] <(38.6, 46.0]]
## 自行指定间断点
In [32]: pd.cut(data.salary,bins = [0,10,20,30,40,50])
Out[32]:
0 (20, 30]
1 (30, 40]
2 (30, 40]
3 (0, 10]
4 (10, 20]
5 (40, 50]
6 (10, 20]
7 (30, 40]
8 (10, 20]
Name: salary, dtype: category
Categories (5, interval[int64]): [(0, 10] < (10, 20] < (20, 30] < (30, 40] < (40, 50]]
## 指定区间的标签
In [34]: pd.cut(data.salary,bins = [0,10,20,30,40,50],labels = [‘低‘,‘中下‘,‘中‘,‘中上‘,‘高‘])
Out[34]:
0 中
1 中上
2 中上
3 低
4 中下
5 高
6 中下
7 中上
8 中下
Name: salary, dtype: category
Categories (5, object): [低 < 中下 < 中 < 中上 < 高]
pd.qcut()
主要用途:将连续变量离散化,区别于pd.cut()用具体数值划分,pd.qcut()使用百分比进行区间划分
主要参数:
## 按照0-33.33%,33.33%-66.67%,66.67%-100%百分位进行划分
In [35]: pd.qcut(data.salary,q = 3)
Out[35]:
0 (18.0, 33.667]
1 (33.667, 46.0]
2 (33.667, 46.0]
3 (8.999, 18.0]
4 (8.999, 18.0]
5 (33.667, 46.0]
6 (8.999, 18.0]
7 (18.0, 33.667]
8 (18.0, 33.667]
Name: salary, dtype: category
Categories (3, interval[float64]): [(8.999, 18.0] < (18.0, 33.667] < (33.667, 46.0]]
DataFrame.where(), Series.where()
主要用途:将不符合条件的值替换掉成指定值,相当于执行了一个if-else
主要参数:
## 语句解析
## 若salary<=40,则保持原来的值不变
## 若salary大于40,则设置为40
In [38]: data[‘salary‘].where(data.salary<=40,40)
Out[38]:
0 30
1 36
2 35
3 9
4 16
5 40
6 15
7 33
8 19
Name: salary, dtype: int32
pd.concat()
主要用途:将多个Series或DataFrame拼起来(横拼或者竖拼都可以)
主要参数:
## 分别取data的前三条和后三条为data1和data2
In [41]: data1 = data.head(3)
In [42]: data1
Out[42]:
number company gender salary
0 40 B female 30
1 31 A female 36
2 28 B female 35
In [43]: data2 = data.tail(3)
In [44]: data2
Out[44]:
number company gender salary
6 28 B female 15
7 40 B female 33
8 32 C male 19
## 拼接数据
In [45]: pd.concat([data1,data2],ignore_index = False)
Out[45]:
number company gender salary
0 40 B female 30
1 31 A female 36
2 28 B female 35
6 28 B female 15
7 40 B female 33
8 32 C male 19
## 拼接数据并重置索引
In [46]: pd.concat([data1,data2],ignore_index=True)
Out[46]:
number company gender salary
0 40 B female 30
1 31 A female 36
2 28 B female 35
3 28 B female 15
4 40 B female 33
5 32 C male 19
DataFrame.pivot_table()
主要用途:对DataFrame进行数据透视,相当于Excel中的数据透视表
主要参数:
## 从公司和性别两个维度对薪水进行数据透视
## 看看这两个维度下的平均薪资水平
In [47]: data.pivot_table(values = ‘salary‘,index = ‘company‘,
columns = ‘gender‘,aggfunc=np.mean)
Out[47]:
gender female male
company
A 36.0 46.0
B 23.0 NaN
C NaN 19.0
Github: (数据科学学习手札69)详解pandas中的map、apply、applymap、groupby、agg
本文就将针对pandas中的map()、apply()、applymap()、groupby()、agg()等方法展开详细介绍,并结合实际例子帮助大家更好地理解它们的使用技巧。
首先读入数据,这里使用到的全美婴儿姓名数据,包含了1880-2018年全美每年对应每个姓名的新生儿数据,在jupyterlab中读入数据并打印数据集的一些基本信息以了解我们的数据集:
import pandas as pd
## 9. 读入数据
data = pd.read_csv(‘data.csv‘)
data.head()
查看各列数据类型、数据框行列数
print(data.dtypes)
print()
print(data.shape)
这里的非聚合指的是数据处理前后没有进行分组操作,数据列的长度没有发生改变,因此本章节中不涉及groupby()。
map()
字典映射
## 定义F->女性,M->男性的映射字典
gender2xb = {‘F‘: ‘女性‘, ‘M‘: ‘男性‘}
## 利用map()方法得到对应gender列的映射列
data.gender.map(gender2xb)
映射函数
## 因为已经知道数据gender列性别中只有F和M所以编写如下lambda函数
data.gender.map(lambda x:‘女性‘ if x is ‘F‘ else ‘男性‘)
特殊对象
## 一些接收单个输入值且有输出的对象也可以用map()方法来处理
data.gender.map("This kid‘s gender is {}".format)
map()还有一个参数na_action,类似R中的na.action,取值为None或ingore,用于控制遇到缺失值的处理方式,设置为ingore时串行运算过程中将忽略Nan值原样返回。
apply()
apply()堪称pandas中最好用的方法,其使用方式跟map()很像,主要传入的主要参数都是接受输入返回输出。
但相较于map()针对单列Series进行处理,一条apply()语句可以对单列或多列进行运算,覆盖非常多的使用场景。
data.gender.apply(lambda x:‘女性‘ if x is ‘F‘ else ‘男性‘)
## 可以看到这里实现了跟map()一样的功能
apply()最特别的地方在于其可以同时处理多列数据,我们先来了解一下如何处理多列数据输入单列数据输出的情况。
譬如这里我们编写一个使用到多列数据的函数用于拼成对于每一行描述性的话,并在apply()用lambda函数传递多个值进编写好的函数中(当调用DataFrame.apply()时,apply()在串行过程中实际处理的是每一行数据,而不是Series.apply()那样每次处理单个值)。
def generate_descriptive_statement(year, name, gender, count):
year, count = str(year), str(count)
gender = ‘女性‘ if gender is ‘F‘ else ‘男性‘
return f‘在{year}年,叫做{name}性别为{gender}的新生儿有{count}个。‘
## 注意在处理多个值时要给apply()添加参数axis=1
data.apply(lambda row:generate_descriptive_statement(row[‘year‘],
row[‘name‘],
row[‘gender‘],
row[‘count‘]),
axis = 1)
输出多列数据:有些时候我们利用apply()会遇到希望同时输出多列数据的情况,在apply()中同时输出多列时实际上返回的是一个Series,这个Series中每个元素是与apply()中传入函数的返回值顺序对应的元组。
比如下面我们利用apply()来提取name列中的首字母和剩余部分字母:
data.apply(lambda row: (row[‘name‘][0], row[‘name‘][1:]), axis=1)
可以看到,这里返回的是单列结果,每个元素是返回值组成的元组,这时若想直接得到各列分开的结果,需要用到zip(*zipped)来解开元组序列,从而得到分离的多列返回值:
a, b = zip(*data.apply(lambda row: (row[‘name‘][0], row[‘name‘][1:]), axis=1))
print(a[:10])
print(b[:10])
applymap()
applymap()是与map()方法相对应的专属于DataFrame对象的方法,类似map()方法传入函数、字典等,传入对应的输出结果。
不同的是applymap()将传入的函数等作用于整个数据框中每一个位置的元素,因此其返回结果的形状与原数据框一致。
譬如下面的简单示例,我们把婴儿姓名数据中所有的字符型数据消息小写化处理,对其他类型则原样返回:
def lower_all_string(x):
if isinstance(x, str):
return x.lower()
else:
return x
data.applymap(lower_all_string)
有些时候我们需要像SQL里的聚合操作那样将原始数据按照某个或某些离散型的列进行分组再求和、平均数等聚合之后的值,在pandas中分组运算是一件非常优雅的事。
要进行分组运算第一步当然就是分组,在pandas中对数据框进行分组使用到groupby()方法。
其主要使用到的参数为by,这个参数用于传入分组依据的变量名称,当变量为1个时传入名称字符串即可。
当为多个时传入这些变量名称列表,DataFrame对象通过groupby()之后返回一个生成器,需要将其列表化才能得到需要的分组后的子集,如下面的示例:
## 10. 按照年份和性别对婴儿姓名数据进行分组
groups = data.groupby(by=[‘year‘,‘gender‘])
## 11. 查看groups类型
type(groups)
可以看到它此时是生成器,下面我们用列表解析的方式提取出所有分组后的结果:
## 12. 利用列表解析提取分组结果
groups = [group for group in groups]
查看其中的一个元素,可以看到每一个结果都是一个二元组,元组的第一个元素是对应这个分组结果的分组组合方式,第二个元素是分组出的子集数据框,而对于DataFrame.groupby()得到的结果。
譬如这里我们提取count列后直接调用max()方法:
## 13. 求每个分组中最高频次
data.groupby(by=[‘year‘,‘gender‘])[‘count‘].max()
注意这里的year、gender列是以索引的形式存在的,想要把它们还原回数据框,使用reset_index(drop=False)即可:
data.groupby(by=[‘year‘,‘gender‘])[‘count‘].max().reset_index(drop=False)
分组后的结果也可以直接调用apply(),这样可以编写更加自由的函数来完成需求,譬如下面我们通过自编函数来求得每年每种性别出现频次最高的名字及对应频次。
要注意的是,这里的apply传入的对象是每个分组之后的子数据框,所以下面的自编函数中直接接收的df参数即为每个分组的子数据框:
import numpy as np
def find_most_name(df):
return str(np.max(df[‘count‘]))+‘-‘+df[‘name‘][np.argmax(df[‘count‘])]
data.groupby([‘year‘,‘gender‘]).apply(find_most_name).reset_index(drop=False)
agg即aggregate,聚合,在pandas中可以利用agg()对Series、DataFrame以及groupby()后的结果进行聚合。
其传入的参数为字典,键为变量名,值为对应的聚合函数字符串,譬如 {‘v1‘:[‘sum‘,‘mean‘], ‘v2‘:[‘median‘,‘max‘,‘min]}
就代表对数据框中的v1列进行求和、均值操作,对v2列进行中位数、最大值、最小值操作。
下面用几个简单的例子演示其具体使用方式:
在对Series进行聚合时,因为只有1列,所以可以不使用字典的形式传递参数,直接传入函数名列表即可:
## 14. 求count列的最小值、最大值以及中位数
data[‘count‘].agg([‘min‘,‘max‘,‘median‘])
对数据框进行聚合时因为有多列,所以要使用字典的方式传入聚合方案:
data.agg({‘year‘: [‘max‘,‘min‘], ‘count‘: [‘mean‘,‘std‘]})
值得注意的是,因为上例中对于不同变量的聚合方案不统一,所以会出现NaN的情况。
data.groupby([‘year‘,‘gender‘]).agg({‘count‘:[‘min‘,‘max‘,‘median‘]}).reset_index(drop=False)
可以注意到虽然我们使用reset_index()将索引列还原回变量,但聚合结果的列名变成红色框中奇怪的样子,而在pandas 0.25.0以及之后的版本中,可以使用pd.NamedAgg()来为聚合后的每一列赋予新的名字:
data.groupby([‘year‘,‘gender‘]).agg(
min_count=pd.NamedAgg(column=‘count‘, aggfunc=‘min‘),
max_count=pd.NamedAgg(column=‘count‘, aggfunc=‘max‘),
median=pd.NamedAgg(column=‘count‘, aggfunc=‘median‘)).reset_index(drop=False)
df.groupby("A").sum()
df.groupby(["A", "B"]).mean()
df.groupby(["A", "B"], as_index=False).mean()
df.groupby("A").agg([np.sum, np.mean, np.std])
df.groupby("A")["C"].agg([np.sum, np.mean, np.std])
df.groupby("A").agg([np.sum, np.mean, np.std])["C"] ## 同上
df.groupby("A").agg({"C": np.sum, "D": np.maen})
def normalize(df):
min_value = df["Rating"].min()
max_value = df["Rating"].max()
df["Rating_norm"] = df["Roting"].apply(
lambda x: (x-min_value)/(max_value-min_value))
return df
def top_2(df, n=2):
return df.sort_values(by="Rating")[[]]
df.groupby("manth").apply(get_)
原文:https://www.cnblogs.com/brt2/p/13466166.html