Pandas数据分析从入门到实战

[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]

[Home]

20 使用stack和pivot实现数据透视

1.获取多维度指标数据

df_group = df.groupby([df["pdata"].dt.month,"Rating"])["UserID"].agg(pv = np.sum)
df_group.head(20)

2.unstack实现二维透视

df_stack = df_group.unstack()
# unstack与stack的互逆操作
df_stack.stack().head(20)

3.使用pivot简化透视

df_pivot = df_reset.pivot("pdata","Rating","pv")
#pivot方法相当于df使用set_index创建分层索引再调用unstack

4.stack\unstack\pivot使用语法

stack:

unstack:

pivot:


[Home] [Top]

[Home]

21 apply同时添加多列

如何方便启动jupyter中的notebook小知识:
首先打开目录(这个目录是数据和代码存放的位置),接着点路径位置所在的输入框,输入cmd,那么这个命令行就会再当前目录打开,打开终端的路径就是当前文件存放的路径,这个时候展现的内容就是刚才文件夹内的所有内容了。

# 同时添加多列数据
def_my_fun(row):
 return row["bWendu"]-row["yWendu"],(row["bWendu"]+row["yWendu"])/2
df[["wencha","avg"]] = df.apply(my_func,axis = 1,result_type="expand")

[Home] [Top]