Pandas的数据结构

本文介绍了Pandas的数据结构,包括Series的创建、索引、切片、运算及其与DataFrame的区别。详细阐述了DataFrame的构造、索引方法和运算规则,强调了在运算中对齐索引和处理缺失值的方法。

Pandas的数据结构

导入pandas:

import numpy as np
import pandas as pd
from pandas import Series,DataFrame

1、Series

Series是一种类似于一维数组的对象,由下面两个部分组成:
  • values:一组数据(ndarray类型)

  • index:相关的数据索引标签

    • sereis对象并不是一个数组,但是它只能记录一维的数据,它类似于数组

1)Series的创建

两种创建方式:

(1) 由列表或numpy数组创建

默认索引为0到N-1的整数型索引

list1=[1,2,3,4,5,6]
arr1=np.array(list1)
arr1
------------------------
array([1,2,3,4,5,6])

# seris对象,如果没有显式指定indexs,则把数组的索引设置成index
list1 = [1,2,3,4,5,6]
s1 = Series(list1)
s1
-----------------------
0    1
1    2
2    3
3    4
4    5
5    6
dtype: int64

# 使用index参数显示设置索引
s2 = Series(data=list1, index=["name","python","c","php","java","address"])
s2
----------------
name       1
python     2
c          3
php        4
java       5
address    6
dtype: int64

# series接收的data必须是一维数组
data = np.random.randint(0,10,size=(3,3)).reshape(9)
s3 = Series(data=data)
s3
-----------------
略

还可以通过设置index参数指定索引

特别地,由ndarray创建的是引用,而不是副本。对Series元素的改变也会改变原来的ndarray对象中的元素。(列表没有这种情况)

list2=[0,1,2,3,4]
array2=np.arange(5)
display(list2,array2)
--------------------
[0, 1, 2, 3, 4]
array([0, 1, 2, 3, 4])

# 使用列表构建的是副本对象
s4 = Series(data=list2)

# 使用numpy构建的是引用对象
s5 = Series(data=array2)

# 副本对象相互独立
list2[0] = 100
s4
------------------
0    0
1    1
2    2
3    3
4    4
dtype: int64

# 引用对象会互相影响
array2[0] = 100
s5
--------------

(2) 由字典创建

dic = {
    "name":"lucy",
    "python":100,
    "java":99,
    "address":"beijing"
}
# 字典本身无需,如果使用字典构建一个sereis,将得到一个有序的series,这个sereis的顺序跟字典可能不一致
s5 = Series(data=dic)
s5
--------------------------
address    beijing
java            99
name          lucy
python         100
dtype: object

a = np.random.randint(0,100,size=30)
np.partition(a, -2)
--------------------------
array([28,  7, 28,  0,  2, 23, 36, 64, 66, 57, 47, 53, 51, 79, 83, 84, 72,
       38, 50, 71, 43, 38, 66, 41, 85, 90, 90, 93, 97, 99])

使用多种方法创建以下Series,命名为s1:

语文 150

数学 150

英语 150

理综 300

import numpy as np
import pandas as pd
from pandas import Series,DataFrame
dic = {
    "语文":150,
    "数学":150,
    "英语":150,
    "理综":300,
}
Series(data=dic)
-----------------------
values = [150,150,150,300]
indexes = ["语文","数学","英语","理综"]

Series(data=values, index=indexes)
-------------------------
values2 = np.array([150,150,150,300])
s1 = Series(data=values2, index=indexes)
s1
--------------------

2)Series的索引和切片

可以使用中括号取单个索引(此时返回的是元素类型),或者中括号里一个列表取多个索引(此时返回的仍然是一个Series类型)。分为显示索引和隐式索引:

(1) 显式索引:

- 使用index中的元素作为索引值
- 使用.loc[](推荐)

注意,此时是闭区间

s1["语文"]
-------------
150

s1.loc["语文"]
------------------
150

# 返回一个子series对象
s1[["语文","数学"]]
----------------
语文    150
数学    150
dtype: int32

# 不安全,不推荐使用
s1[0]
------------------
150

(2) 隐式索引:

- 使用整数作为索引值
- 使用.iloc[](推荐)

注意,此时是半开区间

# 隐士索引访问
s1.iloc[0]
------------
150

# 返回一个子series对象
s1.iloc[[0,2]]
---------------
语文    150
英语    150
dtype: int32

两种访问方式

  • s.loc[key]
  • s.iloc[index]

切片

s2 = Series(data=np.random.randint(0,100,size=10), index=list("ABCDEFGHIJ"))
s2

# 使用显式索引切片 左闭右闭区间
s2.loc["B":"J"]

# 使用隐式索引切片 左闭右开区间
s2.iloc[0:3]
--------------
A    69
B    75
C    86
dtype: int32

3)Series的基本概念

可以把Series看成一个定长的有序字典

可以通过shape,size,index,values等得到series的属性

s1.shape
--------
(4,)


s1.index
-----------
Index(['语文', '数学', '英语', '理综'], dtype='object')

from pandas.core.indexes.base import Index

Index(data=["语文","数学"])
-----------------
Index(['语文', '数学'], dtype='object')

s1.values
-------------------
array([150, 150, 150, 300])

s1.size
---------------
4

可以使用head(),tail()分别查看前n个和后n个值

s1.head(1)
--------------
A    150
dtype: int32

s1.tail(1)
----------------
D    300
dtype: int32

当索引没有对应的值时,可能出现缺失数据显示NaN(not a number)的情况

s1 = Series(data=np.random.randint(0,10,size=5), index=list("ABCDE"))
s2 = Series(data=np.random.randint(0,10,size=5), index=list("ABCDF"))
s3 = s1 + s2
s3
--------------------------
A    15.0
B     7.0
C     8.0
D    11.0
E     NaN
F     NaN
dtype: float64

# NaN就是np.nan ,Not a Number
s3.loc["E"]
------------------------
nan

可以使用pd.isnull(),pd.notnull(),或自带isnull(),notnull()函数检测缺失数据

s3
--------------
A     8.0
B    12.0
C    11.0
D    14.0
E     NaN
F     NaN
dtype: float64

s3.isnull()
---------------
A    False
B    False
C    False
D    False
E     True
F     True
dtype: bool

s3.notnull()
---------------
A     True
B     True
C     True
D     True
E    False
F    False
dtype: bool

# 可以使用notnull函数过滤空值
s3.loc[s3.notnull()]
----------------
A     8.0
B    12.0
C    11.0
D    14.0
dtype: float64

使用Bool_list访问数组对象

Series对象本身及其实例都有一个name属性

s3.name = "Python"
s3
----------------
A    15.0
B     7.0
C     8.0
D    11.0
E     NaN
F     NaN
Name: Python, dtype: float64

4)Series的运算

# 一条原则,索引对齐
s1 = Series(data = np.random.randint(0,150,size=4), index=["python","java","c","php"])
s2 = Series(data = np.random.randint(0,150,size=4), index=["python","C++","php","OC"])

s1 + s2
--------------
C++         NaN
OC          NaN
c           NaN
java        NaN
php       208.0
python    134.0
dtype: float64

s3 = Series(data = [120], index=["python"])

s1 + s3
-----------------
c           NaN
java        NaN
php         NaN
python    199.0
dtype: float64

# 跟一个数字运算,不会出现索引对齐的问题
s1 + 10
----------------
python     89
java       65
c         101
php       122
dtype: int32

(1) 适用于numpy的数组运算也适用于Series

(2) Series之间的运算

  • 在运算中自动对齐不同索引的数据
  • 如果索引不对应,则补NaN

注意:要想保留所有的index,则需要使用

  • add() 加
  • sub() 减
  • mul() 乘
  • div() 除

add函数,指定fill_value参数,当需要使用空值填充时,把空值替换成fill_value的值
s1.add(s2,fill_value=0)
--------------
C++ 53.0
OC 6.0
c 91.0
java 55.0
php 134.0
python 89.0
dtype: float64

  1. 想一想Series运算和ndarray运算的规则有什么不同?
  2. 新建另一个索引包含“文综”的Series s2,并与s2进行多种算术操作。
  • 相同点
    numpy运算 广播机制
    sereis numpy运算都支持, 索引对齐原则

  • 不同点
    numpy可以处理高维数据的运算
    Sereis只能处理一维数据的运算

s1 = Series(data=values2, index=indexes)
s1
-----------------
语文    150
数学    150
英语    150
理综    300
dtype: int32

s2 = Series(data = values2, index=["语文","数学","英语","文综"])
s2
-------------------
同上

s1.add(s2, fill_value=0)
-------------------
C++        63.0
OC        124.0
c          86.0
java       90.0
php       208.0
python    134.0
dtype: float64

s1.sub(s2, fill_value=0)
--------------------
C++       -63.0
OC       -124.0
c          86.0
java       90.0
php       -28.0
python    118.0
dtype: float64

s1.mul(s2, fill_value=1)
----------------
C++          63.0
OC          124.0
c            86.0
java         90.0
php       10620.0
python     1008.0
dtype: float64

s1.div(s2, fill_value=1)
--------------------
C++        0.015873
OC         0.008065
c         86.000000
java      90.000000
php        0.762712
python    15.750000
dtype: float64

2、DataFrame

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

  • 行索引:index
  • 列索引:columns
  • 值:values(numpy的二维数组)

1)DataFrame的创建

最常用的方法是传递一个字典来创建。DataFrame以字典的键作为每一【列】的名称,以字典的值(一个数组)作为每一列。

此外,DataFrame会自动加上每一行的索引(和Series一样)。

同Series一样,若传入的列与字典的键不匹配,则相应的值为NaN

import numpy as np
import pandas as pd
from pandas import Series,DataFrame

# 字典的key作为列标签,字典的值是每一列数据,
# 行标签如果没有显式设置,将采用默认的数组的索引
# 行标签一般都是采用默认值0~~~n
dic = {
    "name":["tome","lucy","jack","rose"],
    "age":[19,20,18,20],
    "score":[100,90,98,90]
}

df1 = DataFrame(data=dic)
df1
--------------------

age	name	score
0	19	tome	100
1	20	lucy	90
2	18	jack	98
3	20	rose	90

data = np.random.randint(0,100,size=(5,3))
columns = ["python","C","java"]
index = ["tom","lucy","mery","jack","rose"]
df2 = DataFrame(data=data, columns=columns, index=index)
df2
--------------------

python	C	java
tom	2	51	22
lucy	19	82	6
mery	60	6	33
jack	21	74	61
rose	99	52	7

# 构建一个空的DataFrame对象,然后使用字典赋值的方式初始化
df3 = DataFrame()
# 相当于给字典赋值
df3["python"] = [190,180,290,90]
df3["java"] = [200,180,189,100]
df3
----------------------------

python	java
0	190	200
1	180	180
2	290	189
3	90	100

# 直接从文件中读取一个dataFrame
# pd.read_table()
# pd.read_csv()
# io 读取的excel文件路径
# sheet_name 设置sheet的名字,或者sheet的编号
# header 把excel的第几行读取成为列标签 默认是第一行
pd.read_excel()

pd.read_excel('students.xlsx', sheet_name='Sheet2')

2)DataFrame的索引

(1) 对列进行索引

- 通过类似字典的方式
- 通过属性的方式

可以将DataFrame的列获取为一个Series。返回的Series拥有原DataFrame相同的索引,且name属性也已经设置好了,就是相应的列名。

df = DataFrame(data=np.random.randint(0,100,size=(5,5)), 
               columns=["C","java","php","python","OC"],
              index=["lucy","jack","tom","mery","rose"])
df
-------------------------------
	C	java	php	python	OC
lucy	83	86	63	33	43
jack	74	65	21	59	7
tom	64	90	79	95	25
mery	93	51	35	53	5
rose	74	83	56	12	17

# 访问一列 
# 可以把DataFrame看成是一个Series的字典,key就是每一个列标签,值就是每一列数据
df["python"]

# 可以使用列表,同时读取多列数据
df[["python","C"]]

# 通过属性方式访问
df.python

(2) 对行进行索引

- 使用.ix[]来进行行索引
- 使用.loc[]加index来进行行索引
- 使用.iloc[]加整数来进行行索引

同样返回一个Series,index为原来的columns。

df1 = DataFrame(df.python)
df1
-----------------------

python
lucy	33
jack	59
tom	95
mery	53
rose	12

df1.loc["lucy"]
---------------
python    42
Name: lucy, dtype: int32

df1.loc[["lucy","rose"]]
--------------------

python
lucy	33
rose	12

df.loc[["lucy","rose"]]
--------------------------

         C java php python OC
lucy	83	86	63	33	43
rose	74	83	56	12	17

# DataFrame访问
# 列访问 直接使用[]
# 行访问 使用.loc[row_key] 使用.iloc[row_index]

# 隐式访问
df.iloc[0]

# 同时提取多行
df.iloc[[0,2]]

(3) 对元素索引的方法

- 使用列索引
- 使用行索引(iloc[3,1]相当于两个参数;iloc[[3,3]] 里面的[3,3]看做一个参数)
- 使用values属性(二维numpy数组)

# 间接访问可以读取数据,但是不建议写入数据
df["python"] .loc["lucy"]
-------------------------------------
42

	    C java	php	python	OC
lucy	47	24	32	42	56
jack	48	0	93	64	22
tom	82	78	15	99	51
mery	56	2	28	8	43
rose	46	25	80	71	93

# 也属于间接访问
df.loc["lucy"].loc["python"]
---------------------------
42

直接访问

df.loc[row,column]

# 显式访问
df.loc["lucy","python"]

# 隐式访问
df.iloc[0,3]

切片

【注意】 直接用中括号时:

  • 索引表示的是列索引
  • 切片表示的是行切片

行切片 左闭右闭区间
df.loc[“lucy”:“tom”]
---------------------------

         C	java php python	OC
lucy	83	86	63	33	43
jack	74	65	21	59	7
tom	64	90	79	95	25

# 隐式行切片 左闭右开
df.iloc[0:3]
---------------------------


# 列切片 
df.loc[:,"C":"php"]
-------------------------
	   C  java	php
lucy	83	86	63
jack	74	65	21
tom	64	90	79
mery	93	51	35
rose	74	83	56

df.loc["lucy":"jack","C":"java"]
-----------------------------------
	C	java
lucy	83	86
jack	74	65

# 也可以这样访问,但是不建议
df["lucy":"jack"]

总结:

访问列 df[columnname] df[[clumnname1, columnname2…]]

访问行 df.loc[indexname] df.loc[[indexname1, indexname2]]

访问元素 df.loc[indexname, columnname]

行切片 df.loc[indexname1:indexname2]

列切片 df.loc[:,columnname1:columnname2]

局部切片 df.loc[indexname1:indexname2, columnname1:columnname2]

df.python["jack"]
--------------------------
59

df.python.loc["jack"]
----------------------
59

df.python.iloc[1]
--------------------------
59

df["python"]["jack"]
df["python"].loc["jack"]
df.loc["jack"].python
--------------------------------

3)DataFrame的运算

DataFrame和一个数运算

DataFrame和一个Series运算

DataFrame和DataFrame运算

df = DataFrame(data=np.random.randint(0,10,size=(3,3)),columns=list("ABC"))
df
-------------------------

    A	 B	 C
0	6	0	0
1	4	8	8
2	9	2	0

df+10
--------------------------
	A	B	C
0	16	10	10
1	14	18	18
2	19	12	10

(1) DataFrame之间的运算

同Series一样:

  • 在运算中自动对齐相同索引的数据
  • 如果索引不对应,则补NaN

df1 = DataFrame(data=np.random.randint(0,10,size=(3,3)), columns=list(“ABC”),index=list(“abc”))
s1 = Series(data=[10,20,30], index=list(“abc”))
display(df1, s1)
--------------------------

    A	B	C
a	5	2	4
b	1	3	3
c	3	8	7
a    10
b    20
c    30
dtype: int64

df1+s1
-----------------------------
	A	B	C	a	b	c
a	NaN	NaN	NaN	NaN	NaN	NaN
b	NaN	NaN	NaN	NaN	NaN	NaN
c	NaN	NaN	NaN	NaN	NaN	NaN

DataFrame和Series相加可以设置相加的方向,必须要保证在运算的方向上的索引是对齐的,不然就会自动补充nan
df1.add(s1,axis='index')
----------------------------------------
	A	B	C
a	15	12	14
b	21	23	23
c	33	38	37



df1 = DataFrame(data=np.random.randint(0,10,size=(3,3)), columns=list("ABC"), index=list("甲乙丙"))
df2 = DataFrame(data=np.random.randint(0,10,size=(3,3)), columns=list("ABD"), index=list("甲乙丁"))
display(df1, df2)
----------------------------------------------
	A	B	C
甲	1	1	3
乙	6	2	1
丙	4	4	1
     A	B	D
甲	5	9	1
乙	9	4	3
丁	2	7	0

df1 + df2
--------------------------------
    A	B	C	java	python
a	NaN	NaN	NaN	NaN	NaN
b	NaN	NaN	NaN	NaN	NaN
c	NaN	NaN	NaN	NaN	NaN
jack	NaN	NaN	NaN	NaN	NaN
lucy	NaN	NaN	NaN	NaN	NaN
mery	NaN	NaN	NaN	NaN	NaN
rose	NaN	NaN	NaN	NaN	NaN
tom	NaN	NaN	NaN	NaN	NaN

df1.add(df2,fill_value=0)
----------------------------------
         A	B	C	java	python
a	    5.0	2.0	4.0	NaN	NaN
b	    1.0	3.0	3.0	NaN	NaN
c	    3.0	8.0	7.0	NaN	NaN
jack	NaN	NaN	74.0	61.0	21.0
lucy	NaN	NaN	82.0	6.0	19.0
mery	NaN	NaN	6.0	33.0	60.0
rose	NaN	NaN	52.0	7.0	99.0
tom	NaN	NaN	51.0	22.0	2.0   

(2) Series与DataFrame之间的运算

【重要】

  • 使用Python操作符:以行为单位操作(参数必须是行),对所有行都有效。(类似于numpy中二维数组与一维数组的运算,但可能出现NaN)
  • 使用pandas操作函数:
    axis=0:以列为单位操作(参数必须是列),对所有列都有效。
    axis=1:以行为单位操作(参数必须是行),对所有行都有效。

axis=0(0 == index 行):以列为单位操作(参数必须是列),对所有列都有效。 axis=1(1 == columns 列):以行为单位操作(参数必须是行),对所有行都有效。

【注意】fill_value在df和series之间运算时,不能使用

df1

s1.index = list("ABC")
s1
------------------
A    10
B    20
C    30
dtype: int64


#fill_value在df和series之间运算时,不能使用
df1.add(s1, fill_value=0)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值