Pandas数据分析从入门到实战

本帖蚂蚁学Python之Pandas数据分析从入门到实战教程的笔记。

  1. 初始Pandas
  2. 读取数据
  3. 数据结构
  4. 数据查询的5种方法
  5. Pandas新增数据列
  6. 数据统计函数
  7. 缺失值处理
  8. SettingsCopyWarning报警
  9. 排序
  10. 字符串处理
  11. 理解axis
  12. index用途
  13. Merge
  14. Concat合并
  15. 批量拆分与合关Excel文件
  16. 分组数据统计
  17. 分层索引Multiindex
  18. map-apply-applymap数据处理
  19. groupby每个分组的apply
  20. 使用stack和pivot实现数据透视
  21. apply同时添加多列

[Home]

1 初始Pandas


  • 什么是Pandas

    • 一个Python的开源类库,用于数据分析、处理、和格式化;
    • 与其它类库配合使用,如Numpy, Scikt-learn。
  • 安装

    pip install pandas
    
  • 演示方式:jupyter notebook


[Home] Top]

[Home]

2 读取数据


[Home] [Top]

[Home]

3 数据结构: DataFrame和Series

1. Series

  • 一维数组对象,由一组数据(可以为不同类型)和一组相对应的数据标签(即索引)组成。

  • 创建方法pd.Series

    • 用一个列表,及一个相对应的索引列表(可选)
      s = pd.Series([1,2,'a',[1,2,3]], index=['a', 'b', 'c', 'd'])
      
    • 用一个字典,在创建值的同时,指定其索引
      dict_data = {'Ohio':35000,'Texas':72000,'Orgeon':16000,'Utah':5000}
      s= pd.Series(dict_data)
      
  • 由标签索引或索引列表查询数据

    s['a']
    s[['b','a']]
    

2. DataFrame

  • 表格型数据结构

    • 每列可以是不同的值类型
    • 即有行索引index,也有列索引columns
    • 可以视为由Series组成的字典
  • 创建方法pd.DataFrame

    • 最常用的方法是从纯文本文件 、Excel文件、MySQL数据库中读取;
    • 由多个字典序列创建,index可选,字典的键即为columns
      dictdata = { 
             'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Neveda'],
             'year': [2000, 2001, 2002, 2001, 2002],
             'pop': [1.5,1.7,3.6,4.3,9]
      }
      df = pd.DataFrame(dictdata, index=[1,2,3,4])
      
  • 查询数据

    • 如果只查询一列,返回的是pd.Series
    • 如果查询多行、多列,返回的是pd.DataFrame
      df['year']
      df[['year', 'pop']]
      df.loc[1]
      # 注意pandas中的切片是包含末尾指标的,这一点不同于Python
      df.loc[1:3]  
      

[Home] [Top]

[Home]

4 数据查询的5种方法

Pandas主要查询方法中,本节主要讲述.loc方法。

  • df.loc方法,根据行、列标签值查询(既能查询数据,又能覆盖写入,强烈推荐!)
  • df.iloc方法,根据行、列的数字位置查询
  • df.where方法
  • df.query方法

1. 使用单个label值查询数据

# 得到单个值
df.loc["2018-01-03", "bWendu"]
# 得到Series
df.loc["2018-01-03", ["bWendu", "yWendu"]]

2. 使用值列表批量查询

    ```
   df.loc[["2018-01-03","2018-01-05"], "bWendu"]
    ```

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

# 既包含开始,也包含结束
# 行index按区间
df.loc["2018-01-03": "2018-01-05", "bWendu"]
# 列index按区间
df.loc["2018-01-03", "bWendu":"fengxiang"]

4. 使用条件表达式查询

# 选出低于10度的记录
df.loc[df["yWendu"]<10,:]

5. 调用函数查询

# lamda函数
df.loc[lamda df : (df["bWendu"]<=30) & (df["yWndu"] > =15), :]
# 外部定义函数
def query_my_data(df):
    ...
df.loc[query_my_data,:]

  • 相关链接

[Home] [Top]

[Home]

5 Pandas新增数据列

1. 直接赋值

# "wencha"列原来是不存在
df.loc[:,"wencha"] = df["bWendu"] - df["yWndu"] 

2. df.apply方法

Apply a function along an axis of the DatatFrame.

Objects passed to the fuction are Series objects whose index is either the DataFrame’s index(axis=0) or the DataFrame’s columns (axis=1).

# 定义函数
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)

3. df.assign方法

同时新增多个列。

Assign new columns to a DataFrame.
Rerturn 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"]="温差正常“ 

[Home] [Top]

[Home]

6 数据统计函数

1. 汇总类统计

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

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

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

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

2. 唯一去重和按值计数

# 列出包含的值(去掉重复的值)
df['fengxiang'].unique()
# 列出各值出现的次数
df['fengxiang'].value_counts()

3. 相关系数和协方差

  • 协方差,表两个向量间的同向或反向程度
  • 相关系数,表两个向量间的相似程度
df.cov()
df.corr()

df['aqi'].corr(df['bWendu'])

[Home] [Top]

Home

7 缺失值处理

  • 场景:对于没有规则的数据做清洁和整理

    • 表格空行、空列
    • 表格有合并
    • 数据有缺失
  • 处理前后对比

  • Pandas处理缺失值有3类函数

    • isnullnotnull:检测是否为空值,可用于dataframe和series;
    • dropna:丢弃、删除缺失值
      • axis:删除还是行还是列,(0 or ‘index’, 1 or ‘columns’, 默认0);
      • how:如果等于any则任何值为空都删除,如果等于all则所有值为空才删除;
      • inplace:如果为True则修改当关df,否则返回新的df;
    • fillna:填充空值
      • value:用于填充的值,可以是单个值,或者字典
      • method:ffill(以前面的非空值填充)、bfill(以后面的非空值填充);
      • inplace:True修改当前df,False返回新的df。
    # 筛选出分类不为空的行
    studf.loc[studf['分类'].notnull(), :]
    
    # 删除掉空列和空行
    studf.dropna(axis="columns", how="all", inplace=True)
    studf.dropna(axis="index", how="all", inplace=True)
    
    # 将分数列为空的值填充为0 
    studf.fillna({"分数": 0})
    studf.loc[:, '分数'] = studf['分数'].fillna(0)
    
    # 将姓名的缺失值填弃
    studf.loc[:, '姓名'] = studf['姓名'].fillna(method='ffill')
    
    # 存成Excel表,不留存索引列
    studf.to_excel(..., index=False)
    

[Home] [Top]

[Home]

8 SettingsCopyWarning报警

  • Warning raised when trying to set on a copied slice from a DataFrame .

  • 核心要决:pandas的dataframe修改操作,只允许在源dataframe上进行,不得在copy上操作。

  • 复现

    condition = df['ymd'].str.startwith('20198-03']
    df[condtion]['wen_cha']=df['bWendu']-df['yWendu']
    # 产生SettingsCopyWarning报警
    
  • 原因

    df[condtion]['wen_cha']相关于先get后set,此时get得到的是一个copy,而非一个view,则set时就会报警。pandas不允许在copy上进行修改。

  • 修改

    df.loc[condition, 'wen_cha'] = df['bWendu']- df['yWendu']
    
  • 总结

    • pandas不允许先筛选子dataframe,再进行修改写入。即不能先get,再set。
    • 只能一次到位。

[Home] [Top]

[Home]

9 数据排序

1.Series的排序

用法:Series.sort_values(ascending=True,inplace=False)

  • asceding:默认True为升序排列,False为降序排列;
  • inplace:是否修改为原始Series;
# 数字Series的升序排列
df["aqi"].sort_values()
# 数字Series的降序排列
df["aqi"].sort_values(ascending=False)
# 除对数字排序外还可对中文的Series列进行排序
df["tianqi"].sort_values()

2.DataFrame的排序

用法:DataFrame.sort_values(ascending=True,inplace=False)

  • by:可以是单列排序和多列排序,亦可以是字符串或者List<字符串>;
  • asceding:bool或List,升序还是降序,其中List对应by的多列;
  • inplace:是否修改为原始DataFrame;
  1. 单列排序

    # 对单个列进行升序
    df.sort_value(by="aqi")
    # 对单个列进行降序
    df.sort_values(by="aqi",ascending=False)
    
  2. 多列排序

    # 按照空气质量等级、最高温度升序排列
    df.sort_values(by=["aqiLevel","bWendu"])
    # 按照空气质量等级、最高温度降序排列
    df.sort_values(by=["aqiLevel","bWendu"],ascending=False)
    # 分别对空气质量等级、最高温度指定升序排列或者降序排列
    df.sort_values(by=["aqiLevel","bWendu"],ascending=[Ture,False])
    

[Home] [Top]

Home

10 字符串处理

1.获取serise的str属性,使用各种字符串处理函数

# 获取erise的str属性
df["bWendu"].str
# 字符串替换函数
df["bWendu"].str.replace("C","")
# 判断是否为数字
df["bWendu"].str.isnumberic()

2.获取str属性用于bool条件查询

# 获取erise的str属性
condition=df["ymd"].str.startswith("2018-03")
df[condition].head()

3.简化多次str处理方法

# slice是切片语法
df["ymd"].str.replace("-","").str.slice[0:6]

4.正则表达式处理

# 添加新列
def get_nisnyueri(X):
   year,month,day = X["ymd"].split("-")
   return f"{year}年{month}月{day}日"
df["中文日期"] = df.apply(get_nianyueri,axis=1)
#去除插入列的文字
# 方法1:链式replace
df["中文日期"] .str.replace("年","") .str.replace("月","").str.replace("日","")
# 方法2:正则表达式替换
df["中文日期"] .str.replace("[年月日"],"")

[Home] [Top]

Home

11 理解axis

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

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

# 案例数据
df = pd.DataFrame(
np.arange(12).reshape(3,4),
columns = ["A","B","C","D"]
)

1.单列drop,就是删除某一列

# 删除某一列
df.drop("A",axis = 1)

2.单列drop,就是删除某一行

# 删除某一行
df.drop(1,axis = 0)

3.按axis=0/index执行mean聚合操作(注意:输出每列的结果)

# axis = 0或axis = index
df.mean(axis = 0)

4.按axis=1/columns执行mean聚合操作(注意:输出每行的结果)

# axis = 1或axis = columns
df.mean(axis = 1)

5.增加列等于其他四列的和

# 增加列=其他四列的和
def get_sum_value(x):
return x["A"]+x["B"]+x["C"]+x["D"]
df["sum__value"] = df.apply(get_sum_value,axis = 1)

[Home] [Top]

Home

12 index用途

1.查询数据

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

2.提升查询性能

  • 如果index是唯一的,pandas使用哈希表优化,查询性能为O(1);
  • 如果index不是唯一的,但是有序的,pandas使用二分法查找,查询性能为O(logN);
  • 如果index是完全随机的,每次查询需要全表搜索,查询性能为O(N);
# 使用index排序后的查询
df_sorted = df_shuffile.sort_index(4)

3.自动对齐数据

# 对齐数据
s1=pd.Series([1,2,3],index=list("abc"))
s2=pd.Series([2,3,4],index=list("bcd"))
s1+s2

4.强大的数据结构支持

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

[Home] [Top]

[Home]

13 Merge

1.数量的对齐关系

  • 一对一关系的merge
pd.merge (left,right,on='sno')
  • 一对多关系的merge
# 数目以多的一边为准(数量会被复制)
pd.merge (left,right,on='sno')
  • 多对多关系的merge
# 数目以多的一边为准(数量会出现乘法)
pd.merge (left,right,on='sno')

2.left、right、inner、outer join的区别

# 左、右边都有key则出现在结果里
pd.merge (left,right,bow='inner')
# 左边的key输出结果,右边无法匹配则为Null
pd.merge (left,right,bow='left')
# 右边的key输出结果,左边无法匹配则为Null
pd.merge (left,right,bow='right')
# 左边、右边都出现结果,如果无法匹配则为Null
pd.merge (left,right,bow='outer')

3.非key字段重名

# 左边、右边都出现结果,如果无法匹配则为Null
pd.merge (left,right,on='key')
#或者自己指定后缀
pd.merge (left,right,on='key',suffixes=('_left','_right'))

[Home] [Top]

[Home]

14 Concat合并

1.pandas.concat合并数据

pd.concat([df1,df2])

# ignore_index=True(忽略)
pd.concat([df1,df2],ignore_index=True)

# join=inner(过滤)
pd.concat([df1,df2],ignore_index=True,join="inner")

# 添加一列Series
s1=pd.series(list(range(4)),name="F")
pd.concat([df1,s1,axis=1)

# 添加多列Series
s2=df1.apply(lambda x:x["A"]+"_GG",axis=1)

# 列表只有series
pd.concat([s1,s2],axis=1)

# 列表混合顺序
pd.concat([s1,df1,s2],axis=1)

2.DataFrame.appent按行合并数据

# 给一个dataframe添加dataframe
df1 = append(df2)

# ignore_index=True(忽略)
df1.append(df2,ignore_index=True)

# 一行一行为ataframe添加数据
df=pd.DataFrame(columns=["A"])


[Home] [Top]

[Home]

15 批量拆分与合并Excel文件

1.大Excel文件等分拆多个Excel

  • 使用df.iloc方法,将一个大的dataframe拆分为多个小的文件
  • 使用dataframe_to_excel保存每个小的excel

2.合并多个Excel

  • 遍历文件夹,合并想要Excel文件列表
  • 读取dataframe,给每个df添加一列用于标记来源
  • 使用pd.concat进行合并
  • 将合并文件输出到Excel

[Home] [Top]

[Home]

16 分组数据处理

1.使用聚合函数统计数据

#单个列groupby查询数据统计
df.groupby("A").sum()
#多个列groupby查询数据统计
df.groupby(["A","B"]).as_index=False)mean()
# 同时查看多种数据统计
df.groupby("A").agg([np.sum,np.mean,np.std])
# 查看单列统计结果
df.groupby("A").agg([np.sum,np.mean,np.std])["C"]
# 不同列使用不同聚合函数
df.groupby("A").agg(["C":np.sum,"D":np.mean])

2.遍历groupby理解执行流程

# 遍历单个分组数据
g=df.groupby("A")
# 遍历多个列聚合分组
g=df.groupby(["A","B"])
# 查询group某几列生成series或者dataframe
g["C"]

[Home] [Top]

[Home]

17 分层索引Multiindex

1.series的分层索引MultiIndex

ser.reset_index()

2.series多层索引筛选数据

# 第一层索引
ser.loc["BAIDU"]
# 多层索引,用元组形式筛选
ser.loc[("BAIDU","2019-10")]
# 筛选第二层索引
ser.loc[(:,"2019-10")]

3.DataFramed 多层索引MultiIndex

stocks.sort_index(inplace = True)
stocks

4.DataFramed 多层索引筛选数据

  • 元组(key1/key2)代表筛选多层索引,其中key1索引第一层,key2索引第二层
  • 列表(key1/key2)代表同一层的多个key,其中key1和key2是并列的同级索引
stocks.loc[(slice(None),["2019-10-02","2019-10-03"]),:]

[Home] [Top]

[Home]

18 map-apply-applymap数据处理

  • map:只用于Series,实现每个值-值的映射
  • apply:用于Series实现每个值的处理,用于DataFrame实现某个轴的Series的处理
  • applymap:只能用于DataFrame,用于处理DataFrame的每个元素

1.map用于Series值的转换

# 使用字典映射或者函数映射
Series.map(dict)或者Series.map(function)
#以将股票代码英文转换为中文名字为例
#使用dict
stocks["公司中文1"] = stocks["公司"].str.lower().map(dict_company_names)
#使用函function
stocks["公司中文2"] = stocks["公司"].map(lambda x:dict_company_names[x.lpwer()])

2.apply用于Series、DataFrame的转换

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

注意:

  • 1.apply在stocks这个DataFrame上调用;
  • 2.lambda x的x是Series,因为指定了axis=1;
# Series.apply(function)
stocks["公司中文3"] = stocks["公司"].apply(lambda x:dict_company_names[x.lpwer()])
# DataFrame.apply(function)
stocks["公司中文4"] = stocks.apply(lambda x:dict_company_names[x["公司"].lpwer()],axis=1)

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

# 将数值取整用于元素
sub_df.applymap(lambda x:int())
# 直接修改原df的几列
stocks.loc[:,['收盘','开盘','高','低']]= sub_df.applymap(lambda x :int(x))

[Home] [Top]

[Home]

19 groupby每个分组的apply

  • function的第一个参数是dataframe
  • function返回结果可以是dataframe、series、单个值或者与输入dataframe完全没关系

1.按照分组将数值归一化

归一化的定义:

def_ratings_norm(df):
  min_value = df["Rating"].min()
  max_value = df["Rating"].max()
  df["Rating_norm"] = df["Rating"].apply(lambda x : (x-min_value)/(max_value-min_value))
  return df
Ratings = Ratings.groupby("UserID").apply(Ratings_norm)
Ratings[Ratings["UserID"].head]()

2.提取每组TOPN数据

# 获取某年每个月温度最高的2天数据
def getWenduTopN(df,topn)
# df指每个月份分组groupby的df
  return df.sort_values(by - "bWendu")[["ynd","bWendu"]][-topn:]
df.groupby("month").apply(getWenduTopN,topn = 2.head)

[Home] [Top]