提示:该篇文章为自学笔记,bilibili学习视频出处bv: BV1UJ411A7Fs
用于数据分析、数据处理和数据可视化。
数据类型 | 说明 | 读取方法 |
---|---|---|
csv、tsv、txt | 用逗号分隔、tab分割的纯文本文件 | pd.read_csv |
json | json格式 | pd.read_json |
excel | xls或者xlsx文件 | pd.read_excel |
数据库 | 关系型数据库表 | pd.read_sql |
使用pandas首先要导入包:
import pandas as pd
加载以逗号为分隔符的CSV(Comma-Separated Values)文件
语法: pd.read_csv(),参数如下:
infer
,会将文件第一行数据
作为列名,等同于header=0。0,1,2,3...
作为列名。CSV文件的第一行指定列的数据头
如果CSV文件第一行没有数据头,read_csv参数中需要指定: header=None
# 从csv文件中加载数据集
dataframe = pd.read_csv(filepath_or_buffer="dataset_demo.csv", header="infer")
# sheet_name用于指定数据在哪张表,可以写成表名称,也可以写成数据表所在位置的整数,也可以传入多张表,比如:sheet_name=[0, 1, 2, 3]
# header用于指定表头在哪一行
dataframe = pd.read_excel("dataset_demo.xlsx", sheet_name=0, header=0)
# orient:用来指定传入的json字符串类型:split, records, index, columns, values
# split: 用来读取有索引,由列字段和数据构成的json格式
# records: 用来读取成员为字典的列表
# index: 用来读取以索引为key,以列字段构成的字典为键值的json格式
# columns:处理以列为键,对应一个值字典的对象
# values: 处理一个嵌套的列表,里面的成员也是列表
dataframe = pd.read_json("dataset_demo.json", orient='records')
from sqlalchemy import create_engine
# 创建一个数据库连接
database_connection = create_engine('sqlite:///sample.db')
# 加载数据
dataframe = pd.read_sql_query('SELECT * FROM data', database_connection)
import pymysql
# 创建数据库连接
conn = pymysql.connect(
host='127.0.0.1',
user='root',
password='123456',
database='xxx',
charset='utf8'
)
dataframe = pd.read_sql("select name from user where id = 3", con=conn)
# 查看前几行数据,如果不指定n,默认输出前5条数据
dataframe.head(n=5)
# 查看数据的形状,返回类型为tuple,(行数,列数)
dataframe.shape
# 查看列名
dataframe.columns
# 查看索引信息
dataframe.index
# 查看每列的数据类型
dataframe.dtypes
DataFrame是二维数据。既有行索引index,也有列索引columns。
类型:
data = {
'state': ['A', 'B', 'C', 'D'],
'year': [2011, 2012, 2013, 2014],
'pop': [12, 43, 46, 67]
}
dataframe = pd.DataFrame(data)
print(dataframe)
data = [
[1.74, 20, 65, '打球'],
[1.75, 30, 64, '看书'],
[1.78, 40, 65, '爬山']
]
col_names = ['身高', '年龄', '体重', '爱好']
df = pd.DataFrame(data=data, columns=col_names)
print('dataframe数据:\n', df)
# 查询一列数据,返回类型为Series
dataframe['year']
# 查询多列数据,返回类型为DataFrame
dataframe[['year', 'pop']]
# 查询一行数据,返回类型为Series
dataframe.loc[1]
# 查询多行数据,这里包括第1,2,3行,注意第3行也会包含,返回类型为DataFrame
dataframe.loc[1:3]
Series: 一维数据,一行或一列。
s1 = pd.Series([1, 2, 3, 'a', 'b', 'c'])
print(s1)
# 查看Series的值,返回结果是一个数组[1 2 3 'a' 'b' 'c'],类型为
print(type(s1.values), s1.values)
s2 = pd.Series([1, 2, 3, 'a', 'b', 'c'], index=['num1', 'num2', 'num3', 'letter1', 'letter2', 'letter3'])
print(s2)
使用字典生成的Series,索引为字典的key值
data = {"A": {"a": 1}, "B": "b", "C": "c"}
s3 = pd.Series(data)
print(s3)
print("一个值: \n", s2['num1'])
print("多个值: \n", s2[['num1', 'letter2']])
根据行、列的标签值查询。
得到单个值:
# 获取行索引为2,列名为‘身高’对应的值
dataframe.loc[2, '身高']
得到一个Series:
# 获取行索引为2,列名为'身高'和'体重'对应的值,返回类型为Series
dataframe.loc[2, ['身高', '体重']]
获取行索引为1和2,列索引为‘身高’数据,返回类型为Series
dataframe.loc[[1, 2], '身高']
获取行索引为1和2,列索引为‘身高’和’体重’的数据,返回类型为DataFrame
dataframe.loc[[1, 2], ['身高', '体重']]
行索引按区间查询:
dataframe.loc[1:2, '身高']
列索引按区间查询:
dataframe.loc[1, '身高':'体重']
行和列都按区间查询:
dataframe.loc[1:2, '身高':'体重']
查询身高大于等于1.75的所有行记录:
# dataframe['身高'] >= 1.75 会将满足条件的索引传给loc。
dataframe.loc[dataframe['身高'] >= 1.75, :]
当有多个条件时,可以像下面这些写,&符号不要切换成and
dataframe.loc[(dataframe['身高'] >= 1.75) & (dataframe['体重'] >= 65), :]
1)使用匿名表达式查询
dataframe.loc[lambda row: (row['身高'] >= 1.75) & (row['体重'] >= 65), :]
2)自定义函数查询
查找出爱好为看书的记录
def query_func(row):
return row['爱好'] == '看书'
dataframe.loc[query_func, :]
例1:让所有记录的体重列增加1kg
dataframe.loc[:, '体重'] = dataframe['体重'] + 1
例2: 新增列’身高/体重’,计算所有记录的该比值
dataframe.loc[:, '身高/比重'] = dataframe['身高'] / dataframe['体重']
或者写为如下形式
dataframe['身高/比重'] = dataframe['身高'] / dataframe['体重']
对某一列统一做函数处理,注意axis=1表示的是列索引,axis=0表示的是行索引。
def weight_type(row):
if row['体重'] <= 50:
return "偏瘦"
elif 50 < row['体重'] <= 65:
return "适中"
else:
return "偏旁"
dataframe['结论'] = dataframe.apply(weight_type, axis=1)
assign方法不会修改原有的dataframe
例1:将所有记录的体重翻倍,并赋给新列
new_df = dataframe.assign(t=lambda row: row['体重'] * 2)
条件判断里写的时候需要注意,在python中1&符号连接多个条件来写。
# 新增一列,初始化都为''
dataframe['年龄段'] = ''
# 小于10岁的置为孩童
dataframe.loc[dataframe['年龄'] <= 10, '年龄段'] = '孩童'
# 大于10岁小于30岁的置为青年
dataframe.loc[(10 < dataframe['年龄']) & (dataframe['年龄'] <= 30), '年龄段'] = '青年'
# 大于30岁的置为中年
dataframe.loc[dataframe['年龄'] > 30, '年龄段'] = '中年'
dataframe.describe()
dataframe['身高'].min()
dataframe['年龄'].mean()
# 获取爱好列中的所有爱好并去重
dataframe['爱好'].unique()
dataframe['爱好'].value_counts()
对于两个变量X、Y:
dataframe.cov()
dataframe.corr()
计算年龄和体重的相关系数
dataframe['年龄'].corr(dataframe['体重'])
dataframe.isnull()
单个列判断是否都为空:
dataframe['年龄'].isnull()
dataframe.notnull()
筛选体重已登记的行:
dataframe.loc[dataframe['体重'].notnull(), :]
删除全是空值的列
dataframe.dropna(axis="columns", how='all', inplace=True)
print(dataframe)
删除全是空值的行
dataframe.dropna(axis="index", how='all', inplace=True)
print(dataframe)
将体重为空的元素填充为100,默认是生成新的df,如果想在原有df上修改,需要添加参数inplace=True
dataframe.fillna({"体重": 100})
等同于
dataframe.loc[:, '体重'] = dataframe['体重'].fillna(100)
print(dataframe)
pandas不允许先筛选子dataframe,再进行修改写入。
两种解决方案:
例子1:对体重列进行升序排序
dataframe['体重'].sort_values()
例子2: 对体重列进行降序排列
dataframe['体重'].sort_values(ascending=False)
例子1:单列排序
按照体重进行排序,默认升序
如果想要降序排列,只需要添加参数ascending=False
即可。
dataframe.sort_values(by="体重")
按照年龄和体重排序
dataframe.sort_values(by=["年龄", "体重"])
按照年龄和体重排序,但是年龄按升序排,体重按降序排:
这种排序方法使用场景:假如给每个记录再添加一个肥胖级别,同一级别有多条数据,先按肥胖级别升序排列,排列之后,再按体重降序排列,这样就很容易看出每个肥胖级别的体重情况。
dataframe.sort_values(by=["年龄", "体重"], ascending=[True, False])
处理过程如下:
1)先获取Series的str属性,然后在属性上调用函数;
2)只能在字符串列上使用,不能数字列上使用;
3)DataFrame上没有str属性和处理方法;
4)Series.str并不是Python原生字符串,而是自己的一套方法,大部分和原生str很相似。
replace
将看
替换为阅读
dataframe['爱好'].str.replace("看", "阅读")
也可以写为如下形式,Series.str默认开启了正则表达式模式,也可以通过参数regex=False
进行关闭。
dataframe['爱好'].str.replace("[看]", "阅读", regex=True)
isnumeric
dataframe['爱好'].str.isnumeric()
len
dataframe['爱好'].str.len()
startswith
condition = dataframe['爱好'].str.startswith("爬")
print(dataframe[condition])
contains
condition = dataframe['爱好'].str.contains("爬")
print(dataframe[condition])
连续的字符串使用方法: dataframe['爱好'].str.replace('爱', ‘喜欢’).str.len(),中间的str不能省,这是因为每次字符串操作后返回的依然是一个Series对象,如果直接.len()会报错。
axis=0或者"index"
跨行
cross rowsaxis=1或者"columns"
跨列
cross columns例子1: 删除一行数据
dataframe.drop(1, axis=0, inplace=True)
例子2: 删除一列数据
dataframe.drop('爱好', axis=1, inplace=True)
例子3: 验证axis=0,如果是聚合操作,指的是跨行cross rows
下方代码是跨行求平均值
dataframe.mean(axis=0)
先看下运行结果,发现计算的是每一列的平均值。跨行指的就是列不动,从行的方向上依次计算每列的聚合操作结果
。
例子4: 验证 axis=1, 如果是聚合操作,指的是跨列cross columns
下方代码是跨列求平均值
dataframe.mean(axis=1)
从结果看出,计算的确实是每一行的平均值。跨列指的就是行不动,从列的方向上依次计算每行的聚合操作结果。
用途:
索引上的一些方法:
dataframe.index.is_monotonic_increasing
dataframe.index.is_unique
将索引修改为user_id列,drop=False
会让user_id保留在column
dataframe.set_index("user_id", inplace=True, drop=False)
dataframe.set_index("user_id", inplace=True, drop=True)
dataframe.loc[2].head()
查询结果:如果查询结果只有一条记录,会以键值对的形式展示出来.
如果查询结果有多条记录,会以表格形式展示出来。
参考下方代码,当两个Series相加时,相等的index对应的列会被对应相加,但是各自独有的index,相加后变为了NaN。
s1 = pd.Series([1, 2, 3], index=list("abc"))
s2 = pd.Series([4, 5, 6], index=list("bcd"))
print(s1)
print(s2)
print(s1+s2)
语法:pd.concat(objs, axis=0, join=‘outer’, ignore_index=False)
拆分: df.iloc[]
例子:
# 具体的索引,获取的是一个Series对象,取的是索引为2的行
df_ratings.iloc[2]
# 切片,取的是索引为[1, 7)的行
df_ratings.iloc[1:7]
# 取的是索引为4, 3, 0的行
df_ratings.iloc[[4, 3, 0]]
# boolean值列表,boolean值个数为索引个数,多一个或少一个都会报错,会把为true对应的行取出来
df_ratings.iloc[[True] * 100835]
groupby: 先对数据分组,然后在每个分组上应用聚合函数、转换函数。
g = df_ratings.loc[:, ['userId', 'movieId', 'rating']].groupby('movieId')
for name, df in g:
print(name)
print(df.head())
g.get_group('1619')
求电影的平均分
df_ratings.loc[:, ['movieId', 'rating']].groupby('movieId').mean().head()
下方代码会先对userId分组,然后再对movieId分组,然后再求分组后的其他列的平均值。此时的userId和movieId变成了二级索引
。
df_ratings.loc[:, ['userId', 'movieId', 'rating']].groupby(['userId', 'movieId']).mean().head()
下方代码比上面的代码多了参数as_index=False
,A和B不再是索引,而是结果中的一部分。
df_ratings.loc[:, ['userId', 'movieId', 'rating']].groupby(['userId', 'movieId'], as_index=False).mean().head()
求每部电影的评分总和、评分平均值、评分标准差
import numpy as np
df_ratings.loc[:, ['movieId', 'rating']].groupby('movieId').agg([np.sum, np.mean, np.std]).head()
分组之后获取某一列的总和、平均值和标准差
df_ratings.loc[:, ['movieId', 'rating']].groupby('movieId')['rating'].agg([np.sum, np.mean, np.std]).head()
发现二级索引没了,这里提前对分组后的列做了过滤,性能会更好。
按电影id分组后,对评分求平均值和总和,对userId求个数。
df_ratings.loc[:, ['userId', 'movieId', 'rating']].groupby('movieId').agg({'rating': [np.sum, np.mean], 'userId': np.count_nonzero}).head()
s = df_ratings.loc[:, ['userId', 'movieId', 'rating']].groupby(['userId', 'movieId']).mean().head()
s.index
# 不会修改源s
s.unstack()
# 不会修改源s
s.reset_index()
将元数据的userId和movieId设置为索引。
df_ratings.set_index(['userId', 'movieId'], inplace=True)
df_ratings.sort_index(inplace=True)
map只用于Series,实现每个值-》值的映射。
使用方法:
hobby_type = {
"打球": "运动",
"看书": "文艺",
"爬山": "运动"
}
dataframe['爱好类型'] = dataframe['爱好'].map(hobby_type)
print(dataframe)
hobby_type = {
"打球": "运动",
"看书": "文艺",
"爬山": "运动"
}
dataframe['爱好类型'] = dataframe['爱好'].map(lambda x: hobby_type[x])
print(dataframe)
apply用于Series实现每个值的处理,用于Dataframe实现某个轴的Series的处理。
dataframe['爱好类型'] = dataframe['爱好'].apply(lambda x: hobby_type[x])
dataframe['爱好类型'] = dataframe.apply(lambda x: hobby_type[x['爱好']], axis=1)
只能用于DataFrame,用于处理该DataFrame的每个
元素。
例子:
dataframe[['user_id', '身高', '年龄', '体重']].applymap(lambda x: int(x))
将列式数据变成二维交叉数据,便于分析,叫做重塑或透视。
透视的方法:
stack: DataFrame.stack(level=-1, dropna=True),将column变成index
level=-1代表多层索引的最内层,可以通过==0、1、2指定多层索引的对应层。
unstack: DataFrame.unstack(level=-1, fill_value=None),将index变成column。
例子:
原始数据如下:
unstack之后的数据如下:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
pd.set_option('display.max_rows', 500)
pd.set_option('display.max_columns', 500)
pd.set_option('display.width', 1000)
# 读取评分数据
df_ratings = pd.read_csv('movies/ratings.csv', sep=",", engine='python', header='infer')
# 将时间戳转换为时间
df_ratings["pdate"] = pd.to_datetime(df_ratings["timestamp"], unit='s')
print(df_ratings[["rating"]].applymap(lambda x: int(x)))
df_group = df_ratings[["userId", "movieId", "rating"]].applymap(lambda x: int(x)).groupby([df_ratings["pdate"].dt.month, "rating"])["userId"].agg(pv=np.size)
df_stack = df_group.unstack()
print(df_stack.head(10))
df_stack.plot()
plt.legend(loc='upper center', bbox_to_anchor=(0.6, 0.95), ncol=3, fancybox=True, shadow=True)
plt.show()
print(df_stack.stack().head(10))
pivot: DataFrame.pivot(index=None, columns=None, values=None)
指定index、columns、values实现二维透视。
参考代码:
df_pivot = df.pivot("pdate", "rating", "pv")
df_pivot.plot()
plt.show()
透视效果:
pivot方法相当于对df使用set_index创建分层索引,然后调用unstack。
Pandas官方中文文档: https://www.pypandas.cn/docs/getting_started/
电影数据集: https://grouplens.org/datasets/movielens/