目录
1.读文件
读取CSV、txt、 都是用 read_csv ,excel :read_excel,读数据库可以用 pd.read_sql函数
import pandas as pd
fpath = "D:/test/1.csv"
df = pd.read_csv(fpath, encoding = 'gb18030')
df.head()
#查看行数,列数
df.shape
df.columns
#查看索引列
df.index
df.dtypes
2.Pandas数据结构
Series是一种类似于一维数组的对象,它由一组数据(不同数据类型)以及一组与之相关的数据标签(即标签)组成。
import pandas as pd
import numpy as np
myS = pd.Series([1,'a',5.2,7])
#myS = pd.Series([1,'a',5.2,7],index=['a','b','c','d'])
#myS =pd.Series(dict)
myS
myS.index
myS.values
DataFrame查询一行返回的是series,多行是dataframe结构
import pandas as pd
import numpy as np
data = {'my1':['a','b',1],
'my2':['d','e',1],
'my3':['c',1.5,2]}
df = pd.DataFrame(data)
df.dtypes
df.columns
df.index
#查询多列
df[['my1','my2']]
#查询一行,返回index=1的行
df.loc[1]
df.loc[1:2]
3.pd查询
pandas查询数据的集中方法:
1.df.loc方法,根据行列标签值查询
2.df.iloc方法,根据行列数字位置查询
3.df.where方法
4.df.query方法
.loc既能查询,又能覆盖写入,强烈推荐,
a.准备数据:
import pandas as pd
df = pd.read_csv("./pandas/ant-learn-pandas/datas/beijing_tianqi/beijing_tianqi_2018.csv", engine='python',
encoding='utf-8')
# 设定索引日期,方便日期筛选
df.set_index('ymd', inplace=True)
# 替换掉温度后缀℃
df.loc[:, 'bWendu'] = df["bWendu"].str.replace("℃", "").astype('int32')
df.loc[:, 'yWendu'] = df["yWendu"].str.replace("℃", "").astype('int32')
1)使用单个列表值查询数据
# 得到单个值(2018-01-03最高温度)
res = df.loc["2018-01-03", "bWendu"]
print(res)
# 得到一个Series(2018-01-03最高温度和最低温度)
ret = df.loc["2018-01-03", ["bWendu", "yWendu"]]
print(ret)
2).使用值列表批量查询
# 得到Series
s1 = df.loc[['2018-01-03', '2018-01-04', '2018-01-05'], 'bWendu']
print(s1)
# 得到DataFrame
s2 = df.loc[['2018-01-03', '2018-01-04', '2018-01-05'], ['bWendu', 'yWendu']]
3).使用数值区间进行范围查询
# 行index按区间
s3 = df.loc['2018-01-03':'2018-01-05', 'bWendu']
print(s3)
# 列index按区间
s4 = df.loc['2018-01-03', 'bWendu':'fengxiang']
print(s4)
# 行和列都按区间查询
s5 = df.loc['2018-01-03':'2018-01-05', 'bWendu':'fengxiang']
print(s5)
4).使用条件表达式查询
# 简单条件查询,最低温度低于-10度的列表
s6 = df.loc[df["yWendu"] < -10, :]
print(s6)
# 复杂条件查询,查一下我心中的完美天气
# 查询最高温度小于30度,并且最低温度大于15度,并且是晴天,并且天气为优的数据
s7 = df.loc[(df["bWendu"] <= 30) & (df["yWendu"] >= 15) & (df["tianqi"] == '晴') & (df["aqiLevel"] == 1), :]
print(s7)
5).调用函数查询
# 直接写lambda表达式
s8 = df.loc[lambda df: (df["bWendu"] <= 30) & (df["yWendu"] >= 15), :]
print(s8)
# 编写自己的函数,查询9月份,空气质量好的数据
def query_my_data(df):
return df.index.str.startswith("2018-09") & (df["aqiLevel"] == 1)
s9 = df.loc[query_my_data, :]
print(s9)
4.pandas 增加修改列
1)直接赋值
# 注意,df["bWendu"]其实是一个Series,后面的减法返回的是Series
df.loc[:, "wencha"] = df["bWendu"] - df["yWendu"]
2)apply方法
Apply a function along an axis of the DataFrame.
Objects passed to the function are Series objects whose index is either the DataFrame’s index (axis=0) or the DataFrame’s columns (axis=1).
实例:添加一列温度类型:
- 如果最高温度大于33度就是高温
- 低于-10度是低温
- 否则是常温
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["wendu_type"].value_counts()
3)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
)
4)按条件选择分组分别赋值
# 先创建空列(这是第一种创建新列的方法)
df['wencha_type'] = ''
df.loc[df["bWendu"]-df["yWendu"]>10, "wencha_type"] = "温差大"
df.loc[df["bWendu"]-df["yWendu"]<=10, "wencha_type"] = "温差正常"
5.pandas统计
df.describe() # 提取所有数字列统计结果
df["bWendu"].mean() # 查看单个Series的平均数据(bWendu)
df["bWendu"].max() # 最高温
df["bWendu"].min() # 最低温
df["fengxiang"].unique() #进行去重的输出结果。
df["fengxiang"].value_counts() # 统计"fengxiang"这个列标签中各种风向出现的次数。
#协方差:用于衡量两个变量的总体误差。衡量同向反向程度,如果协方差为正,说明X,Y同向变化,协方差越大说明同向程度越高;如果协方差为负,说明X,Y反向运动,协方差越小说明反向程度越高。
#相关系数:衡量相似度程度,当他们的相关系数为1时,说明两个变量变化时的正向相似度最大,当相关系数为-1时,说明两个变量变化的反向相似度最大
df.cov() # 协方差矩阵
df.corr() # 相关系数矩阵
df["aqi"].corr(df["bWendu"]) # 单独查看空气质量和最高温度的相关系数
6.pandas 缺省值
studf.isnull()
studf["分数"].isnull()
studf.loc[studf["分数"].notnull(), :] # 筛选没有空分数的所有行
studf.dropna(axis="columns", how='all', inplace=True) #删除都为空值所对应的列
#axis : 删除行还是列,{0 or ‘index’, 1 or ‘columns’}, default 0
#how :如果等于any则任何值为空都删除,如果等于all则所有值都为空才删除
#inplace : 如果为True则修改当前df,否则返回新的df
tudf.fillna({"分数":0}) #把分数这列为空值的地方填充为0
# 等同于
studf.loc[:, '分数'] = studf['分数'].fillna(0) #查询分数空值的覆盖写入
# 使用前面的有效值填充,用ffill:forward fill
studf.loc[:, '姓名'] = studf['姓名'].fillna(method="ffill")
to_excel()#写到excel中
7.pandas排序
#DataFrame.sort_values(by, ascending=True, inplace=False)
#参数说明:
#by:字符串或者List<字符串>,单列排序或者多列排序
#ascending:bool或者List,升序还是降序,如果是list对应by的多列 inplace:是否修改原始DataFrame
# 分别指定升序和降序
df.sort_values(by=["aqiLevel", "bWendu"], ascending=[True, False])
8.pandas字符串处理
Pandas的字符串处理
1).使用方法:先获取Series的str属性,然后在属性上调用函数;
2).只能在字符串列上使用,不能数字列上使用
3).Dataframe上没有str属性和处理方法
4).Series.str并不是Python原生字符串,而是自己的一套方法,不过大部分和原生str很相似
# 字符串替换函数
df["bWendu"].str.replace("℃", "")
# 判断是不是数字
df["bWendu"].str.isnumeric()
df["aqi"].str.len()
condition = df["ymd"].str.startswith("2018-03")
df[condition].head()
#怎样提取201803这样的数字月份?
#1、先将日期2018-03-31替换成20180331的形式
#2、提取月份字符串201803
df["ymd"].str.replace("-", "")
df["ymd"].str.replace("-", "").str.slice(0, 6)
# slice就是切片语法,可以直接用(同上操作)
df["ymd"].str.replace("-", "").str[0:6]
# 添加新列
def get_nianyueri(x):
year,month,day = x["ymd"].split("-")
return f"{year}年{month}月{day}日"
df["中文日期"] = df.apply(get_nianyueri, axis=1)
问题:怎样将“2018年12月31日”中的年、月、日三个中文字符去除?
# 方法1:链式replace
df["中文日期"].str.replace("年", "").str.replace("月","").str.replace("日", "")
#Series.str默认就开启了正则表达式模式
# 方法2:正则表达式替换
df["中文日期"].str.replace("[年月日]", "")
9.pandas axis
按哪个axis,就是这个axis要动起来(类似被for遍历),其它的axis保持不动
10.pandas index
更方便的数据查询;
使用index可以获得性能提升;
自动的数据对齐功能;
更多更强大的数据结构支持;
1.使用index查询数据
#如果index是唯一的,Pandas会使用哈希表优化,查询性能为O(1);
#如果index不是唯一的,但是有序,Pandas会使用二分查找算法,查询性能为O(logN);
#如果index是完全随机的,那么每次查询都要扫描全表,查询性能为O(N);
# drop==False,让索引列还保持在column
df.set_index("userId", inplace=True, drop=False)
df.index
# 使用index的查询方法
df.loc[500].head(5)
# 使用column的condition查询方法(同上)
df.loc[df["userId"] == 500].head()
#试验1:完全随机的顺序查询
# 将数据随机打散
from sklearn.utils import shuffle
df_shuffle = shuffle(df)
df_shuffle.head()
# 索引是否是递增的
df_shuffle.index.is_monotonic_increasing
# 索引是否是唯一的
df_shuffle.index.is_unique
# 计时,查询id==500数据性能
%timeit df_shuffle.loc[500]
#实验2:将index排序后的查询
df_sorted = df_shuffle.sort_index()
# 索引是否是递增的
df_sorted.index.is_monotonic_increasing
df_sorted.index.is_unique
%timeit df_sorted.loc[500]
11.pandas merge
1、merge的语法:
pd.merge(left, right, how=‘inner’, on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=True, suffixes=(‘x’, ‘y’), copy=True, indicator=False, validate=None)
left,right:要merge的dataframe或者有name的Series
how:join类型,‘left’, ‘right’, ‘outer’, ‘inner’
on:join的key,left和right都需要有这个key
left_on:left的df或者series的key
right_on:right的df或者seires的key
left_index,right_index:使用index而不是普通的column做join
suffixes:两个元素的后缀,如果列有重名,自动添加后缀,默认是(‘x’, ‘y’)
###############################例子######################
#内连接
pd.merge(df1, df2, on='sno')
pd.merge(df1, df2, how='inner')
pd.merge(df1, df2, how='left')
pd.merge(left, right, how='right')
pd.merge(left, right, how='outer')
pd.merge(left, right, on='key', suffixes=('_left', '_right'))#这里是以'_left', '_right'来区分
12.pandas实现数据合并
使用场景:
批量合并相同格式的Excel、给DataFrame添加行、给DataFrame添加列
一句话说明concat语法:
- 使用某种合并方式(inner/outer)
- 沿着某个轴向(axis=0/1)
- 把多个Pandas对象(DataFrame/Series)合并成一个。
concat语法:pandas.concat(objs, axis=0, join=‘outer’, ignore_index=False)
- objs:一个列表,内容可以是DataFrame或者Series,可以混合
- axis:默认是0代表按行合并,如果等于1代表按列合并
- join:合并的时候索引的对齐方式,默认是outer join,也可以是inner join
- ignore_index:是否忽略掉原来的数据索引
append语法:DataFrame.append(other, ignore_index=False)
- append只有按行合并,没有按列合并,相当于concat按行的简写形式
- other:单个dataframe、series、dict,或者列表
- ignore_index:是否忽略掉原来的数据索引
#1.默认的concat,参数为axis=0、join=outer、ignore_index=False
pd.concat([df1,df2])#行索引不能忽略
#2.使用ignore_index=True可以忽略原来的索引
pd.concat([df1,df2], ignore_index=True)#行索引忽略
#3.使用join=inner过滤掉不匹配的列
pd.concat([df1,df2], ignore_index=True, join="inner")
4.使用axis=1相当于添加新列
s2 = df1.apply(lambda x:x["A"]+"_GG", axis=1)
s2.name="G"
pd.concat([s1,s2], axis=1)
pd.concat([s1,df1,s2], axis=1)
DataFrame.append按行合并数据
df1 = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))
df2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB'))
一行一行的给DataFrame添加数据
# 一个空的df
df = pd.DataFrame(columns=['A'])
#低性能版本
for i in range(5):
# 注意这里每次都在复制
df = df.append({'A': i}, ignore_index=True)
# 高性能版本,第一个入参是一个列表,避免了多次复制
pd.concat(
[pd.DataFrame([i], columns=['A']) for i in range(5)],
ignore_index=True
)
13.pandas EXCEL拆分合并
#拆分:
#(1)计算拆分后的每个excel的行数
total_row_count = df_source.shape[0]
# 这个大excel,会拆分给这几个人
user_names = ["xiao_shuai", "xiao_wang", "xiao_ming", "xiao_lei", "xiao_bo", "xiao_hong"]
# 每个人的任务数目
split_size = total_row_count // len(user_names)
if total_row_count % len(user_names) != 0:
split_size += 1
#(2)拆分成多个dataframe
df_subs = []
for idx, user_name in enumerate(user_names):
# iloc的开始索引
begin = idx*split_size
# iloc的结束索引
end = begin+split_size
# 实现df按照iloc拆分
df_sub = df_source.iloc[begin:end]
# 将每个子df存入列表
df_subs.append((idx, user_name, df_sub))
#(3)拆分成多个dataframe
for idx, user_name, df_sub in df_subs:
file_name = f"{splits_dir}/crazyant_blog_articles_{idx}_{user_name}.xlsx"
df_sub.to_excel(file_name, index=False)
#合并
(1)遍历文件夹,得到要合并的Excel文件列表
(2)分别读取到dataframe,给每个df添加一列用于标记来源
(3)使用pd.concat进行df批量合并
(4)将合并后的dataframe输出到excel
#1. 遍历文件夹,得到要合并的Excel名称列表
import os
excel_names = []
for excel_name in os.listdir(splits_dir):
excel_names.append(excel_name)
#2分别读取到dataframe
df_list = []#用于存储各个读取出来的dataframe
for excel_name in excel_names:
# 读取每个excel到df
excel_path = f"{splits_dir}/{excel_name}"
df_split = pd.read_excel(excel_path)
# 得到username
username = excel_name.replace("crazyant_blog_articles_", "").replace(".xlsx", "")[2:]
print(excel_name, username)
# 给每个df添加1列,即用户名字
df_split["username"] = username
df_list.append(df_split)
#使用pd.concat进行合并
df_merged = pd.concat(df_list)
df_merged.shape
df_merged.head()
df_merged["username"].value_counts()
df_merged.to_excel(f"{work_dir}/crazyant_blog_articles_merged.xlsx", index=False)