pandas学习

1. Pandas读取数据

  1. 1pandas读取纯文本文件
    • 读取csv文件
    • 读取txt文件

(1)读取CSV,使用默认的标题行逗号分隔符

fpath = "./datas/ml-latest-small/ratings.csv"

ratings = pd.read_csv(fpath)

# 查看每列的数据类型
ratings.dtypes

(2)读取txt文件,自己指定分隔符、列名

fpath = "./datas/crazyant/access_pvuv.txt"

pvuv = pd.read_csv(
    fpath,
    sep="\t",(制表符)
    header=None,
    names=['pdate', 'pv', 'uv']
)

 1.2pandas读取xlsx格式excel文件  

fpath = "./datas/crazyant/access_pvuv.xlsx"
pvuv = pd.read_excel(fpath)

1.3pandas读取mysql数据表

import pymysql
conn = pymysql.connect(
        host='127.0.0.1',
        user='root',
        password='12345678',
        database='test',
        charset='utf8'
    )

mysql_page = pd.read_sql("select * from crazyant_pvuv", con=conn)

其他:

# 查看数据的形状,返回(行数、列数)
ratings.shape

# 查看列名列表
ratings.columns

# 查看索引列
ratings.index

# 查看每列的数据类型
ratings.dtypes


2.Pandas数据结构

2.1. Series

Series是一种类似于一维数组的对象,它由一组数据(不同数据类型)以及一组与之相关的数据标签(即索引)组成。

(1)仅有数据列表即可产生最简单的Series   

  s1 = pd.Series([1,'a',5.2,7])

(2)创建一个具有标签索引的Series

 s2 = pd.Series([1, 'a', 5.2, 7], index=['d','b','a','c'])

(3)使用Python字典创建Series

sdata={'Ohio':35000,'Texas':72000,'Oregon':16000,'Utah':5000}

s3=pd.Series(sdata)

(4) 根据标签索引查询数据

s2['a']

type(s2[['b','a']])同级【【】】

其他:

# 获取索引
s1.index

# 获取数据
s1.values

2.2 DataFrame

DataFrame是一个表格型的数据结构

  • 每列可以是不同的值类型(数值、字符串、布尔值等)
  • 既有行索引index,也有列索引columns
  • 可以被看做由Series组成的字典

(1)创建dataframe最常用的方法,见02节读取纯文本文件、excel、mysql数据库

(2) 根据多个字典序列创建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)

其他:

df.columns

2.3 从DataFrame中查询出Series

  • 如果只查询一行、一列,返回的是pd.Series
  • 如果查询多行、多列,返回的是pd.DataFrame

查询一列,结果是一个pd.Series

df['year']

type(df['year'])

查询多列,结果是一个pd.DataFrame

df[['year', 'pop']]

type(df[['year', 'pop']])

查询一行,结果是一个pd.Series

df.loc[0]

查询多行,结果是一个pd.DataFrame

df.loc[0:3]

3. Pandas查询数据

  1. df.loc方法,根据行、列的标签值查询
  2. df.iloc方法,根据行、列的数字位置查询
  3. df.where方法
  4. df.query方法

.loc既能查询,又能覆盖写入,强烈推荐!

使用值列表批量查询

# 得到DataFrame
df.loc[['2018-01-03','2018-01-04','2018-01-05'], ['bWendu', 'yWendu']]

使用数值区间进行范围查询

# 行和列都按区间查询
df.loc['2018-01-03':'2018-01-05', 'bWendu':'fengxiang']

布尔条件---简单条件查询,最低温度低于-10度的列表

df.loc[df["yWendu"]<-10, :]

使用条件表达式查询

## 查询最高温度小于30度,并且最低温度大于15度,并且是晴天,并且天气为优的数据
df.loc[(df["bWendu"]<=30) & (df["yWendu"]>=15) & (df["tianqi"]=='晴') & (df["aqiLevel"]==1), :]

调用函数查询

# 直接写lambda表达式
df.loc[lambda df : (df["bWendu"]<=30) & (df["yWendu"]>=15), :]

# 编写自己的函数,查询9月份,空气质量好的数据,调用日期列转换成字符串index.str,
def query_my_data(df):
    return df.index.str.startswith("2018-09") & (df["aqiLevel"]==1)
df.loc[query_my_data, :]

4. Pandas新增数据列

(1)直接赋值的方法

# 替换掉温度的后缀℃
df.loc[:, "bWendu"] = df["bWendu"].str.replace("℃", "").astype('int32')
df.loc[:, "yWendu"] = df["yWendu"].str.replace("℃", "").astype('int32')

# 注意,df["bWendu"]其实是一个Series,后面的减法返回的是Series
df.loc[:, "wencha"] = df["bWendu"] - df["yWendu"]

(2)df.apply方法

实例:添加一列温度类型:

  1. 如果最高温度大于33度就是高温
  2. 低于-10度是低温
  3. 否则是常温

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方法

# 可以同时添加多个新的列
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数据统计函数

(1)汇总类统计

# 一下子提取所有数字列统计结果
df.describe()

## 查看单个Series的数据
df["bWendu"].mean() 

# 最高温
df["bWendu"].max()

# 最低温
df["bWendu"].min()

(2)唯一去重和按值计数

一般不用于数值列,而是枚举、分类列

唯一性去重

df["fengxiang"].unique()

 按值计数

df["fengxiang"].value_counts()

 (3)相关系数和协方差

  1. 协方差:衡量同向反向程度,如果协方差为正,说明X,Y同向变化,协方差越大说明同向程度越高;如果协方差为负,说明X,Y反向运动,协方差越小说明反向程度越高。-~<---0--->+~
  2. 相关系数:衡量相似度程度,当他们的相关系数为1时,说明两个变量变化时的正向相似度最大,当相关系数为-1时,说明两个变量变化的反向相似度最大 -1<---0--->1

# 协方差矩阵:
df.cov()

# 相关系数矩阵
df.corr()

 # 单独查看空气质量和最高温度的相关系数
df["aqi"].corr(df["bWendu"])

# 空气质量和温差的相关系数
df["aqi"].corr(df["bWendu"]-df["yWendu"])

6.Pandas对缺失值的处理

Pandas使用这些函数处理缺失值:

  • isnull和notnull检测是否是空值,可用于df和series
  • dropna:丢弃、删除缺失值
    • axis : 删除行还是列,{0 or ‘index’, 1 or ‘columns’}, default 0
    • how : 如果等于any则任何值为空都删除,如果等于all则所有值都为空才删除
    • inplace : 如果为True则修改当前df,否则返回新的df
  • fillna:填充空值
    • value:用于填充的值,可以是单个值,或者字典(key是列名,value是值)
    • method : 等于ffill使用前一个不为空的值填充forword fill;等于bfill使用后一个不为空的值填充backword fill
    • axis : 按行还是列填充,{0 or ‘index’, 1 or ‘columns’}
    • inplace : 如果为True则修改当前df,否则返回新的df

(1)studf.isnull()

studf["分数"].notnull()

# 筛选没有空分数的所有行
studf.loc[studf["分数"].notnull(), :]

(2)#删除掉全是空值的列

studf.dropna(axis="columns", how='all', inplace=True)

#删除掉全是空值的行

studf.dropna(axis="index", how='all', inplace=True)

(3)将分数列为空的填充为0分

studf.fillna({"分数":0})

# 等同于
studf.loc[:, '分数'] = studf['分数'].fillna(0)

(4)使用前面的有效值填充,用ffill:forward fill

studf.loc[:, '姓名'] = studf['姓名'].fillna(method="ffill")

7.Pandas的SettingWithCopyWarning报警

# 只选出3月份的数据用于分析
condition = df["ymd"].str.startswith("2018-03")

发出警告的代码 df[condition]["wen_cha"] = df["bWendu"]-df["yWendu"]

相当于:df.get(condition).set(wen_cha),第一步骤的get发出了报警

链式操作其实是两个步骤,先get后set,get得到的dataframe可能是view也可能是copy,pandas发出警告

(1)解决方法1

将get+set的两步操作,改成set的一步操作

df.loc[condition, "wen_cha"] = df["bWendu"]-df["yWendu"]

(2)解决方法2

如果需要预筛选数据做后续的处理分析,使用copy复制dataframe

df_month3 = df[condition].copy()

df_month3["wen_cha"] = df["bWendu"]-df["yWendu"]

总之,pandas不允许先筛选子dataframe,再进行修改写入
要么使用.loc实现一个步骤直接修改源dataframe
要么先复制一个子dataframe再一个步骤执行修改

8.Pandas数据排序

Series的排序:
Series.sort_values(ascending=True, inplace=False)
参数说明:

  • ascending:默认为True升序排序,为False降序排序
  • inplace:是否修改原始Series

DataFrame的排序:
DataFrame.sort_values(by, ascending=True, inplace=False)
参数说明:

  • by:字符串或者List<字符串>,单列排序或者多列排序
  • ascending:bool或者List,升序还是降序,如果是list对应by的多列
  • inplace:是否修改原始DataFrame

df["aqi"].sort_values(ascending=False)

单列排序

df.sort_values(by="aqi")

多列排序

# 按空气质量等级、最高温度排序,默认升序
df.sort_values(by=["aqiLevel", "bWendu"])

# 分别指定升序和降序
df.sort_values(by=["aqiLevel", "bWendu"], ascending=[True, False])

9.Pandas字符串处理

Pandas的字符串处理:

  1. 使用方法:先获取Series的str属性,然后在属性上调用函数;
  2. 只能在字符串列上使用,不能数字列上使用;
  3. Dataframe上没有str属性和处理方法
  4. Series.str并不是Python原生字符串,而是自己的一套方法,不过大部分和原生str很相似;

# 字符串替换函数
df["bWendu"].str.replace("℃", "")

# 判断是不是数字
df["bWendu"].str.isnumeric()

需要多次str处理的链式操作

# slice就是切片语法,可以直接用
df["ymd"].str.replace("-", "").str[0:6]

使用正则表达式的处理

# 方法2:正则表达式替换
df["中文日期"].str.replace("[年月日]", "")

10.Pandas的axis参数怎么理解

  • axis=0或者"index":
    • 如果是单操作,就指的是某一行
    • 如果是聚合操作,指的是跨行cross rows
  • axis=1或者"columns":
    • 如果是单操作,就指的是某一列
    • 如果是聚合操作,指的是跨列cross columns

按哪个axis,就是这个axis要动起来(类似被for遍历),其它的axis保持不动

# 代表的就是删除某列
df.drop("A", axis=1)

# 代表的就是删除某行
df.drop(1, axis=0)

跨行# axis=0 or axis=index
df.mean(axis=0)

跨列# axis=1 or axis=columns
df.mean(axis=1)

def get_sum_value(x):
    return x["A"] + x["B"] + x["C"] + x["D"]

df["sum_value"] = df.apply(get_sum_value, axis=1)

 11.Pandas的索引index的用途

index的用途总结:

  1. 更方便的数据查询;
  2. 使用index可以获得性能提升;
  3. 自动的数据对齐功能;
  4. 更多更强大的数据结构支持;

(1)使用index查询数据

# 使用index的查询方法
df.loc[500].head(5)

# 使用column的condition查询方法
df.loc[df["userId"] == 500].head()

(2)使用index会提升查询性能

  • 如果index是唯一的,Pandas会使用哈希表优化,查询性能为O(1);
  • 如果index不是唯一的,但是有序,Pandas会使用二分查找算法,查询性能为O(logN);
  • 如果index是完全随机的,那么每次查询都要扫描全表,查询性能为O(N);

排序 df_sorted = df_shuffle.sort_index()

%timeit df_sorted.loc[500]

(3)使用index能自动对齐数据

 (4)

很多强大的索引数据结构

  • CategoricalIndex,基于分类数据的Index,提升性能;
  • MultiIndex,多维索引,用于groupby多维聚合后结果等;
  • DatetimeIndex,时间类型索引,强大的日期和时间的方法支持;

12.Pandas怎样实现DataFrame的Merge

Pandas的Merge,相当于Sql的Join,将不同的表按key关联到一个表

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')

df_ratings_users_movies = pd.merge(
    df_ratings_users, df_movies, left_on="MovieID", right_on="MovieID", how="inner"
)

所有列名都有

 

 

如果出现非Key的字段重名怎么办

 

 13.Pandas实现数据的合并concat

使用场景:

批量合并相同格式的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)使用pandas.concat合并数据

添加一列Series

 s1 = pd.Series(list(range(4)), name="F")
pd.concat([df1,s1], axis=1)

添加多列Series***lambda x每一行的字典:x["A"]A这一列每一行的值+"_GG"

s2 = df1.apply(lambda x:x["A"]+"_GG", axis=1)

pd.concat([df1,s1,s2], axis=1)

(2)使用DataFrame.append按行合并数据

df1.append(df2, ignore_index=True)

for i in range(5):
    # 注意这里每次都在复制
    df = df.append({'A': i}, ignore_index=True)
df

# 第一个入参是一个列表,避免了多次复制
pd.concat(
    [pd.DataFrame([i], columns=['A']) for i in range(5)],
    ignore_index=True
)

14.Pandas批量拆分Excel与合并Excel

work_dir="./course_datas/c15_excel_split_merge"
#f是format的高级引入方法,格式化字符串

df_source = pd.read_excel(f"{work_dir}/crazyant_blog_articles_source.xlsx")

(1)将一个大Excel等份拆成多个Excel

# 每个人的任务数目,//向负无穷方向取整后
split_size = total_row_count // len(user_names)
if total_row_count % len(user_names) != 0:
    split_size += 1

拆分成多个dataframe

enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,for循环传进参数是数组

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))

遍历的是列表,将df存入的是列表,遍历列表,加文件名,将df存入命名好的excel 

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)

(2)合并多个小Excel到一个大Excel

遍历文件夹,得到要合并的Excel名称列表

分别读取到dataframe

使用pd.concat进行合并

df_merged = pd.concat(df_list)

15.Pandas怎样实现groupby分组统计

groupby:先对数据分组,然后在每个分组上应用聚合函数、转换函数

df.groupby(['A','B']).mean()

 df.groupby(['A','B'], as_index=False).mean()

 # 方法1:预过滤,性能更好
df.groupby('A')['C'].agg([np.sum, np.mean, np.std])

不同列使用不同的聚合函数

df.groupby('A').agg({"C":np.sum, "D":np.mean}) 

# 新增一列为月份
df['month'] = df['ymd'].str[:7]

#agg是使用多个聚合函数
group_data = df.groupby('month').agg({"bWendu":np.max, "yWendu":np.min, "aqi":np.mean})
16.Pandas的分层索引MultiIndex

(1)Series的分层索引MultiIndex

# unstack把二级索引变成列
ser.unstack()

#将索引变成列
ser.reset_index()

Series有多层索引MultiIndex怎样筛选数据?

#筛选第一个索引
ser.loc['BIDU']

# 多层索引,可以用元组的形式筛选
ser.loc[('BIDU', '2019-10-02')]

#筛选第二个索引
ser.loc[:, '2019-10-02']

(2)DataFrame的多层索引MultiIndex

  • 元组(key1,key2)代表筛选多层索引,其中key1是索引第一级,key2是第二级,比如key1=JD, key2=2019-10-02
  • 列表[key1,key2]代表同一层的多个KEY,其中key1和key2是并列的同级索引,比如key1=JD, key2=BIDU

#筛选多级索引用元组括起来
stocks.loc[('BIDU', '2019-10-02'), :]

#[]表示并列筛选多个值
stocks.loc[['BIDU', 'JD'], :]

# slice(None)代表筛选这一索引的所有内容
stocks.loc[(slice(None), ['2019-10-02', '2019-10-03']), :]

17.Pandas的数据转换函数map、apply、applymap

数据转换函数对比:map、apply、applymap:

  1. map:只用于Series,实现每个值->值的映射;
  2. apply:用于Series实现每个值的处理,用于Dataframe实现某个轴的Series的处理;
  3. applymap:只能用于DataFrame,用于处理该DataFrame的每个元素;

# 公司股票代码到中文的映射,注意这里是小写
dict_company_names = {
    "bidu": "百度",
    "baba": "阿里巴巴",
    "iq": "爱奇艺", 
    "jd": "京东"
}

17.1. map用于Series值的转换

实例:将股票代码英文转换成中文名字

Series.map(dict) or Series.map(function)均可

方法1:Series.map(dict)

#str.lower()变成小写去map里找,直接实现value的映射
stocks["公司中文1"] = stocks["公司"].str.lower().map(dict_company_names)

方法2:Series.map(function)

function的参数是Series的每个元素的值

#lambda x 即series每个值
#lambda x : dict_company_names[x.lower()] value形成新的series,
stocks["公司中文2"] = stocks["公司"].map(lambda x : dict_company_names[x.lower()])

17.2. apply用于Series和DataFrame的转换

  • Series.apply(function), 函数的参数是每个值
  • DataFrame.apply(function), 函数的参数是Series

Series.apply(function)

function的参数是Series的每个值

stocks["公司中文3"] = stocks["公司"].apply(
    lambda x : dict_company_names[x.lower()])

DataFrame.apply(function)

function的参数是对应轴的Series

stocks["公司中文4"] = stocks.apply(
    lambda x : dict_company_names[x["公司"].lower()], 
    axis=1)

17.3. applymap用于DataFrame所有值的转换

# 将这些数字取整数,应用于所有元素
sub_df.applymap(lambda x : int(x))

# 直接修改原df的这几列
stocks.loc[:, ['收盘', '开盘', '高', '低', '交易量']] = sub_df.applymap(lambda x : int(x))

18.归一化,Pandas怎样对每个分组应用apply函数

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值