文章目录
1.读取数据
import pandas as pd
# 使用pd.read_csv读取数据
fpath = "./datas/ml-latest-small/ratings.csv"
df = pd.read_csv(fpath)
# 读取txt文件,自己指定分隔符、列名
fpath = "./datas/crazyant/access_pvuv.txt"
df = pd.read_csv(
fpath,
sep="\t",
header=None,
names=['pdate', 'pv', 'uv']
)
# 如果读取文件没有列名(输出默认第一行内容为列名),
# 则需要给header=None同时names给自定义列名列表
# 读取excel文件
fpath = "./datas/crazyant/access_pvuv.xlsx"
df = pd.read_excel(fpath, skiprows=2)
# skiprows 忽略前面的2个空行
# 读取MySQL数据库
import pymysql
conn = pymysql.connect(
host='127.0.0.1',
user='root',
password='test',
database='test',
charset='utf8'
)
mysql_df = pd.read_sql("select * from table_name", con=conn)
2.查看数据集基本信息
# 查看数据类型
type(df)
# 查看前几行数据,默认前5行
df.head()
# 查看后几行数据
df.tail()
# 查看数据的形状,返回(行数、列数)
df.shape
# 数据各列名包含的数据计数
df.count()
# 查看列名列表
df.columns
# 查看索引列
df.index
# 查看每列的数据类型
df.dtypes
# 查看数据值
df.values
# 提取所有数字列统计结果
df.describe()
# 查看数据基本信息
df.info()
3.pandas数据结构分 DataFrame 和 Series
DataFrame是一个表格型的数据结构
1. 每列可以是不同的值类型(数值、字符串、布尔值等)
2. 既有行索引index,也有列索引columns
3. 可以被看做由Series组成的字典
4. 一行一列为Series,多行多列为DataFrame
# 创建 Series 数据
ser_data = [1, 'a', 5.2, 7]
ser = pd.Series(ser_data, index=['d','b','a','c'])
# 字典形式创建
ser_dict_data = {'Ohio':35,'Texas':72,'Oregon':16,'Utah':50}
ser2 = pd.Series(ser_dict_data )
# 为Series的列名赋值
ser.name = 'new_name'
# 字典形式创建 DataFrame
data={
'state':['Ohio','Ohio','Ohio','Nevada','Nevada'],
'year':[2000,2001,2002,2001,2002],
'pop':[1.5,1.7,3.6,2.4,2.9]
}
df = pd.DataFrame(data)
4.Pandas查询数据(推荐.loc,既能查询,又能覆盖写入)
- df是可以直接做条件筛选或切片操作的 df[ 条件或切片操作]
- df.loc方法,根据行、列的 标签值 查询
- df.iloc方法,根据行、列的 数字位置 查询----只能整数
- df.where方法
- df.query方法
# Series类型
df['bWendu']
df.loc[:,'bWendu']
# DataFrame类型
df[['bWendu']]
df.loc[:,['bWendu']]
1、使用单个label值查询数据
# 得到单个值
df.loc['2018-01-03', 'bWendu']
# 得到一个Series
df.loc['2018-01-03', ['bWendu', 'yWendu']]
2、使用值列表批量查询
# 得到Series
df.loc[['2018-01-03','2018-01-04','2018-01-05'], 'bWendu']
# 得到DataFrame
df.loc[['2018-01-03','2018-01-04','2018-01-05'], ['bWendu', 'yWendu']]
3、使用数值区间进行范围查询
# 行index按区间
df.loc['2018-01-03':'2018-01-05', 'bWendu']
# 列index按区间
df.loc['2018-01-03', 'bWendu':'fengxiang']
# 行和列都按区间查询
df.loc['2018-01-03':'2018-01-05', 'bWendu':'fengxiang']
4、使用条件表达式查询
## 查询最高温度小于30度,并且最低温度大于15度,并且是晴天,并且天气为优的数据
df.loc[(df["bWendu"]<=30) & (df["yWendu"]>=15) & (df["tianqi"]=='晴'), :]
5、调用函数查询
# 直接写lambda表达式
df.loc[lambda df : (df["bWendu"]<=30) & (df["yWendu"]>=15), :]
# 编写自己的函数,查询9月份,空气质量好的数据
def query_my_data(df):
return df.index.str.startswith("2018-09") & (df["aqiLevel"]==1)
df.loc[query_my_data, :]
iloc() 和 at() 、iat()、ix()
# 取前两列
df.iloc[:, :2]
# 取前两行
df.iloc[:2, ]
df.iloc[0,2]
df.iloc[1:4,[0,2]]
df.iloc[[1,3,5],[0,2]]
df.iloc[[1,3,5],0:2]
# ix 的功能更加强大,参数既可以是索引,也可以是名称,相当于,loc和iloc的合体
df.ix[1:3,['a','b']]
df.ix[[1,3,5],['a','b']]
# at 根据指定行index及列label,快速定位DataFrame的某个元素,选择列时仅支持列名
df.at[3,'a']
# iat 与at的功能相同,只使用索引参数
df.iat[3, 0]
df.iat[3,'a']
5.新增数据列
- 直接赋值
df.loc[:, "wencha"] = df["bWendu"] - df["yWendu"]
- df.apply 方法
Apply a function along an axis of the DataFrame.
def get_wendu_type(x):
if x["bWendu"] > 33:
return '高温'
if x["yWendu"] < -10:
return '低温'
return '常温'
# 注意需要设置axis==1,这是series的index是columns
df.loc[:, "wendu_type"] = df.apply(get_wendu_type, axis=1)
- df.assign 方法
Assign new columns to a DataFrame.
Returns a new object with all original columns in addition to new ones.
# 可以同时添加多个新的列
df.assign(
yWendu_huashi = lambda x : x["yWendu"] * 9 / 5 + 32,
# 摄氏度转华氏度
bWendu_huashi = lambda x : x["bWendu"] * 9 / 5 + 32
)
- 按条件选择分组分别赋值
# 先创建空列(这是第一种创建新列的方法)
df['wencha_type'] = ''
df.loc[df["bWendu"]-df["yWendu"]>10, "wencha_type"] = "温差大"
df.loc[df["bWendu"]-df["yWendu"]<=10, "wencha_type"] = "温差正常"
6.数据统计函数
- 协方差:衡量同向反向程度,如果协方差为正,说明X,Y同向变化,协方差越大说明同向程度越高;如果协方差为负,说明X,Y反向运动,协方差越小说明反向程度越高。
- 相关系数:衡量相似度程度,当他们的相关系数为1时,说明两个变量变化时的正向相似度最大,当相关系数为-1时,说明两个变量变化的反向相似度最大
# 一下子提取所有数字列统计结果
df.describe()
# 查看单个Series的数据
df["bWendu"].mean() # 平均值
df["bWendu"].max() # 最大值
df["bWendu"].min() # 最小值
df["fengxiang"].unique() # 去重
df["fengxiang"].value_counts() # 按值计数
# 所有数值列相关程度
df.cov() # 协方差矩阵
df.corr() # 相关系数矩阵
# 单独查看空气质量和最高温度的相关系数
df["aqi"].corr(df["bWendu"])
7.缺失值处理过程
- 步骤1:读取excel的时候,忽略前几个空行(也可利用dropna删除
空行)
studf = pd.read_excel("./datas/student_excel/student_excel.xlsx", skiprows=2)
- 步骤2:检测数据空值
studf.isnull()
# 筛选没有空分数的所有行
studf.loc[studf["分数"].notnull(), :]
- 步骤3:删除掉全是空值的列
studf.dropna(axis="columns", how='all', inplace=True)
# axis : 删除行还是列,{0 或 ‘index’, 1 或 ‘columns’}, default 0
# how : any则任何值为空都删除,all则所有值都为空才删除
# inplace : True修改当前df,False返回新的df
- 步骤4:删除掉全是空值的行
studf.dropna(axis="index", how='all', inplace=True)
- 步骤5:填充应该有值的空值项
studf.loc[:, '分数'] = studf['分数'].fillna(value=0)
studf.loc[:, '姓名'] = studf['姓名'].fillna(method="ffill")
# value:用于填充的值,可以是单个值,或者字典(key是列名,value是值)
# method : 等于ffill使用前一个不为空的值填充(forword fill)
# 等于bfill使用后一个不为空的值填充(backword fill)
# axis : 按行还是列填充,{0 or ‘index’, 1 or ‘columns’}
# inplace : True修改当前df,False返回新的df
- 步骤6:保存处理清洗后的数据
studf.to_excel("./datas/student_excel/student_excel_clean.xlsx", index=False)
8.数据排序
- Series 排序:
Series.sort_values(ascending=True, inplace=False)
df["aqi"].sort_values(ascending=False)
# ascending:默认为True升序排序,为False降序排序
# inplace:是否修改原始Series
- DataFrame 排序
DataFrame.sort_values(by, ascending=True, inplace=False)
# 分别指定升序和降序
df.sort_values(by=["aqiLevel", "bWendu"], ascending=[True, False])
# by:字符串或者List<字符串>,单列排序或者多列排序
# ascending:bool或者List,升序还是降序,如果是list对应by的多列
# inplace:是否修改原始DataFrame
9.字符串处理
- 使用方法:先获取Series的str属性,然后在属性上调用函数;
- 只能在字符串列上使用,不能数字列上使用;
- Dataframe上没有str属性和处理方法,只有Series有
- Series.str并不是Python原生字符串,而是自己的一套方法,不过大部分和原生str很相似
# 获取Series的str属性,使用各种字符串处理函数
# 字符串替换函数
df["bWendu"].str.replace("℃", "")
# 判断是不是数字
df["bWendu"].str.isnumeric()
# 获取长度
df["bWendu"].str.len()
# 使用str的startswith、contains等得到bool的Series可以做条件查询
condition = df["ymd"].str.startswith("2018-03")
condition = df["ymd"].str.contains("2018")
df[condition].head()
# 多次str处理的链式操作
df["ymd"].str.replace("-", "").str.slice(0, 6)
# 等同于
# slice就是切片语法,可以直接用
df["ymd"].str.replace("-", "").str[0:6]
# 使用正则表达式的处理(2018年12月31日 --> 20181231)
# 方法1:链式replace
df["中文日期"].str.replace("年", "").str.replace("月","").str.replace("日", "")
# 方法2:正则表达式替换
df["中文日期"].str.replace("[年月日]", "")
10.处理日期时间数据
# 将日期列转换成pandas的日期
df.set_index(pd.to_datetime(df["ymd"]), inplace=True)
# DatetimeIndex是Timestamp的列表形式
df.index
df.index[0]
# 固定的某一天筛选
df.loc['2018-01-05']
# 日期区间筛选
df.loc['2018-01-05':'2018-01-10']
# 按月份前缀筛选
df.loc['2018-03']
# 按月份区间筛选
df.loc["2018-07":"2018-09"]
# 按年份前缀筛选
df.loc["2018"]
# 周、月、季度数字列表
df.index.week
df.index.month
df.index.quarter
# 统计每周、月、季度的数据
df.groupby(df.index.week)["bWendu"].max().plot()
df.groupby(df.index.month)["bWendu"].max().plot()
df.groupby(df.index.quarter)["bWendu"].max().plot()
- 处理日期索引的缺失的一般方法
# 一. 使用pandas.reindex方法
## 1. 将日期列设为索引,再将索引变成日期索引
df_date = df.set_index("pdate")
df_date = df_date.set_index(pd.to_datetime(df_date.index))
## 2. 使用pandas.reindex填充缺失的索引,date_range函数可以设置periods参数
pdates = pd.date_range(start="2019-12-01", end="2019-12-05") # 生成完整的日期序列
df_date_new = df_date.reindex(pdates, fill_value=0)
# 二. 使用pandas.resample方法
## 1. 先将索引变成日期索引
df_new2 = df.set_index(pd.to_datetime(df["pdate"])).drop("pdate", axis=1)
## 2. 使用dataframe的resample的方法按照天重采样
df_new2 = df_new2.resample("D").mean().fillna(0)
- 说明:
resample的含义:改变数据的时间频率
11.groupby分组
- 所有的聚合统计,都是在dataframe和series上进行的
1.常用用法
df.groupby('A').sum() # 如果不是数值,会被直接忽略
df.groupby(['A','B']).mean() # ('A','B')成对变成了二级索引
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({"C":np.sum, "D":np.mean}) # 不同列使用不同的聚合函数
- 理解过程
# 1、遍历单个列聚合的分组
g = df.groupby('A')
g
for name,group in g:
print(name)
print(group)
print()
bar
A B C D
1 bar one -0.375789 -0.345869
3 bar three -1.564748 0.081163
5 bar two -0.202403 0.701301
foo
A B C D
0 foo one 0.542903 0.788896
2 foo two -0.903407 0.428031
g.get_group('bar')
# 2、遍历多个列聚合的分组
g = df.groupby(['A', 'B'])
# name是一个2个元素的tuple
for name,group in g:
print(name)
print(group)
print()
g.get_group(('foo', 'one'))
g['C']
for name, group in g['C']:
print(name)
print(group)
print(type(group))
print()
12.groupby后其他列数据处理
# 1. 单列-单指标统计
df.groupby("MovieID")["Rating"].mean()
# 2. 单列-多指标统计(1)
df.groupby("MovieID")["Rating"].agg(
mean="mean", max="max", min=np.min
)
# 2. 单列-多指标统计(2)
df.groupby("MovieID").agg(
{"Rating":['mean', 'max', np.min]}
)
# 3. 多列-多指标统计(1)
df.groupby("MovieID").agg(
rating_max=("Rating", "max"),
user_count=("UserID", lambda x : x.nunique()),
LTB=("LTB", (lambda x: ",".join(x.unique())))
# 尤其对‘字符串’数据列这样处理
)
# 3. 多列-多指标统计(2)
df.groupby("MovieID").agg(
{
"Rating": ['mean', 'min', 'max'],
"UserID": lambda x :x.nunique()
}
)
.reset_index()
.rename(columns={"ymd":"月份"})
13. 按行遍历DataFrame的3种方法
# 1. df.iterrows() 慢
for idx, row in df.iterrows():
print(idx, row)
print(idx, row["A"], row["B"], row["C"], row["D"])
# 2. df.itertuples() 快
for row in df.itertuples():
print(row)
print(row.Index, row.A, row.B, row.C, row.D)
# 3. for+zip 快
for A, B in zip(df["A"], df["B"]):
print(A, B)
14. DataFrame赋值方法
# 1. 索引或者标签修改值的位置
df.iloc[2,2] = 1111
df.loc['20130101','B'] = 2222
# 2.有条件赋值
df.B[df.A>4] = 0
df.col1[df.col1 =='a'] = 'm'
# 3. 按行或列
df['F'] = np.nan
# 4. 添加series序列
df['E'] = pd.Series([1,2,3,4,5,6], index=pd.date_range('20130101',periods=6))
15. 数据转换函数map、apply、applymap
- map:只用于Series,实现每个值->值的映射
- apply:用于Series实现每个值的处理,用于Dataframe实现某个轴的Series的处理
- applymap:只能用于DataFrame,用于处理该DataFrame的每个元素
- map用于Series值的转换
# 将股票代码英文转换成中文名字
dict_company_names = {
"bidu": "百度",
"baba": "阿里巴巴",
"iq": "爱奇艺",
"jd": "京东"
}
stocks["公司中文1"] = stocks["公司"].str.lower().map(dict_company_names)
# 或者
stocks["公司中文2"] = stocks["公司"].map(lambda x : dict_company_names[x.lower()])
- apply用于Series和DataFrame的转换
# Series.apply(function), 函数的参数是每个值
stocks["公司中文3"] = stocks["公司"].apply(
lambda x : dict_company_names[x.lower()])
# DataFrame.apply(function), 函数的参数是Series
stocks["公司中文4"] = stocks.apply(
lambda x : dict_company_names[x["公司"].lower()],
axis=1)
- applymap用于DataFrame所有值的转换
# 将这些数字取整数,应用于所有元素
sub_df.applymap(lambda x : int(x))