pandas数据类型
pandas 基于两种数据类型,series 和 dataframe。
- series 是一种一维的数据类型,其中的每个元素都有各自的标签。标签可以是数字或者字符。
- dataframe 是一个二维的、表格型的数据结构。pandas 的 dataframe 可以储存许多不同类型的数据,类似于我们常用的excel。dataframe 可以看成一个series的字典{"key1":series1,"key2":series2}。
接入pandas
pandas是python的一个第三方库,使用前需要先进行安装:
pip3 install pandas
安装完成后我们来导入这个库:
import pandas as pd
接下来我们新建一个数据集,并对它进行操作。我们可以选择新建一个数据集,或者从本地文件中导入,这里我们选择后者,因为这更符合我平时的使用场景。pandas提供了丰富的api来读取各种文件:

这里我们新建一个Excel,读取并打印:
标题1 | 标题2 | 标题3 | 标题4 |
---|---|---|---|
1 | 11 | 111 | 1a |
2 | 22 | 222 | 2a |
3 | 33 | 333 | 3a |
4 | 44 | 444 | 4a |
5 | 55 | 555 | 5a |
df = pd.read_excel("C:/Users/Administrator/Desktop/新建 Microsoft Excel 工作表.xlsx")
print(df)
# 标题1 标题2 标题3 标题4
#0 1 11 111 1a
#1 2 22 222 2a
#2 3 33 333 3a
#3 4 44 444 4a
#4 5 55 555 5a
数据前面的0,1,2,3,4为行索引,从0开始。
获取数据基本信息
获取行数、列数
print(df.shape)
# (5, 4)
我们得到一个tuple,tuple[0]为行,tuple[1]为列。并且我们可以得到一个信息,它会默认第一个非空行为题头,数据的行数并没有计算标题行。
获取标题
print(df.columns.values.tolist())
# ['标题1', '标题2', '标题3', '标题4']
如果某列没有标题头,会得到Unnamed x。
获取数据数目
print(len(df))
# 5
这里的数据指的一行为一条数据,所以返回的实际就是行数。
数据的过滤
获取前几行或者后几行
print("前两行:\n")
print(df.head(2))
print("-----------")
print("后两行:\n")
print(df.tail(2))
#前两行:
# 标题1 标题2 标题3 标题4
#0 1 11 111 1a
#1 2 22 222 2a
#-----------
#后两行:
# 标题1 标题2 标题3 标题4
#3 4 44 444 4a
#4 5 55 555 5a
获取某列
print(df["标题1"])
#0 1
#1 2
#2 3
#3 4
#4 5
# 将 标题1 这列切割出来,注意会再原数据集中删除
# print(df.pop("标题1"))
注意前面的第一列01234为它的索引。
除了这种方式外,我们也可以使用小数点来调用:
print(df.标题1)
得到的结果是一样的,不过在程序里面用中文总觉得哪里怪怪的,我们可以自定义标题:
df.columns = ["title_1", "title_2", "title_3", "title_4"]
print(df.title_1)
获取符合条件的数据
比如我们需要获取第一列小于3的数据:
print(df[df.title_1 < 3])
# title_1 title_2 title_3 title_4
#0 1 11 111 1a
#1 2 22 222 2a
比如我们需要获取第一列小于3并且第二列小于20的数据:
print(df[(df.title_1 < 3) & (df.title_2 < 20)])
# title_1 title_2 title_3 title_4
#0 1 11 111 1a
注意不能使用and、or,必须用 &、| 和圆括号。
如果数据为字符串,我们也可以用字符串的方法来进行过滤,格式为.str.[string method]:
print(df[df.title_4.str.startswith("2")])
# title_1 title_2 title_3 title_4
#1 2 22 222 2a
print(df[df.title_4.str.endswith("a")])
# title_1 title_2 title_3 title_4
#0 1 11 111 1a
#1 2 22 222 2a
#2 3 33 333 3a
#3 4 44 444 4a
#4 5 55 555 5a
数据的索引
获取某条数据
比如我想获取第4行数据:
print(df.iloc[3])
#title_1 4
#title_2 44
#title_3 444
#title_4 4a
#Name: 3, dtype: object
注意索引是从0开始的。
比如我想获取第4列值为3a的那一条数据,我们可以先设置第四列为索引:
df = df.set_index(["title_4"])
print(df.loc["3a"])
#title_1 3
#title_2 33
#title_3 333
#Name: 3a, dtype: int64
此时我们打印一下数据集:
print(df)
# title_1 title_2 title_3
#title_4
#1a 1 11 111
#2a 2 22 222
#3a 3 33 333
#4a 4 44 444
#5a 5 55 555
刚好可以验证我们之前0,1,2,3,4是索引的说法。
如果我们使用完毕,可以用以下方法来将索引恢复成数据形式:
df = df.reset_index(["title_4"])
print(df)
# title_4 title_1 title_2 title_3
#0 1a 1 11 111
#1 2a 2 22 222
#2 3a 3 33 333
#3 4a 4 44 444
#4 5a 5 55 555
数据排序
我们将数据按降序排列:
df.sort_index(ascending=False, inplace=True)
print(df)
# title_4 title_1 title_2 title_3
#4 5a 5 55 555
#3 4a 4 44 444
#2 3a 3 33 333
#1 2a 2 22 222
#0 1a 1 11 111
ascending:True为升序,False为降序。 inplace:是否替换原数据,默认False。
注意它的索引一起跟着倒序了,这时候我们调用df.iloc[1]得到的依然是2a那行数据。
数据的修改
删除行、列
我们可以使用drop方法来删除行或者列:
# 删除title_1列
result_2 = df.drop(labels=["title_1"], axis=1, inplace=False)
print(result_2)
# title_4 title_2 title_3
#4 5a 55 555
#3 4a 44 444
#2 3a 33 333
#1 2a 22 222
#0 1a 11 111
# 删除前两列
result_2 = df.drop(labels=df.columns[[0, 1]], axis=1, inplace=False)
print(result_2)
# title_2 title_3
#4 55 555
#3 44 444
#2 33 333
#1 22 222
#0 11 111
# 删除前两行
result_2 = df.drop(labels=[0, 1], axis=0, inplace=False)
print(result_2)
# title_4 title_1 title_2 title_3
#4 5a 5 55 555
#3 4a 4 44 444
#2 3a 3 33 333
参数labels表示要删除的标签;axis为0表示行,1表示列,默认0;inplace表示是否要替换原数据集。
插入行、列
# 再最后添加一列
#df["title_5"] = ["1","2","3","4","5"]
# 插入到第一列
#data = ["1","2","3","4","5"]
#df2.insert(0,'title_5',data)
# 插入行,先切割两部分再拼接,可以使用append或者concat
#df_1.append(insertRow,ignore_index=True).append(df_2,ignore_index=True)
# 或者
#pd.concat([df_1,insertRow,df_2],ignore_index=True)
修改具体数据值
apply
当我们想让操作作用在一维的向量上时,可以使用apply。它可以作用于Series,也可以作用于DataFrame数据。
# 作用于某一列,Series数据。
df["title_5"] = df.title_4.apply(self.apply_data) # 新增一列
print(df)
def apply_data(self, data):
result = data[:1]
return result + "b"
# title_4 title_1 title_2 title_3 title_5
#4 5a 5 55 555 5b
#3 4a 4 44 444 4b
#2 3a 3 33 333 3b
#1 2a 2 22 222 2b
#0 1a 1 11 111 1b
# 作用于DataFrame 数据
result_2 = df.apply(self.apply_data_2) # 获取第二行数据
print(result_2)
def apply_data_2(self, data):
return data[1]
#title_4 2a
#title_1 2
#title_2 22
#title_3 222
#title_5 2b
#dtype: object
applymap
如果想让操作作用于DataFrame中的每一个元素,可以使用applymap():
df = df.applymap(self.applymap_data)
print(df)
def applymap_data(self, data):
return str(data) + "c"
# title_4 title_1 title_2 title_3 title_5
#4 5ac 5c 55c 555c 5bc
#3 4ac 4c 44c 444c 4bc
#2 3ac 3c 33c 333c 3bc
#1 2ac 2c 22c 222c 2bc
#0 1ac 1c 11c 111c 1bc
map
map()只能是将函数作用于一个Series的每一个元素:
print(df.title_1.map(self.apply_data))
#4 5b
#3 4b
#2 3b
#1 2b
#0 1b
#Name: title_1, dtype: object
总的来说就是apply()是一种让函数作用于列或者行操作,applymap()是一种让函数作用于DataFrame每一个元素的操作,而map是一种让函数作用于Series每一个元素的操作。
数据分组
为了方便演示我们先添加一列数据,然后通过groupby进行分组:
df["title_6"] = ["1", "0", "1", "0", "1"]
print(df.groupby(df.title_6).max()) # 获取每个分组里面最大的数据
# title_4 title_1 title_2 title_3 title_5 title_6
#title_6
#0 4ac 4c 44c 444c 4bc 0
#1 5ac 5c 55c 555c 5bc 1
print(df.groupby(df.title_6).max()["title_1"]) # 获取分组后的某列
print(df.groupby([df.title_6, df.title_5]).max())
#title_6
#0 4c
#1 5c
#Name: title_1, dtype: object
类似的还有min(),mean()等方法。
我们也可以根据多个列进行分组:
df = df.groupby([df.title_6, df.title_5]).max()
print(df)
# title_4 title_1 title_2 title_3 title_5 title_6
#title_6 title_5
#0 2bc 2ac 2c 22c 222c 2bc 0
# 4bc 4ac 4c 44c 444c 4bc 0
#1 1bc 1ac 1c 11c 111c 1bc 1
# 3bc 3ac 3c 33c 333c 3bc 1
# 5bc 5ac 5c 55c 555c 5bc 1
我们也可以通过unstack方法来改变分组后的显示形式:
print(df.unstack(0))
# title_4 title_1 title_2 ... title_3 title_5 title_6
#title_6 0 1 0 1 0 ... 1 0 1 0 1
#title_5 ...
#1bc NaN 1ac NaN 1c NaN ... 111c NaN 1bc NaN 1
#2bc 2ac NaN 2c NaN 22c ... NaN 2bc NaN 0 NaN
#3bc NaN 3ac NaN 3c NaN ... 333c NaN 3bc NaN 1
#4bc 4ac NaN 4c NaN 44c ... NaN 4bc NaN 0 NaN
#5bc NaN 5ac NaN 5c NaN ... 555c NaN 5bc NaN 1
#[5 rows x 12 columns]
print(df.unstack(1))
# title_4 ... title_6
#title_5 1bc 2bc 3bc 4bc 5bc ... 1bc 2bc 3bc 4bc 5bc
#title_6 ...
#0 NaN 2ac NaN 4ac NaN ... NaN 0 NaN 0 NaN
#1 1ac NaN 3ac NaN 5ac ... 1 NaN 1 NaN 1
#[2 rows x 30 columns]
传入的参数0、1表示将第几个索引置为横向。
其中很多的NaN表示空记录,比如第一条记录对应title_5 = 1bc & title_6 = 0,实际数据集中没有这样的数据,因此显示NaN,如果觉得看起来不直观,也可以使用fillna方法来替换调NaN的显示:
print(df.unstack(0).fillna(""))
# title_4 title_1 title_2 ... title_3 title_5 title_6
#title_6 0 1 0 1 0 ... 1 0 1 0 1
#title_5 ...
#1bc 1ac 1c ... 111c 1bc 1
#2bc 2ac 2c 22c ... 2bc 0
#3bc 3ac 3c ... 333c 3bc 1
#4bc 4ac 4c 44c ... 4bc 0
#5bc 5ac 5c ... 555c 5bc 1
#[5 rows x 12 columns]
fillna传入的参数表示你想要替换的显示值,这里传入空字符串,当然你也可以传入任意的字符串或者数字。
上面的一系列操作也可以用pivot方法来代替:
print(df)
# title_4 title_1 title_2 title_3 title_5 title_6
#4 5ac 5c 55c 555c 5bc 1
#3 4ac 4c 44c 444c 4bc 0
#2 3ac 3c 33c 333c 3bc 1
#1 2ac 2c 22c 222c 2bc 0
#0 1ac 1c 11c 111c 1bc 1
print(df.pivot(index="title_6", columns="title_5", values=["title_1", "title_2"]).fillna(""))
# title_1 title_2
#title_5 1bc 2bc 3bc 4bc 5bc 1bc 2bc 3bc 4bc 5bc
#title_6
#0 2c 4c 22c 44c
#1 1c 3c 5c 11c 33c 55c
参数index代表索引列,columns代表横向的那个分组,values表示要显示的值。上面的写法也可以写成:
# 获取所有数据再单独显示某几列
print(df.pivot("title_6", "title_5")[["title_1", "title_2"]].fillna(""))
数据合并
如果有两个相关联的数据集,比如两个数据集有相同的某列,可以用merge方法合并成一个数据集。
# 以title_1为根据将两个数据集合并
df.merge(df_other, on='title_1')
数据的保存
还是以Excel为例,我们将数据读取进来,进行一系列操作后,很多时候会希望保存下来,我们可以直接使用to_excel方法,注意需要安装openpyxl库:
df.to_excel("data_new.xlsx")

网友评论