zoukankan      html  css  js  c++  java
  • pandas之DataFrame

    DataFrame


    DataFrame是一个【表格型】的数据结构,可以看做是【由Series组成的字典】(共用同一个索引)。DataFrame由按一定顺序排列的多列数据组成。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。
    行索引:index
    列索引:columns
    值:values(numpy的二维数组)
    1、DataFrame的创建

    最常用的方法是传递一个字典来创建。DataFrame以字典的键作为每一【列】的名称,以字典的值(一个数组)作为每一列。
    此外,DataFrame会自动加上每一行的索引(和Series一样)。
    同Series一样,若传入的列与字典的键不匹配,则相应的值为NaN。
    # 字典创建
    df1 = DataFrame({"Python":[99,98,89,97,88],
                   "Java":[56,75,46,86,39],
                   "C++":[98,54,76,45,84]},
                   index = list("abcde"),
                  columns = ["Python","Java","C++","PHP"])
    # index(列索引不能多也不能少)
    # columns(行索引可多可少:多的为NaN,少的不显示)
    DataFrame属性:values、columns、index、shape
    df1.values   -- 打印value值
    df1.columns  -- 打印列索引
    df1.shape    -- 打印形状
    df1.index    -- 打印行索引
    # ndarray对象创建
    df2 = DataFrame(data=np.random.randint(0,100,size=(5,4)),
                  index = list("abcde"),
                  columns = ["Python","Java","Html","PHP"])
    2、DataFrame的索引
    1对列进行索引
    1. 通过类似字典的方式
    2. 通过属性的方式
    可以将DataFrame的列获取为一个Series。返回的Series拥有原DataFrame相同的索引,且name属性也已经设置好了,就是相应的列名。
    df2.Python
    df2["Python"]  -- 这个方法比较常用(列表中可以传多个值,用逗号隔开)
    # 列不支持切片操作
    2对行进行索引
    1. 使用.loc[]加index来进行行索引
    2. 使用.iloc[]加整数来进行行索引
    同样返回一个Series,index为原来的columns。
    # 行索引不支持直接使用中括号(即df2[]是错误的写法)
    df2.loc["a"] df2.iloc[0] -- 这两种方法(使用一个中括号)得到的是Series对象
    df2.loc[["a"]] df2.iloc[[0]] -- 使用两个中括号得到的是DataFrame对象
     -- 可以传多个值,用逗号隔开
    df2.loc["a":"c"] -- 闭区间(左闭右闭)
    df2.iloc[0:3] -- 左开右闭区间
    3对元素索引的方法
    1. 使用列索引
    2. 使用行索引(iloc[3,1]相当于两个参数;iloc[[3,3]] 里面的[3,3]看做一个参数)
    3. 使用values属性(二维numpy数组)
    df2["Python"]["c"]     -- 先列索引,后行索引
    df2.loc["c"]["Python"] -- 先行索引,后列索引
    # 【注意】 直接用中括号时:
       索引表示的是列索引
       切片表示的是行切片
    3、DataFrame的运算

    1DataFrame之间的运算
    同Series一样:
    在运算中自动对齐不同索引的数据
    如果索引不对应,则补NaN
       df1+df2 df1.add(df2, fill_value=0)
    Html Java Python Ruby 数学 英语 语文 Html Java Python Ruby 数学 英语 语文
    a NaN NaN 131 NaN NaN NaN NaN     a 121.0 132.0 131 125.0 120.0 NaN 123.0
    b NaN NaN 235 NaN NaN NaN NaN      b 1.0 123.0 235 48.0 136.0 NaN 114.0
    c NaN NaN 228 NaN NaN NaN NaN      c 130.0 77.0 228 29.0 141.0 NaN 130.0
    d NaN NaN 130 NaN NaN NaN NaN      d 18.0 88.0 130 33.0 129.0 NaN 117.0
     
    2Series与DataFrame之间的运算
    使用Python操作符:以行为单位操作(参数必须是行),对所有行都有效。(类似于numpy中二维数组与一维数组的运算,但可能出现NaN)
    使用pandas操作函数:
    axis=0:以列为单位操作(参数必须是列),对所有列都有效。
    axis=1:以行为单位操作(参数必须是行),对所有行都有效。
    df2  ----> DataFrame对象
    s_row = df2.loc["c"] ---- Series对象
    s_column = df2["Python"] ---- Series对象
    df2.add(s_row) ---- df2对象每一列与s_row相加
    df2.add(s_column, axis="index") ---- df2对象每一行与s_column相加
    # axis参数,指定两者相加的方式,默认等于column

    丢失数据的处理

    分为两种: None np.nan(NaN)

    None

    numpy中:
       type(None) ---- NoneType
       None是Python自带的,其类型为python object。因此,### None不能参与到任何计算中。
       object类型的运算要比int类型的运算慢得多
       计算不同数据类型求和时间
       %timeit np.arange(1e5,dtype=xxx).sum()

       %timeit np.arange(1e6, dtype = int).sum()
       3.21 ms ± 1.01 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
       %timeit np.arange(1e6, dtype = float).sum()
       6.89 ms ± 1.3 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
       %timeit np.arange(1e6, dtype = object).sum()
       89.3 ms ± 9.79 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    pands中:
    pandas中将None视作np.nan
    np.nan(NaN)

    numpy中:
       np.nan是浮点类型,能参与到计算中。但计算的结果总是NaN。
       但可以使用np.nan*()函数来计算nan,此时视nan为0
       nd = np.array([10,20,30,np.nan])
       np.nansum(nd) ----> 60.0    # 将nan视为0
    pandas中:
    pandas中None与np.nan都视作np.nan
    df = DataFrame([10,20,57,np.nan, None],index = list("abcde"), columns = ["Python"])
       df.sum() ----> 87.0
       df = DataFrame([[10,20,57,np.nan,None],
                  [22,33,56,12,None],
                  [np.nan,1,2,3,4]], index = list("abc"),
                 columns = ["Python","Java","数学","物理","H5"])
       df.sum(axis=1) ----> 求每一行的和
    pandas中None与np.nan操作

    判断函数:
    isnull():数据是否为空
    notnull():数据是否不为空
    #DataFrame的isnull函数返回的是和之前一模一样的结构,且为boolean类型,不为空的False 为空的True
    isnull().any() -- 判断行或列中的数据是否有空值,有返回True,没有返回False
    notnull().all() -- 判断行或列的数据是否全不为空,是返回True,否则返回False
    用法:
    df = DataFrame([[10,20,57,np.nan,None],
                  [22,33,56,12,None],
                  [np.nan,1,2,3,4]], index = list("abc"),
                 columns = ["Python","Java","数学","物理","H5"])
       df2 = DataFrame([[10,20,57,90,20],
                  [22,33,56,12,80],
                  [100,1,2,3,4]], index = list("efg"),
                 columns = ["Python","Java","数学","物理","H5"])
       df3 = df.add(df2, fill_value=0) ---- df+df2
       df3_isnull = df3.isnull().any(axis = 1) ---- 判断df3每行是否有空值,返回Series类型
       df3[df3_isnull] ---- 把非空值的行过滤掉,留下含空值的行
    扩展:
    cond = (df3 >= 10).all(axis = 1)
       # 判断df3每一行数据是否全部都大于等于10,返回series类型对象,且值为布尔类型
       df3[cond] ---- 取出df3中值全部大于等于10的数据
    过滤函数:
       dropna(): 过滤丢失数据
       df3["H5"] = np.nan  ---- DataFrame的列索引,把“H5”列全部赋值为np.nan
       df3.dropna(axis = 1, how = "all") ---- 过滤掉值全为空的列
      axis :可以选择过滤的是行还是列(默认为行,axis=0
      也可以选择过滤的方式 how = 'all'
    填充函数:
       fillna(): 填充丢失数据
    df3.fillna(-1) ---- 将df3中为空的数据全部填充为-1
       df3.fillna(method="bfill") ---- 向后填充(用下一行的数据填充)
       df3.fillna(method="ffill") ---- 向前填充(用上一行的数据填充)
       df3.fillna(method="ffill",axis = 1) ---- 向右进行填充(用左边的数据填充)
       df3.fillna(method="bfill",axis = 1) ---- 向左进行填充(用右边的数据填充)
       # method:可以选择前向填充还是后向填充
       # 对于DataFrame来说,还要选择填充的轴axis;axis=0:index/行;axis=1:columns/列

    pandas层次化索引

    创建多层行索引

    1隐式构造
    最常见的方法是给DataFrame构造函数的index参数传递两个或更多的数组
    Series也可以创建多层索引
    s = Series(data = [1,2,3,"a"],
             index = [["a","a","b","b"],["期中","期末","期中","期末"]])
    DataFrame:
    # 二层索引
    df = DataFrame(data = [1,2,3,"a"],
                  index = [["a","a","b","b"],["期中","期末","期中","期末"]],
                 columns = ["Python"])
       # 三层索引
       df = DataFrame(data = np.random.randint(0,150,size = 8),
                 index = [['a',"a","a","a","b","b","b","b"],
                          ['期中',"期中","期末","期末",'期中',"期中","期末","期末"],
                          ["一单元","二单元","一单元","二单元","一单元","二单元","一单元","二单元"]],
                 columns = ["Python"])
    2显示构造 pd.MultiIndex
       1. 使用数组
       df1 = DataFrame(data = np.random.randint(0,150,size = (8,4)),
                  index = pd.MultiIndex.from_arrays([['a',"a","a","a","b","b","b","b"],
                          ['期中',"期中","期末","期末",'期中',"期中","期末","期末"],
                          ["一单元","二单元","一单元","二单元","一单元","二单元","一单元","二单元"]]),
                  columns = ["Python","h5","php","go"])
       2. 使用tuple
       df3 = DataFrame(np.random.randint(0,150,size = 4),
                   index = pd.MultiIndex.from_tuples([("a",1),("a",2),("b",1),("b",2)]),
                  columns = ["Python"])
       3. 使用product  ---- 最简单,推荐使用
       df4 = DataFrame(np.random.randint(0,150,size = (8,2)),
                   index = pd.MultiIndex.from_product([list("abcd"), ["期中","期末"]]),
                  columns = ['Python',"数学"])
    多层列索引

    除了行索引index,列索引columns也能用同样的方法创建多层索引
    df = DataFrame(data = np.random.randint(0,150,size = (1,8)),
                 columns = [['a',"a","a","a","b","b","b","b"],
                          ['期中',"期中","期末","期末",'期中',"期中","期末","期末"],
                          ["一单元","二单元","一单元","二单元","一单元","二单元","一单元","二单元"]],
                 index = ["Python"])
    多层索引对象的索引与切片操作

    1Series的操作
    # 对于Series来说,直接中括号[]与使用.loc()完全一样,因此,推荐使用中括号索引和切片。
    s = Series(data=[1,2,3,"a"], index = [["a","a","b","b"],["期中","期末","期中","期末"]])
    1. 索引
       s["a"]["期末"] s["a","期末"] ---- 效果相同
       2. 切片
       s["a":"b"] ---- 得到整个对象
       s["期中":"期末"] ---- 空的对象  
       # 这两种方法得到的对象不精确,不推荐使用
       s.iloc[0:3] ---- 隐式索引切片
       # 把所有的数据放到一块进行切片,得到的数据比较精确 推荐使用
    2DataFrame的操作
    (1) 可以直接使用列名称来进行列索引
    (2) 使用行索引需要用ix(),loc()等函数
    【极其重要】推荐使用loc()函数
    # 注意: 在对行索引的时候,若一级行索引还有多个,对二级行索引会遇到问题!也就是说,无法直接对二级索引进行索引,必须让二级索引变成一级索引后才能对其进行索引!
    df4 = DataFrame(np.random.randint(0,150,size = (8,2)),
                   index = pd.MultiIndex.from_product([list("abcd"), ["期中","期末"]]),
                  columns = ['Python',"数学"])
    df4["Python"]["a","期末"] ---- 先列索引,再行索引
    df4.loc["a"].loc["期末"]["Python"] ---- 先行索引,再列索引
    # 在索引取值的时候,一定要注意数据的类型

    索引的堆


    unstack():行索引变列索引
    df4.unstack() ---- 把第二层的行索引变成列索引
    df4.unstack(level=1) ---- 把第二层的行索引变成列索引
    df1.unstack(level = 1) ---- 把df1的第二层行索引变为列索引
    # 【小技巧】使用unstack()的时候,level等于哪一个,哪一个就消失,出现在列里。
    stack(): 列索引变行索引
    df.stack(level=1) ---- 把df的第二层列索引变成行索引
    df.stack(level=(0,2)) ---- 把df的第一层、第三层列索引放到行索引上面
    # 【小技巧】使用stack()的时候,level等于哪一个,哪一个就消失,出现在行里。
    # level索引的下标(从0开始计数)最外层为0,第二层为1,以此类推

    聚合操作


    【注意】需要指定axis
    【小技巧】和unstack()相反,聚合的时候,axis等于哪一个,哪一个就保留。
    所谓的聚合操作:平均数,方差,最大值,最小值……
    df4.div(10, axis = "index") ---- df4的数据除10
    df4.sum(axis = 1) ---- 按行求和
    df4.std() ---- df4的标准差

    pandas的拼接操作


    pandas的拼接分为两种:
    级联:pd.concat, pd.append
    合并:pd.merge, pd.join
    使用pd.concat()级联

    pandas使用pd.concat函数,与np.concatenate函数类似,只是多了一些参数:
    pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False,
             keys=None, levels=None, names=None, verify_integrity=False,
             copy=True) ---- 常用
    # axis:轴,拼接方向,默认为行拼接
    # ignore_index:是否忽视索引,默认不忽视
    # keys:是否使用多层索引,默认不使用
    # join:连接方式,默认为外链接;join=“inner”时内连接
    # join_axes:连接指定轴

    # 定义生成DataFrame的函数
    def make_df(cols, inds):
       #data: a,{a:[a1,a2,a3],b:[b1,b2,b3],c:[c1,c2,c3]}
       data = {c:[c+str(i) for i in inds] for c in cols}
       return DataFrame(data, index = inds)
    df1 = make_df(list("abc"), [1,2,3])
    df2 = make_df(list('abc'), [4,5,6])
    df3 = make_df(list("def"), [1,2,3])
    df4 = make_df(list("abc"), [2,3,4])
    df5 = make_df(list("abcd"), [3,4,5,6])
    df6 = make_df(list("abcz"), [3,4,7,8])
    1简单级联
       pd.concat([df1,df2],axis=0) ---- 行拼接(行数增加)
       pd.concat([df1,df2],axis=1) ---- 列拼接(列数增加)
       # 在行上面进行级联的时候,最好列相同,才不会出现空值  
       # 在列上面进行级联的时候,最好行相同,才不会出现空值
    pd.concat([df1,df4], ignore_index=True) ---- 忽视索引,并重新索引
       pd.concat([df1,df4], keys = ["一班","二班"]) ---- 使用多层索引
    2不匹配级联
    有三种连接方式:外链接、内连接、指定轴连接
       不匹配指的是级联的维度的索引不一致。例如纵向级联时列索引不一致,横向级联时行索引不一致
    pd.concat([df1,df5], join = "outer") ---- 外链接(没有的会补NaN)
       # 外链接,两个表的都要
       pd.concat([df1,df5], join = "inner") ---- 内连接
       # 内连接,只取两个表共有的字段数据
       pd.concat([df1,df2,df5,df6],join_axes=[df6.columns]) ---- 以df6的列为连接轴
       # 指定轴连接,只显示已指定的轴,其他的不显示, 没有数据的补NaN
    3使用append()函数添加 -- 不常用
    由于在后面级联的使用非常普遍,因此有一个函数append专门用于在后面添加
       df5.append(df1) ---- 在df5后面拼接df1,空字段补NaN
    使用pd.merge()合并

    merge与concat的区别在于,merge需要依据某一共同的行或列来进行合并
    使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并。
    注意每一列元素的顺序不要求一致
    1一对一合并
    df1 = DataFrame({"age":[30,22,36],
                   "work":["tech","accounting","sell"],
                   "sex":["男","女","女"]}, index = list("abc"))
    df2 = DataFrame({"home":["上海","安徽","山东"],
                   "work":["tech","accounting","sell"],
                   "weight":[60,50,55]}, index = list("abc"))
    pd.concat([df1, df2],axis = 1)
    2多对一合并  ----常用
    df3 = DataFrame({"home":['深圳',"北京","上海","安徽","山东"],
                   "work":["tech","tech","tech","accounting","sell"],
                   "weight":[60,75,80,50,55]}, index = list("abcde"))
    df1.merge(df3)
    # 会根据相同的列,如tech,得到1*3个数据
    3多对多合并  ---- 很少用
    df5 = DataFrame({"age":[28,30,22,36],
                   "work":['tech',"tech","accounting","sell"],
                   "sex":["女","男","女","女"]}, index = list("abcd"))
    df3.merge(df5)
    # 会根据相同的列,如tech,得到3*2个数据
    4、key的规范化
     1. 使用on=显式指定哪一列为key,当有多个key相同时使用
     df6 = DataFrame({'age':[30,22,37],
                   "work":['tech',"leader","sell"],
                   "hobby":["sixdog","playcat","diaofish"]},
                  index = list("abc"))
     df5.merge(df6, on = "age",suffixes=["_总部","_分部"])
     # on: 用来指定以那一列为主; suffixes:指定后缀名,用以区分
     # 当列冲突时,即有多个列名称相同时,需要使用on=来指定哪一个列作为key,配合suffixes指定冲突列名   可以使用suffixes=自己指定后缀
     2. 使用left_on和right_on指定左右两边的列作为key,当左右两边的key都不想等时使用
     df7 = DataFrame({"年龄":[30,22,36],
                   "工作":['tech',"accounting","sell"],
                   "性别":["男","女","女"]}, index = list("abc"))
     df5.merge(df7, left_on="work",right_on="工作") ---- 这个很重要
     # left_on:指定左边(df5)的连接键; right_on:指定右边(df7)的连接键;以两个键来拼接

    以原有的列新建一列
       s = df5[["age"]]*1000 ---- 更改“age”列数值,并赋给s
       s.columns = ["salary"] ---- 重命名
       pd.concat([df5,s], axis = 1) ---- 使用concat新建一列
       df5.merge(s, left_index=True, right_index=True) ---- 使用合并新建一列
       # left_index(df5)和right_index(s) 如果为True的话,就以行索引进行合并
    5内合并与外合并
    内合并:只保留两者都有的key(默认模式)
    df3.merge(df6, how = "inner")
    外合并 how='outer':补NaN
    df3.merge(df6, how = "outer")
       # how: 指定合并方式,默认为内合并
    左合并 how='left'
       df3.merge(df6, how = "left")
       # 左合并以左边为主, 左边的数据宁愿为空值也不能丢失, 右边的可以
    右合并 how='right'
    df3.merge(df6, how = "right")
       # 以右边的为主
     
    参数说明:
    left与right:两个不同的DataFrame
    how:指的是合并(连接)的方式有inner(内连接),left(左外连接),right(右外连接),outer(全外连接);默认为inner
    on : 指的是用于连接的列索引名称。必须存在右右两个DataFrame对象中,如果没有指定且其他参数也未指定则以两个DataFrame的列名交集做为连接键
    left_on:左则DataFrame中用作连接键的列名;这个参数中左右列名不相同,但代表的含义相同时非常有用。
    right_on:右则DataFrame中用作 连接键的列名
    left_index:使用左则DataFrame中的行索引做为连接键
    right_index:使用右则DataFrame中的行索引做为连接键
    sort:默认为True,将合并的数据进行排序。在大多数情况下设置为False可以提高性能
    suffixes:字符串值组成的元组,用于指定当左右DataFrame存在相同列名时在列名后面附加的后缀名称,默认为('_x','_y')
    案例补充扩展

    案例:美国各州人口数据分析(具体操作见jupyter day04)


    删除指定列:drop()
    例:pop2.drop("abbreviation", axis = 1, inplace=True)
       # axis: 指定轴(axis=0,对行操作; axis=1,对列操作)
       # inplace: 是否在原对象上操作,默认为False,不改变原数据;inplace=True,在原对象上修改
    去重操作:unique()
    例:pop2[cond_state]["state/region"].unique()

    pandas数据处理

    删除重复元素

    duplicated()
    使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象,每个元素对应一行,如果该行不是第一次出现,则元素为True
    df = DataFrame({"color":["red","pink","red","green"], "size":[10,20,10,30]})
    df.duplicated()
    使用drop_duplicates()函数删除重复的行
    df.drop_duplicates()
    映射

    映射的含义:创建一个映射关系列表,把values元素和一个特定的标签或者字符串绑定
    需要使用字典:
    map = {
       'label1':'value1',
       'label2':'value2',
      ...
      }
    包含三种操作:
    replace()函数:替换元素
    最重要:map()函数:新建一列
    rename()函数:替换索引
    1replace()函数:替换元素
    使用replace()函数,对values进行替换操作
       首先定义一个字典:color = {'red':10, "green":20}
       调用.replace():df.replace(color, inplace=True)
       # inplace:是否修改原对象,默认为False,不修改原对象
       replace还经常用来替换NaN元素
       例:  df.loc[1] = np.nan
             v ={np.nan:40}
    df.replace(v)
    2map()函数:新建一列
     1. 使用map()函数,由已有的列生成一个新列
    适合处理某一单独的列。
    df = DataFrame(np.random.randint(0,150,size = (4,4)),columns =["Python","Java","PHP","HTML"],index = ["张三","旭日","阳刚","木兰"])
       仍然是新建一个字典
       v = {36:37,54:105,117:108,144:124}
       df["Go"] = df["Python"].map(v) -- 利用python列新建Go列
     2. map()函数中可以使用lambda函数
       df["C"] = df["Go"].map(lambda x: x-10)
     3. map()函数还可以传 一个回调函数
       def mp(x):
      #复杂的条件
      if x < 51:
          return "不及格"
      else:
          return "优秀"
       df["score"] = df["C"].map(mp)
    3transform()
    transform()用法和map()类似

    rename()函数:替换索引
    def cols(x):
       if x == "Python":
           return "大蟒蛇"
       if x == "PHP":
           return "php"
       else:
           return x
    df.rename(columns=cols) ----传回调函数
    inds = {"张三":"Zhang sir","木兰":"Miss hua"}
    df.rename(index=inds) ---- 传字典
  • 相关阅读:
    01_根据Id查询User的数据
    rest_framework常用设置
    django AnonymousUser
    获取视频时长和文件大小
    xadmin增加用户 除了账号和密码 添加其他信息
    Django 重写用户模型
    xadmin 常见错误
    Django在根据models生成数据库表时报 __init__() missing 1 required positional argument: 'on_delete'
    xadmin设置
    python3安装xadmin出现 UnicodeDecodeError: 'gbk' codec can't decode byte 0xa4 in position 3444: illegal multibyte sequence
  • 原文地址:https://www.cnblogs.com/fansirs/p/13944530.html
Copyright © 2011-2022 走看看