美文网首页Python
Python 数据处理(四)——DataFrame

Python 数据处理(四)——DataFrame

作者: 名本无名 | 来源:发表于2021-02-05 21:25 被阅读0次

    2. DataFrame

    DataFrame 数二维带标签的数据结构,每列可以是不同的数据类型,你可以把它想象成一个 excel 表格或 SQL 表,或者是由 Series 对象构成的字典。

    DataFrame 是我们最常用的对象,它也支持多种类型的输入数据

    • 一维数组字典,列表、字典或 Series
    • 二维数组
    • 结构化数组或记录数组
    • Series
    • 其他 DataFrame

    除了传入数据,也可以同时指定数据的索引(index)和列名(columns)。如果输入数据是字典类型的 Series 且带有索引,那么会将与指定索引不匹配的数据删除

    如果没有设置轴标签,则按常规数据解析构建索引和列名

    注意:与前面提到的从字典构建 Series 对象类似,在 Python > = 3.6,且 Pandas > = 0.23 时,当输入数据是字典,且未指定 columns 参数时,DataFrame 的列按字典的插入顺序排序。其他版本会按照字典键的字母顺序对列排序

    值为 Series 的字典

    Series 字典构建 DataFrame 其生成的索引是各个 Series 索引的并集。如果存在嵌套的字典,会先把嵌套字典转换为 Series。如果未指定列名,会将字典的键作为列名

    In [37]: d = {'one': pd.Series([1., 2., 3.], index=['a', 'b', 'c']),
       ...:      'two': pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])
       ...:     }
    
    In [38]: df = pd.DataFrame(d)
    
    In [39]: df
    Out[40]: 
       one  two
    a  1.0  1.0
    b  2.0  2.0
    c  3.0  3.0
    d  NaN  4.0
    
    In [40]: pd.DataFrame(d, index=["d", "b", "a"])
    Out[40]: 
       one  two
    d  NaN  4.0
    b  2.0  2.0
    a  1.0  1.0
    
    In [41]: pd.DataFrame(d, index=["d", "b", "a"], columns=["two", "three"])
    Out[41]: 
       two three
    d  4.0   NaN
    b  2.0   NaN
    a  1.0   NaN
    

    可以使用成员属性 indexcolumns 访问索引和列名

    In [42]: df.index
    Out[42]: Index(['a', 'b', 'c', 'd'], dtype='object')
    
    In [43]: df.columns
    Out[43]: Index(['one', 'two'], dtype='object')
    

    注意:如果设置了列名参数,会覆盖原本字典的键

    值为数组/列表的字典

    字典里的每个数组长度必须一致,如果指定了索引参数,那么索引的长度必须与数组长度一致。如果未指定索引,默认会将 range(n) 作为索引,n 为数组长度

    In [44]: d = {"one": [1.0, 2.0, 3.0, 4.0], "two": [4.0, 3.0, 2.0, 1.0]}
    
    In [45]: pd.DataFrame(d)
    Out[45]: 
       one  two
    0  1.0  4.0
    1  2.0  3.0
    2  3.0  2.0
    3  4.0  1.0
    
    In [46]: pd.DataFrame(d, index=["a", "b", "c", "d"])
    Out[46]: 
       one  two
    a  1.0  4.0
    b  2.0  3.0
    c  3.0  2.0
    d  4.0  1.0
    

    如果长度不一致,会抛出异常

    >>>pd.DataFrame(d, index=["a", "b", "c"])
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    ...
    
    结构化数组和记录型数组

    这种情况的处理方式与值为数组的字典一样

    In [47]: data = np.zeros((2,), dtype=[("A", "i4"), ("B", "f4"), ("C", "a10")])
    
    In [48]: data[:] = [(1, 2.0, "Hello"), (2, 3.0, "World")]
    
    In [49]: pd.DataFrame(data)
    Out[49]: 
       A    B         C
    0  1  2.0  b'Hello'
    1  2  3.0  b'World'
    
    In [50]: pd.DataFrame(data, index=["first", "second"])
    Out[50]: 
            A    B         C
    first   1  2.0  b'Hello'
    second  2  3.0  b'World'
    
    In [51]: pd.DataFrame(data, columns=["C", "A", "B"])
    Out[51]: 
              C  A    B
    0  b'Hello'  1  2.0
    1  b'World'  2  3.0
    

    注意DataFrame 的运作方式与二维 NumPy 数组是不一样的

    字典列表
    In [52]: data = [{"a": 1, "b": 2}, {"a": 5, "b": 10, "c": 20}]
    
    In [53]: pd.DataFrame(data)
    Out[53]: 
       a   b     c
    0  1   2   NaN
    1  5  10  20.0
    
    In [54]: pd.DataFrame(data, index=["first", "second"])
    Out[54]: 
            a   b     c
    first   1   2   NaN
    second  5  10  20.0
    
    In [55]: pd.DataFrame(data, columns=["a", "b"])
    Out[55]: 
       a   b
    0  1   2
    1  5  10
    
    元组型字典

    通过传递元组字典,可以自动创建多级索引

    In [56]: pd.DataFrame(
       ....:     {
       ....:         ("a", "b"): {("A", "B"): 1, ("A", "C"): 2},
       ....:         ("a", "a"): {("A", "C"): 3, ("A", "B"): 4},
       ....:         ("a", "c"): {("A", "B"): 5, ("A", "C"): 6},
       ....:         ("b", "a"): {("A", "C"): 7, ("A", "B"): 8},
       ....:         ("b", "b"): {("A", "D"): 9, ("A", "B"): 10},
       ....:     }
       ....: )
       ....: 
    Out[56]: 
           a              b      
           b    a    c    a     b
    A B  1.0  4.0  5.0  8.0  10.0
      C  2.0  3.0  6.0  7.0   NaN
      D  NaN  NaN  NaN  NaN   9.0
    
    Series

    Series 构建的 DataFrame 将会有同样的索引,如果未设置列名,默认将使用 Seriesname

    >>> s = pd.Series(np.random.randn(5), index=list('abcde'), name='something')
    
    >>> s
    
    a   -0.722865
    b    1.317593
    c   -1.843862
    d   -1.530197
    e    0.404915
    Name: something, dtype: float64
    
    >>> pd.DataFrame(s)
       something
    a  -0.722865
    b   1.317593
    c  -1.843862
    d  -1.530197
    e   0.404915
    
    命名元组列表

    DataFrame 的列数由列表中第一个 namedtuple 的字段名称确定,其余的命名元组(或元组)会被简单地解压缩,并填到新的行中

    如果其中任何一个元组比第一个命名的元组短,则相应的行中后面的列将标记为缺失值。如果存在长度超过第一个命名元组的元组,则会引发 ValueError

    In [57]: from collections import namedtuple
    
    In [58]: Point = namedtuple("Point", "x y")
    
    In [59]: pd.DataFrame([Point(0, 0), Point(0, 3), (2, 3)])
    Out[59]: 
       x  y
    0  0  0
    1  0  3
    2  2  3
    
    In [60]: Point3D = namedtuple("Point3D", "x y z")
    
    In [61]: pd.DataFrame([Point3D(0, 0, 0), Point3D(0, 3, 5), Point(2, 3)])
    Out[61]: 
       x  y    z
    0  0  0  0.0
    1  0  3  5.0
    2  2  3  NaN
    
    备选构造函数
    • DataFrame.from_dict

    DataFrame.from_dict 接收嵌套字典或数组序列的字典,并生成 DataFrame

    其中 orient 参数默认为 columns,该构建器的操作与 DataFrame 构建器类似。

    In [65]: pd.DataFrame.from_dict(dict([("A", [1, 2, 3]), ("B", [4, 5, 6])]))
    Out[65]: 
       A  B
    0  1  4
    1  2  5
    2  3  6
    

    如果 orient 参数设置为 index, 则会把字典的键作为行索引,同时还可以设置列名。

    In [66]: pd.DataFrame.from_dict(
       ....:     dict([("A", [1, 2, 3]), ("B", [4, 5, 6])]),
       ....:     orient="index",
       ....:     columns=["one", "two", "three"],
       ....: )
       ....: 
    Out[66]: 
       one  two  three
    A    1    2      3
    B    4    5      6
    
    • DataFrame.from_records

    DataFrame.from_records 接受元组列表或结构数据类型(dtype)的多维数组。

    DataFrame 构建器类似,只不过生成的 DataFrame 索引是结构数据类型指定的字段。例如

    In [67]: data
    Out[67]: 
    array([(1, 2., b'Hello'), (2, 3., b'World')],
          dtype=[('A', '<i4'), ('B', '<f4'), ('C', 'S10')])
    
    In [68]: pd.DataFrame.from_records(data, index="C")
    Out[68]: 
              A    B
    C               
    b'Hello'  1  2.0
    b'World'  2  3.0
    
    列的选择、添加、删除

    你可以在语义上将 DataFrame 看作是类似 Series 的字典,获取、设置和删除列的语法与字典类似

    In [69]: df["one"]
    Out[69]: 
    a    1.0
    b    2.0
    c    3.0
    d    NaN
    Name: one, dtype: float64
    
    In [70]: df["three"] = df["one"] * df["two"]
    
    In [71]: df["flag"] = df["one"] > 2
    
    In [72]: df
    Out[72]: 
       one  two  three   flag
    a  1.0  1.0    1.0  False
    b  2.0  2.0    4.0  False
    c  3.0  3.0    9.0   True
    d  NaN  4.0    NaN  False
    

    可以像字典一样删除或 pop

    In [73]: del df["two"]
    
    In [74]: three = df.pop("three")
    
    In [75]: df
    Out[75]: 
       one   flag
    a  1.0  False
    b  2.0  False
    c  3.0   True
    d  NaN  False
    

    当插入标量值时,它会自动扩展来填充列

    In [76]: df["foo"] = "bar"
    
    In [77]: df
    Out[77]: 
       one   flag  foo
    a  1.0  False  bar
    b  2.0  False  bar
    c  3.0   True  bar
    d  NaN  False  bar
    

    当插入与 DataFrame 索引不同的 Series 时,它将与 DataFrame 的索引对齐,未匹配的赋值为 NaN

    In [78]: df["one_trunc"] = df["one"][:2]
    
    In [79]: df
    Out[79]: 
       one   flag  foo  one_trunc
    a  1.0  False  bar        1.0
    b  2.0  False  bar        2.0
    c  3.0   True  bar        NaN
    d  NaN  False  bar        NaN
    

    您可以插入原始的 ndarray 数组,但是它们的长度必须与 DataFrame 索引的长度一致

    默认情况下,列会插入到末尾。 使用 insert 函数可用于在列中的特定位置插入

    In [80]: df.insert(1, "bar", df["one"])
    
    In [81]: df
    Out[81]: 
       one  bar   flag  foo  one_trunc
    a  1.0  1.0  False  bar        1.0
    b  2.0  2.0  False  bar        2.0
    c  3.0  3.0   True  bar        NaN
    d  NaN  NaN  False  bar        NaN
    
    用方法链分配新列

    dplyrmutate 动词的启发,DataFrame 也提供了一个 assign 方法,利用现有的列创建新的列

    In [82]: iris = pd.read_csv("data/iris.data")
    
    In [83]: iris.head()
    Out[83]: 
       SepalLength  SepalWidth  PetalLength  PetalWidth         Name
    0          5.1         3.5          1.4         0.2  Iris-setosa
    1          4.9         3.0          1.4         0.2  Iris-setosa
    2          4.7         3.2          1.3         0.2  Iris-setosa
    3          4.6         3.1          1.5         0.2  Iris-setosa
    4          5.0         3.6          1.4         0.2  Iris-setosa
    
    In [84]: iris.assign(sepal_ratio=iris["SepalWidth"] / iris["SepalLength"]).head()
    Out[84]: 
       SepalLength  SepalWidth  PetalLength  PetalWidth         Name  sepal_ratio
    0          5.1         3.5          1.4         0.2  Iris-setosa     0.686275
    1          4.9         3.0          1.4         0.2  Iris-setosa     0.612245
    2          4.7         3.2          1.3         0.2  Iris-setosa     0.680851
    3          4.6         3.1          1.5         0.2  Iris-setosa     0.673913
    4          5.0         3.6          1.4         0.2  Iris-setosa     0.720000
    

    还可以传递带参数的函数进行求值

    In [85]: iris.assign(sepal_ratio=lambda x: (x["SepalWidth"] / x["SepalLength"])).head()
    Out[85]: 
       SepalLength  SepalWidth  PetalLength  PetalWidth         Name  sepal_ratio
    0          5.1         3.5          1.4         0.2  Iris-setosa     0.686275
    1          4.9         3.0          1.4         0.2  Iris-setosa     0.612245
    2          4.7         3.2          1.3         0.2  Iris-setosa     0.680851
    3          4.6         3.1          1.5         0.2  Iris-setosa     0.673913
    4          5.0         3.6          1.4         0.2  Iris-setosa     0.720000
    

    assign 返回的是一个数据拷贝,而不会修改原数据

    当你在数据操作链的中间想要添加一列数据,又不想写入数据中时,会非常有用。

    例如,对于花萼长度大于 5 的数据,计算比例并绘制图像

    In [86]: (
       ....:     iris.query("SepalLength > 5")
       ....:     .assign(
       ....:         SepalRatio=lambda x: x.SepalWidth / x.SepalLength,
       ....:         PetalRatio=lambda x: x.PetalWidth / x.PetalLength,
       ....:     )
       ....:     .plot(kind="scatter", x="SepalRatio", y="PetalRatio")
       ....: )
       ....: 
    Out[86]: <AxesSubplot:xlabel='SepalRatio', ylabel='PetalRatio'>
    
    image.png

    在这个例子中,我们使用了 DataFrame 的链式操作,先筛选出花萼长度大于 5 的数据,然后用 assign 计算并添加两列比例值,最后绘制这两列计算值的散点图

    3.6 版开始,Python 可以保存 **kwargs 顺序。也就是说前面的参数会保存,可以让后面的参数调用。

    In [87]: dfa = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
    
    In [88]: dfa.assign(C=lambda x: x["A"] + x["B"], D=lambda x: x["A"] + x["C"])
    Out[88]: 
       A  B  C   D
    0  1  4  5   6
    1  2  5  7   9
    2  3  6  9  12
    

    在这个例子中,在新建 D 列的时候我们调用了之前创建的 C 列。即 D = A + (A + B)

    要兼容所有的版本,可以使用链式操作

    >>> dfa.assign(C=lambda x: x["A"] + x["B"]).assign(D=lambda x: x["A"] + x["C"])
       A  B  C   D
    0  1  4  5   6
    1  2  5  7   9
    2  3  6  9  12
    

    相关文章

      网友评论

        本文标题:Python 数据处理(四)——DataFrame

        本文链接:https://www.haomeiwen.com/subject/ttggtltx.html