失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > pandas dataframe创建_Python数据分析基础之Pandas学习 (上)

pandas dataframe创建_Python数据分析基础之Pandas学习 (上)

时间:2022-05-21 16:37:58

相关推荐

pandas dataframe创建_Python数据分析基础之Pandas学习 (上)

全文共 20592 字,63 幅图,预计阅读时间 52 分钟。【注:本帖小节 2.2 用万矿里的 WindPy 来下载金融数据】0引言

本文是 Python 系列的第六篇

Python 入门篇 (上)

Python 入门篇 (下)

数组计算之 NumPy (上)

数组计算之 NumPy (下)

科学计算之 SciPy

数据结构之 Pandas (上)

数据结构之 Pandas (下)

基本可视化之 Matplotlib

统计可视化之 Seaborn

交互可视化之 Bokeh

炫酷可视化之 PyEcharts

机器学习之 Sklearn

深度学习之 TensorFlow

深度学习之 Keras

深度学习之 PyTorch

深度学习之 MXnet

Pandas 是 Python 为解决数据分析而创建的,详情看官网 (/)。在使用pandas之前,需要引进它,语法如下:

importpandas

这样你就可以用pandas里面所有的内置方法 (build-in methods) 了,比如创建一维的Series和二维的DataFrame。

pandas.Series()pandas.DataFrame()

但是每次写pandas字数有点多,通常我们给pandas起个别名 pd,用以下语法,这样所有出现pandas的地方都可以用pd替代。

importpandasaspd

Pandas里面的数据结构是「多维数据表」,学习它可以类比这NumPy里的「多维数组」。1/2/3维的「多维数据表」分别叫做Series(系列),DataFrame(数据帧)和Panel(面板),和1/2/3维的「多维数组」的类比关系如下。

由于「系列」、「数据帧」和「面板」这些直译过来的中文名词听起来有些奇怪,在本帖还是直接用 Series, DataFrame和Panel。

对比 NumPy (np) 和 Pandas (pd) 每个维度下的数据结构,不难看出

pd 多维数据表 = np 多维数组 + 描述

其中

Series = 1darray + index

DataFrame = 2darray + index + columns

Panel = 3darray + index + columns + item

每个维度上的「索引」使得「多维数据表」比「多维数组」涵盖更多的信息,如下图,左边的2darray仅仅储存了一组数值(具体代表什么意思却不知道),而右边的DataFrame一看就知道这是平安银行和茅台从-1-3到-1-3的价格。

和学习numpy一样,学习pandas还是遵循的 Python 里「万物皆对象」的原则,既然把数据表当对象,我们就按着数据表的创建、数据表的存载、数据表的获取、数据表的合并和连接、数据表的重塑和透视、和数据表的分组和整合来盘一盘Pandas,目录如下:

由于篇幅原因,Pandas系列分两贴,上贴讲前三节的内容,下帖讲后三节的内容。

1数据表的创建

数据表有三大类型

Series:一维数据,类似于python中的基本数据的list或NumPy中的1Darray。Pandas里最基本的数据结构

DataFrame:二维数据,类似于R中的data.frame或Matlab中的Tables。DataFrame是Series的容器

Panel:三维数据。Panel是DataFrame的容器

知识点最常见的数据类型是二维的DataFrame,其中

每行代表一个示例 (instance)

每列代表一个特征 (feature)

DataFrame可理解成是Series的容器,每一列都是一个Series,或者Series是只有一列的DataFrame。Panel可理解成是DataFrame的容器。

接下来我们用代码来创建pandas数据表,有两种方式:

按步就班的用pd.Series(),pd.DataFrame() 和pd.Panel()

一步登天的用万矿里面的WindPy API 读取

2.1

按部就班法

一维 Series

创建 Series 只需用下面一行代码

pd.Series( x, index=idx )

其中 x 可以是

列表 (list)

numpy数组 (ndarray)

字典 (dict)

回顾在〖Python 入门篇 (下)〗讲的函数里可以设定不同参数,那么

x 是位置参数

index 是默认参数,默认值为 idx = range(0, len(x))

用列表

s = pd.Series([27.2, 27.65, 27.70, 28])s

0 27.20

1 27.65

2 27.70

3 28.00

dtype:float64

打印出来并不仅仅是列表里面的浮点数,每个浮点数前面还有一个索引,在本例中是0,1,2,3。

因此在创建Series时,如果不显性设定index,那么Python给定一个默认从0到N-1的值,其中N是x的长度。

Series s 也是一个对象,用 dir(s) 可看出关于 Series 所有的属性和内置函数,其中最重要的是

用 s.values 打印 s 中的元素

用 s.index 打印 s中的元素对应的索引

s.values

array([27.2 , 27.65, 27.7 , 28. ])

s.index

RangeIndex(start=0, stop=4, step=1)

不难发现,以上创建的Series和numpy数组比多了「索引」,但这种0,1,2,3的索引是在没有什么描述意义。实际上我们定义的s是海底捞在4月1日到4月4日的股价,那么用日期来当索引是不是更好些?

dates = pd.date_range('0401',periods=4)s2 = pd.Series( [27.2, 27.65, 27.70, 28], index=dates )s2

-04-01 27.20

-04-02 27.65

-04-03 27.70

-04-04 28.00

Freq:D, dtype:float64

显然,s2比s包含的信息更多,这是s2的索引是一组日期对象,数据类型是datetime64,频率是D(天)。

s2.index

DatetimeIndex(['-04-01', '-04-02', '-04-03', '-04-04'],

dtype='datetime64[ns]', freq='D')

你甚至还可以给 s2 命名,就叫海底捞股价如何?

s2.name = '海底捞股价's2

-04-01 27.20

-04-02 27.65

-04-03 27.70

-04-04 28.00

Freq:D, Name:海底捞股价,dtype:float64

用 numpy 数组

除了用列表,我们还可以用numpy数组来生成Series。在下例中,我们加入缺失值np.nan,并分析一下Series中另外5个属性或内置函数的用法:

len:s里的元素个数

shape:s的形状(用元组表示)

count:s里不含nan的元素个数

unique:返回s里不重复的元素

value_counts:统计s里非nan元素的出现次数

对照上面函数的用法,下面的输出一看就懂了吧。

s = pd.Series( np.array([27.2, 27.65, 27.70, 28, 28, np.nan]) )print( 'The length is', len(s) )print( 'The shape is', s.shape )print( 'The count is', s.count() )

The length is 6

The shape is (6,)

The count is 5

s.unique()

array([27.2 , 27.65, 27.7 , 28. , nan])

s.value_counts()

28.00 2

27.70 1

27.65 1

27.20 1

dtype:int64

用字典

创建Series还可以用字典。字典的「键值对」的「键」自动变成了Series的索引(index),而「值」自动变成了Series的值(values)。代码如下(下列用name参数来对s3命名)

data_dict = { 'BABA':187.07, 'PDD':21.83, 'JD':30.79, 'BIDU':184.77 }s3 = pd.Series(data_dict, name='中概股')s3.index.name='股票代号's3

股票代号

BABA 187.07

PDD21.83

JD 30.79

BIDU 184.77

Name:中概股,dtype:float64

给s3起名中概股是因为阿里巴巴(BABA)、拼多多(PDD)、京东(JD)和百度(BIDU)都是中国公司但在美国上市的。此外还可以给index命名为'股票代号'。

现在假设我们的股票代号为

stock = ['FB', 'BABA', 'PDD', 'JD']s4 = pd.Series( sdata, index=stock )s4

FB NaN

BABA 160.0

PDD28.0

JD 25.0

dtype:float64

代号里多加了脸书(FB),而sdata字典中没有FB这个键,因此生成的s4在FB索引下对应的值为NaN。再者,代号里没有百度(BIDU),因此s4里面没有BIDU对应的值(即便sdata里面有)。

当两个Series进行某种操作时,比如相加,Python会自动对齐不同Series的index,如下面代码所示:

s3 + s4

BABA 320.0

BIDUNaN

FB NaN

JD 50.0

PDD56.0

dtype:float64

Series是Pandas里面最基本的数据结构,但是对应每个索引只有一个元素(比如一个日期对应一个股价),因此Series处理不了每个索引对应多个元素(比如一个日期对应一个开盘价、收盘价、交易量等等)。而DataFrame可以解决这个问题。

二维 DataFrame

创建 DataFrame 只需用下面一行代码

pd.DataFrame( x, index=idx,

columns=col )

其中 x 可以是

二维列表 (list)

二维numpy数组 (ndarray)

字典 (dict),其值是一维列表、numpy 数组或 Series

另外一个 DataFrame

回顾在〖Python 入门篇 (下)〗讲的函数里可以设定不同参数,那么

x 是位置参数

index 是默认参数,默认值为 idx = range(0, x.shape[0])

columns 是默认参数,默认值为 col =range(0, x.shape[1])

用列表或 numpy 数组

#df1=pd.DataFrame([[1,2,3],[4,5,6]])df1 = pd.DataFrame( np.array([[1, 2, 3], [4, 5, 6]]) )df1

在创建 DataFrame 时,如果不显性设定 index 和 columns 时,那么Python 给它们默认值,其中

index = 0 到 r-1,r 是 x 的行数

colmns = 0 到 c-1,c是 x 的列数

用对象为列表的字典

symbol = ['BABA', 'JD', 'AAPL', 'MS', 'GS', 'WMT']data = {'行业':['电商', '电商', '科技', '金融', '金融', '零售'], '价格':[176.92, 25.95, 172.97, 41.79, 196.00, 99.55], '交易量':[16175610, 27113291, 18913154, 10132145, 2626634, 8086946], '雇员':[101550, 175336, 100000, 60348, 36600, 2200000]}df2 = pd.DataFrame( data, index=symbol )df2.name='美股'df2.index.name = '代号'df2

字典的「键值对」的「键」自动变成了DataFrame的栏(columns),而「值」自动变成了DataFrame的值(values),而其索引(index)需要另外定义。

分别来看df2的values,columns和index。

df2.values

array([['电商', 176.92, 16175610, 101550],

['电商', 25.95, 27113291, 175336],

['科技', 172.97, 18913154, 100000],

['金融', 41.79, 10132145, 60348],

['金融', 196.0, 2626634, 36600],

['零售', 99.55, 8086946, 2200000]], dtype=object)

df2.columns

Index(['行业', '价格', '交易量', '雇员'], dtype='object')

df2.index

Index(['BABA', 'JD', 'AAPL', 'MS', 'GS', 'WMT'],

dtype='object', name='代号')

A查看 DataFrame

我们可以从头或从尾部查看 DataFrame 的 n 行,分别用 df2.head() 和 df2.tail(n),如果没有设定n,默认值为5行。

df2.head()

df2.tail(3)

B统计 DataFrame

我们用 df2.describe()还可以看看DataFrame每栏的统计数据。

df2.describe()

函数describe()只对「数值型变量」有用(没有对「字符型变量」行业栏做统计),统计量分别包括个数、均值、标准差、最小值,25-50-75百分数值,最大值。一般做数据分析第一步会用这个表大概看看

数据是否有缺失值(每个栏下的count是否相等)?

数据是否有异常值(最小值min和最大值max是否太极端)?

C升维 DataFrame

我们用 MultiIndex.from_tuples()还可以赋予DataFrame多层索引(实际上增加了维度,多层索引的DataFrame实际上是三维数据)。

df2.index = pd.MultiIndex.from_tuples( [('中国公司','BABA'), ('中国公司','JD'), ('美国公司','AAPL'),('美国公司','MS'),('美国公司','GS'),('美国公司','WMT')])df2

在 MultiIndex.from_tuples()中传递一个「元组的列表」,每个元组,比如 ('中国公司', 'BABA'),第一个元素中国公司是第一层 index,第二个元素BABA是第二层index。

DataFrame是Series的容器,那什么是DataFrame的容器?Panel!

三维 Panel

首先需要指出的是Panel在未来版本中会被废除,因此不想花时间看的同学可跳过。

创建 Panel 只需用下面一行代码

pd.Panel( x, item=itm,

major_axis=n1,

minor_axis=n2 )

其中 x 可以是

三维列表 (list)

三维numpy数组 (ndarray)

字典 (dict),其值是 DataFrame

回顾在〖Python 入门篇 (下)〗讲的函数里可以设定不同参数,那么

x 是位置参数

items 是默认参数 (axis 0),默认值为 itm = range(0, number of DataFrame)

major_axis是默认参数 (axis 1),默认值和 DataFrame 的默认 index 一样

minor_axis是默认参数 (axis 2),默认值和 DataFrame 的默认 columns 一样

用 numpy 数组

pn = pd.Panel(np.random.randn(2, 5, 4))pn

'pandas.core.panel.Panel'>

Dimensions: 2 (items) x 5 (major_axis) x 4 (minor_axis)

Items axis: 0 to 1

Major_axis axis: 0 to 4

Minor_axis axis: 0 to 3

Panelpn含有2个DataFrame,items为0,1;每个DataFrame有5行4列,因此major_axis为0,1,2,3,4,而minor_axis为0,1,2,3。

用对象为 DataFrame 的字典

dates = pd.date_range('0401',periods=4)data={'开盘价':[27.2,27.65,27.70,28],'收盘价':[27.1,27.55,27.45,28.1]}df1 = pd.DataFrame( data, index=dates )data={'开盘价':[367,369.8,378.2,380.6],'收盘价':[369.5,370.1,380,382.1]}df2 = pd.DataFrame( data, index=dates )p_data={'海底捞':df1,'腾讯':df2}pn = pd.Panel(p_data)pn

'pandas.core.panel.Panel'>

Dimensions: 2 (items) x 4 (major_axis) x 2 (minor_axis)

Items axis: 海底捞 to 腾讯

Major_axis axis: -04-01 00:00:00 to -04-04 00:00:00

Minor_axis axis: 开盘价 to 收盘价

分析上面的 Panel pn

有 2 个 DataFrame,items 为 '海底捞' 和 ‘腾讯’

每个 DataFrame 有 4 行 2 列

major_axis 从 -04-01 到 -04-04

minor_axis 为 ‘开盘价’ 和 ‘收盘价’

让我们来查看两个DataFrame 的内容

pn['海底捞']

pn['腾讯']

上面这种 Panel 类型的数据在量化投资中还蛮常见,比如我们需要10 个股票1 年时期OHLC 价格(Open, High, Low, Close),Panel 的 Items, Major_axis 和 Minor_axis 正好可以存储这样的三维数据。如果Panel要废掉,那用什么容器来储存三维数据呢?

用多层索引(Multi-index)的DataFrame!

df = pd.concat([df1, df2])code = ['海底捞', '腾讯']midx = [ (c, d) for c in code for d in dates ] df.index =pd.MultiIndex.from_tuples( midx )df

首先用 concat()函数(下帖的内容)将df1和df2连接起来;再用「列表解析法」生成midx,它是一个元组的列表,c是股票代码,d是日期;最后放入MultiIndex.from_tuples()生成有多层索引的DataFrame。

2.2

一步登天法

不喜欢量化的读者可跳过本节,不影响本帖的完整性。

上节都是手敲一些数据来创建「多维数据表」的,现实中做量化分析时,数据量都会很大,一般都是从量化平台中或者下载好的 csv 中直接读取。本节介绍如何从量化平台「万矿」中读取数据来创建「多维数据表」的。

首先在注册一个账号,点击「研究」后在点开一个 Notebook 作为你的研究环境 (这是要夸奖一下万矿的 Notebook 体验真的不错,而且数据质量方面还有万德保证)。

接着必须加载 WindPy,然后执行 w.start()启动API接口:

from WindPy import *w.start()

WindPy 里面有几个获取数据的核心函数,分别是

日期序列函数 wsd

多维数据函数 wss

行情数据函数 wsq

分钟序列数据函数 wsi

日期序列函数 wsd

该函数支持股票、债券、基金、期货、指数等多种证券的基本资料、股东信息、市场行情、证券分析、预测评级、财务数据等各种数据,可以支持取单品种单指标多品种单指标单品种多指标的时间序列数据 (注:不支持多品种多指标)。函数定义如下

w.wsd(security, fields, startdate, enddate, options)

security = 证券代号,可以是 str 或 list

fields = 指标,可以是 str 或 list

startdate = 起始日,可以是 str 或 datetime

enddate = 起始日,可以是 str 或 datetime

options = 一些特定设置

单品种单指标

获取平安银行在 -04-01 到 -04-04 的收盘价。

code = "000001.SZ"factors = ["close"]startDate = "-04-01"endDate = "-04-04"data = w.wsd(code, factors, startDate, endDate, usedf=True )data

(0,CLOSE

-04-01 00:00:00.005 13.18

-04-02 00:00:00.005 13.36

-04-03 00:00:00.005 13.44

-04-04 00:00:00.005 13.86)

知识点当 usedf=True 时返回元组

元组第一个元素为 ErrorCode,其为 0 时表示数据获取正常

元组第二个元素为获取的数据 DataFrame,其中 index 列为时间,columns 为参数 Fields 各指标

上面结果 errorcode = 0,要获取 DataFrame 只需访问 data[1]

data[1]

单品种多指标

获取平安银行在 -04-01 到 -04-04 的开盘价、最低价、最高价和收盘价。

code = "000001.SZ"factors = "open,low,high,close"startDate = "-04-01"endDate = "-04-04"data = w.wsd(code, factors, startDate, endDate, usedf=True )data[1]

多品种单指标

获取平安银行、万科、茅台在 -04-01 到 -04-04 的收盘价。

code=["000001.SZ","000002.SZ","600519.SH"]factors = "close"startDate = "-04-01"endDate = "-04-04"data = w.wsd(code, factors, startDate, endDate, usedf=True )data[1]

多维数据函数 wss

该函数同样支持股票、债券、基金、期货、指数等多种证券的基本资料、股东信息、市场行情、证券分析、预测评级、财务数据等各种数据。但是 wss 支持取多品种多指标某个时间点的截面数据。函数定义如下

w.wss(security, fields, option)

security = 证券代号,可以是 str 或 list

fields = 指标,可以是 str 或 list

options = 一些特定设置

获取平安银行、万科、茅台在 -12-31 的收盘价、交易量、每股盈余和 profit/GR。

date = "-12-31"codes = ["000001.SZ","000002.SZ","600519.SH"]factors = "close, volume, eps_basic, profittogr"data=w.wss(codes,factors, "rptDate="+date+";currencyType=",usedf=True)data[1]

如果要看财务数据,万矿是取每个季度最后一天作为报告期,如取 年的四个定期报告数据,那报告期设置分别为:

一季报:-03-31

半年报:-06-30

三季报:-09-30

年报: -12-31

本例-12-31 是年报的数据。

行情数据函数 wsq

该函数支持股票、债券、基金、期货、指数等多种证券品种的实时行情数据。函数定义如下

w.wsq(security, fields, func=None)

security = 证券代号,可以是 str 或 list

fields = 指标,可以是 str 或 list

func = 回调函数

获取易方达深证 100ETF 里所有成分中的各种行情指标。

ETF = w.wset("allfundhelddetail", "rptdate=1231;windcode=159901.OF")codes = ETF.Data[2]fields = "rt_last,rt_vol,rt_chg,rt_pct_chg,rt_vwap,rt_ask1,rt_bid1"data = w.wsq( codes, fields ) data = pd.DataFrame( data.Data, index=data.Fields,columns=data.Codes).Tdata.head(3).append(data.tail(3))

读者肯定好奇第一行代码怎么来的?这里 wset 是专门收集数据集信息的函数,万矿做的好的东西是又一套 GUI 帮你生成第一行代码,展示如下:

点击「API 函数」下面的「WSET 数据集」会带给你以下界面。再选择「ETF 申购成分信息」。

点击下一步得到

看到没有第一行代码就这样生成了,获取数据的门槛迅速降低了好多。

分钟序列数据函数 wsi

该函数获取选定证券品种的分钟线数据,包含基本行情和部分技术指标的分钟数据,分钟周期为 1-60 min,技术指标参数可以自定义设置。函数定义如下

w.wsi(security, fields, starttime = None, endtime = None, options = None)

security = 证券代号,可以是 str 或 list

fields = 指标,可以是 str 或 list

startdate = 起始日,可以是 str 或 datetime

enddate = 起始日,可以是 str 或 datetime

options = 一些特定设置

获取中金所 IF 股指期货当月连续合约 -04-01 09:30:00 开始至 -04-01 09:40:00 的 1 分钟数据。

codes ='IF00.CFE'fields ='open, high, low, close'IF = w.wsi( codes, fields, '-04-01 09:30:00', '-04-01 09:40:00', "", usedf=True ) IF[1]

2数据表的存载

本节讲数据表的「保存」和「加载」,在 NumPy 一贴已经提到过,数据的存载没什么技术含量

保存只是为了下次再用处理好的 DataFrame

加载可以不用重新再定义 DataFrame

DataFrame 可以被保存为 Excel, csv, SQL 和 HDF5 格式,其语句一看就懂,用 to_数据格式,具体如下:

to_excel()

to_csv()

to_sql()

to_hdf()

如果要加载某种格式的数据到 DataFrame 里,用 read_数据格式,具体如下:

read_excel()

read_csv()

read_sql()

read_hdf()

我们只用excel和csv格式举例。

Excel 格式

用 pd.to_excel函数将DataFrame保存为.xlsx格式,并保存到‘Sheet1’中,具体写法如下:

pd.to_excel( '文件名','表名' )

df = pd.DataFrame(np.array([[1, 2, 3], [4, 5, 6]]))df.to_excel('pd_excel.xlsx',sheet_name='Sheet1')

用pd.read_excel( '文件名','表名' )即可加载该文件并存成DataFrame 形式

df1=pd.read_excel('pd_excel.xlsx',sheet_name='Sheet1')df1

csv 格式

用pd.to_csv函数将DataFrame保存为.csv格式,注意如果index没有特意设定,最后不要把index值存到csv文件中。具体写法如下:

pd.to_csv( '文件名',index=False)

data = {'Code':['BABA', '00700.HK', 'AAPL', '600519.SH'], 'Name':['阿里巴巴', '腾讯', '苹果', '茅台'], 'Market':['US', 'HK', 'US', 'SH'], 'Price':[185.35, 380.2, 197, 900.2], 'Currency':['USD', 'HKD', 'USD', 'CNY']}df = pd.DataFrame(data)df.to_csv('pd_csv.csv',index=False)

用pd.read_csv('文件名' )即可加载该文件并存成DataFrame 形式

df2=pd.read_csv('pd_csv.csv')df2

如果一开始储存 df 的时候用index=True,你会发现加载完后的df2是以下的样子。

df2里面第一栏是df的index,由于没有具体的columns名称,系统给它一个"Unamed:0"。因此在存储df的时候,如果df.index没有特意设定,记住要在to_csv()中把index设置为False

3数据表的索引和切片

由于索引/切片Series跟numpy数组很类似,由于Panel在未来会被废掉,因此本节只专注于对DataFrame做索引和切片。本节以下面df为例做展示。

symbol = ['BABA', 'JD', 'AAPL', 'MS', 'GS', 'WMT']data = {'行业':['电商', '电商', '科技', '金融', '金融', '零售'], '价格':[176.92, 25.95, 172.97, 41.79, 196.00, 99.55], '交易量':[16175610, 27113291, 18913154, 10132145, 2626634, 8086946], '雇员':[101550, 175336, 100000, 60348, 36600, 2200000]}df=pd.DataFrame(data,index=symbol)df.name='美股'df.index.name='代号'df

用不同颜色标注了df的index,columns和values,可视图如下:

DataFrame的索引或切片可以基于标签 (label-based) ,也可以基于位置 (position-based),不像 numpy 数组的索引或切片基于位置。

DataFrame的索引或切片有四大类:

索引单元素:

基于标签的 at

基于位置的 iat

切片columns:

.来切片单列

[]来切片单列或多列

基于标签的loc

基于位置的 iloc

切片index:

[]来切片单行或多行

基于标签的loc

基于位置的iloc

切片index和columns:

基于标签的loc

基于位置的iloc

总体规律,基于标签就用at 和 loc,基于位置就用iat和 iloc。下面我们来一类类分析:

3.1

索引单元素

两种方法来索引单元素,情况 1 基于标签 at,情况 2 基于位置 iat。

情况 1-df.at['idx_i', 'attr_j']

情况 2-df.iat[i, j]

Python 里的中括号[] 会代表很多意思,比如单元素索引,多元素切片,布尔索引等等,因此让 Python 猜你用的[]意图会很低效。如果你想索引单元素,明明白白的用at和iat效率最高。

情况 1

df.at['AAPL','价格']

172.97

用at获取「行标签」为'AAPL'和「列标签」为‘价格’对应的元素。

情况 2

df.iat[2,1]

172.97

用iat获取第3行第2列对应的元素。

索引单元素的总结图:

3.2

切片 columns

切片单个columns

切片单个columns会返回一个Series,有以下四种情况。情况1用点.;情况2用中括号[];情况3基于标签loc,情况 4 基于位置 iloc。

情况 1-df.attr_i

情况2-df['attr_i']

情况3-df.loc[:,'attr_i']

情况4-df.iloc[:,i]

情况1记住就可以了,没什么可说的。

情况 2 非常像二维 numpy 数组 arr 的切片,用 arr[i] 就能获取 arr 在「轴 0」上的第 i 个元素 (一个 1darray),同理 df['attr_i']也能获取df的第i个Series。

情况 3 和 4 的loc和iloc可类比于上面的at和iat。带i的基于位置 (位置用整数表示,i 也泛指整数),不带i的基于标签。里面的冒号:代表所有的index(和numpy数组里的冒号意思相同)。

个人建议,如果追求简洁和方便,用. 和 [];如果追求一致和清晰,用loc和iloc。

情况 1

df.价格

代号

BABA 176.92

JD 25.95

AAPL 172.97

MS 41.79

GS196.00

WMT99.55

Name:价格,dtype:float64

用.获取「价格」那一栏下的Series。

情况 2

df['价格']

代号

BABA 176.92

JD 25.95

AAPL 172.97

MS 41.79

GS196.00

WMT99.55

Name:价格,dtype:float64

用[]获取「价格」属性下的Series。

情况 3

df.loc[:,'交易量']

代号

BABA 16175610

JD27113291

AAPL 18913154

MS10132145

GS 2626634

WMT8086946

Name:交易量,dtype:int64

用loc获取「交易量」属性下的Series。

情况 4

df.iloc[:,0]

代号

BABA 电商

JD电商

AAPL 科技

MS金融

GS金融

WMT零售

Name:行业,dtype:object

用iloc获取第1列下的Series。

切片单个columns的总结图:

切片多个columns

切片多个columns会返回一个sub-DataFrame(原DataFrame的子集),有以下三种情况。情况1用中括号[];情况2基于标签loc,情况 3 基于位置iloc。

情况1-df[['attr_i', 'attr_j']]

情况2-df.loc[:,'attr_i':'attr_j']

情况3-df.iloc[:,i:j]

和切片单个columns相比:

情况 1 用一个列表来储存一组属性 'attr_i', 'attr_j',然后在放进中括号[] 里获取它们

情况 2 用 'attr_i':'attr_j' 来获取从属性 i 到属性 j 的 sub-DataFrame

情况 3 用 i:j 来获取从列 i+1 到列 j 的 sub-DataFrame

个人建议,如果追求简洁和方便,用[];如果追求一致和清晰,用loc和iloc。

情况 1

df[ ['雇员', '价格'] ]

用[]获取「雇员」和「价格」两个属性下的sub-DataFrame。

情况 2

df.loc[:,'行业':'交易量']

用loc获取从属性‘行业’到‘交易量‘的sub-DataFrame。

情况 3

df.iloc[:,0:2]

用iloc获取第1和2列下的sub-DataFrame。

切片多个columns的总结图:

3.3

切片 index

切片单个index

切片单个index有时会返回一个Series,有以下两种情况。情况1基于标签loc,情况 2 基于位置iloc。

情况1-df.loc['idx_i',:]

情况2-df.iloc[i,:]

切片单个index 有时会返回一个只有一行的 DataFrame,有以下两种情况。情况3用中括号[]加「位置」,情况 4用中括号[]加「标签」。

情况3-df[i:i+1]

情况4-df['idx_i':'idx_i']

情况 1 和 2 的loc和iloc可类比于上面的at和iat。带i的基于位置 (位置用整数表示,i 也泛指整数),不带i的基于标签。里面的冒号:代表所有的columns(和numpy数组里的冒号意思相同)。

情况 3 用中括号[]加「位置」,位置 i:i+1 有前闭后开的性质。如果要获取第i+1行,需要用i:i+1。

情况 4 用中括号[]加「标签」,标签没有前闭后开的性质。如果要获取标签 i,只需要用'idx_i':'idx_i'。为什么不能只用'idx_i'呢?原因是Python会把df['idx_i'] 当成切片 columns,然后发现属性中没有'idx_i'这一个字符,会报错的。

个人建议,只用loc和iloc。情况3太麻烦,获取一行还要用i:i+1。情况 4 的df['idx_i'] 很容易和切片 columns 中的语句df['attr_j']混淆。

情况 1

df.loc['GS',:]

行业金融

价格 196

交易量 2626634

雇员 36600

Name:GS,dtype:object

用loc获取标签为‘GS‘的Series。(GS=GoldmanSachs=高盛)

情况 2

df.iloc[3,:]

行业 金融

价格 41.79

交易量 10132145

雇员 60348

Name:MS,dtype:object

用iloc获取第4行下的Series。(MS=MorganStanley=摩根斯坦利)

情况 3

df[1:2]

用[1:2]获取第2行的sub-DataFrame(只有一行)。

情况 4

df['JD':'JD']

用['JD':'JD']获取标签为'JD'的sub-DataFrame(只有一行)。

切片单个index的总结图:

切片多个index

切片多个index会返回一个sub-DataFrame,有以下四种情况。情况 1用中括号[]加「位置」,情况 2 用中括号[]加「标签」,情况 3 基于标签loc,情况 4 基于位置iloc。

情况1-df[i:j]

情况2-df['idx_i':'idx_j']

情况3-df.loc['idx_i':'idx_j',:]

情况4-df.iloc[i:j,:]

和切片单个index相比:

情况 1 用[i:j]来获取行 i+1 到行 j 的 sub-DataFrame

情况 2 用['idx_i':'idx_j']来获取标签 i 到标签 j 的 sub-DataFrame

情况 3 用loc 加'idx_i':'idx_j'来获取从标签 i 到标签 j 的 sub-DataFrame

情况 4 用iloc 加i:j来获取从行 i+1 到行 j 的 sub-DataFrame

个人建议,只用loc和iloc。情况1和2的df[]很容易混淆中括号[]里的到底是切片index还是columns。

情况 1

df[1:4]

用[1:4]获取第2到4行的sub-DataFrame。

情况 2

df[ 'GS':'WMT' ]

用['GS':'WMT']获取标签从'GS'到'WMT'的sub-DataFrame。(WMT=Walmart=沃尔玛)

情况 3

df.loc[ 'MS':'GS',:]

用loc获取标签从 ‘MS‘ 到 'GS' 的 sub-DataFrame。注意‘MS’:’GS’要按着index里面元素的顺序,要不然会返回一个空的DataFrame,比如:

df.loc[ 'MS':'JD',:]

情况 4

df.iloc[1:3,:]

用iloc获取第 2 到 3 行的 sub-DataFrame。

切片多个index的总结图:

3.4

切片 index 和 columns

切片多个index 和 columns 会返回一个 sub-DataFrame,有以下两种情况。情况1基于标签loc,情况 2 基于位置iloc。

情况1-df.loc['idx_i':'idx_j','attr_k':'attr_l']

情况2-df.iloc[i:j,k:l]

清清楚楚,明明白白,用loc 和 iloc。

情况 1

df.loc[ 'GS':'WMT', '价格':]

用loc获取行标签从 ‘GS‘ 到 'WMT',列标签从'价格'到最后的sub-DataFrame。

情况 2

df.iloc[:2,1:3]

用iloc获取第1到2行,第1到2列的sub-DataFrame。

切片index和columns的总结图:

3.5

高级索引

高级索引 (advanced indexing) 可以用布尔索引(boolean indexing) 和调用函数(callable function) 来实现,两种方法都返回一组“正确”的索引,而且可以和 loc,iloc,[]一起套用,具体形式有以下常见几种:

df.loc[布尔索引,:]

df.iloc[布尔索引,:]

df[布尔索引]

df.loc[调用函数,:]

df.iloc[调用函数,:]

df[调用函数]

还有以下罕见几种:

df.loc[:,布尔索引]

df.iloc[:,布尔索引]

df.loc[:,调用函数]

df.iloc[:,调用函数]

读者可以想一想为什么第一组形式「常见」而第二组形式「罕见」呢?(Hint:看看两组里冒号:在不同位置,再想想DataFrame每一行和每一列中数据的特点)

布尔索引

在〖数组计算之 NumPy (上)〗提过,布尔索引就是用一个由布尔类型值组成的数组来选择元素的方法。

当我们要过滤掉雇员小于 100,000 人的公司,我们可以用loc加上布尔索引。

print( df.雇员 >= 100000 )df.loc[df.雇员>=100000,:]

一种更简便的表达形式是用 df[],但是我个人不喜欢 [],总觉得会引起「到底在切片index还是columns」的歧义。

df[ df.雇员 >= 100000 ]

现在来看一个「罕见」例子,假如我们想找到所有值为整数型的 columns

print( df.dtypes == 'int64' )df.loc[:,df.dtypes=='int64' ]

调用函数

调用函数是只能有一个参数(DataFrame,Series)并返回一组索引的函数。因为调用函数定义在loc,iloc,[] 里面,因此它就像在〖Python 入门篇 (下)〗提过的匿名函数。

当我们要找出交易量大于平均交易量的所有公司,我们可以用loc加上匿名函数 (这里 x 代表 df)。

df.loc[lambdax:x.交易量>x.交易量.mean(),:]

在上面基础上再加一个条件 -- 价格要在 100 之上 (这里 x 还是代表df)

df.loc[lambdax:(x.交易量>x.交易量.mean())&(x.价格>100),:]

最后来看看价格大于 100 的股票 (注意这里 x 代表 df.价格)

df.价格.loc[lambdax:x>100]

代号

BABA 176.92

AAPL 172.97

GS196.00

Name:价格,dtype:float64

3.6

多层索引

在Panel那节已经提到过,多层索引可以将「低维数据」升维到「高维数据」,此外,多层索引还可以。。。。

多层索引 Series

首先定义一个Series,注意它的index是一个二维列表,列表第一行dates作为第一层索引,第二行codes作为第二层索引。

price = [190,32,196,192,200,189,31,30,199]dates = ['-04-01']*3 + ['-04-02']*2+['-04-03']*2+ ['-04-04']*2codes = ['BABA','JD','GS','BABA','GS','BABA','JD','JD','GS']data = pd.Series( price, index=[ dates, codes ])data

-04-01 BABA 190

JD 32

GS196

-04-02 BABA 192

GS200

-04-03 BABA 189

JD 31

-04-04 JD 30

GS199

dtype:int64

这个Series存储了四天里若干股票的价格,-04-01储存了阿里巴巴、京东和高盛的股价,-04-04只储存了京东和高盛的股价。试想,如果不用多层索引的Series,我们需要用一个DataFrame来存储在这样的数据,把index设置成dates,把colums设置成codes。

让我们看看 Series 的多层 index 是如何表示的

data.index

MultiIndex(levels=[['-04-01', '-04-02', '-04-03', '-04-04'],

['BABA', 'GS', 'JD']],

labels=[[0, 0, 0, 1, 1, 2, 2, 3, 3],

[0, 2, 1, 0, 1, 0, 2, 2, 1]])

输出是一个MultiIndex的对象,里面有levels和labels二类信息。

知识点

索引既然分多层,那么肯定分「内层」和「外层」把,levels就是描述层的先后的。levels是一个二维列表,每一行只存储着「唯一」的索引信息:

dates 是第一层索引,有 4 个「唯一」元素

codes 是第二层索引,有 3 个「唯一」元素

但是data里面有九行啊,4个dates和3个codes怎么能描述这九行信息呢?这就需要labels了。labels也是一个二维列表:

第一行储存 dates 每个元素在 data 里的位置索引

第二行储存 codes 每个元素在 data 里的位置索引

用[]加第一层索引可以获取第一层信息。

data['-04-02']

BABA 192

GS 200

dtype:int64

同理,用loc加第一层索引也可以切片获取第一层信息。

data.loc['-04-02':'-04-04']

-04-02 BABA 192

GS200

-04-03 BABA 189

JD 31

-04-04 JD 30

GS199

dtype:int64

此外,切片还可以在不同层上进行,下面loc 中的冒号:表示第一层所有元素,‘GS’表示第二层标签为‘GS’。

data.loc[:,'GS']

-04-01 196

-04-02 200

-04-04 199

dtype:int64

多层索引 DataFrame

Series 只有 index,上面刚介绍完多层 index,DataFrame 有 index 和 columns,它们可以设置成多层吗?下面代码用 MultiIndex 函数创建「多层 index」midx 和「多层columns」mcol。

midx 和 mcol 都是对象,各种都有 levels, labels, names 等性质。

data = [ ['电商', 101550, 176.92, 16175610],['电商', 175336, 25.95, 27113291],['金融', 60348, 41.79, 10132145],['金融', 36600, 196.00, 2626634] ]midx = pd.MultiIndex( levels=[['中国','美国'],['BABA','JD','GS','MS']],labels=[[0,0,1,1],[0,1,2,3]],names=['地区','代号'])mcol = pd.MultiIndex( levels=[['公司数据','交易数据'],['行业','雇员','价格','交易量']],labels=[[0,0,1,1],[0,1,2,3]],names=['概括','细分'])df = pd.DataFrame(data, index=midx, columns=mcol)df

这个 DataFrame 的 index 和 columns 都有两层,严格来说是个四维数据。下面看看如何进行「多层索引」的操作吧。

在第一层 columns 的 ‘公司数据’ 和第二层 columns 的 ‘行业’ 做索引,得到一个含两层 index 的 Series。

# 1st level-1 column, 2nd level-2 columndf['公司数据','行业']

地区 代号

中国 BABA 电商

JD 电商

美国 GS 金融

MS 金融

Name: (公司数据, 行业), dtype: object

在第一层 index 的 ‘中国’ 做切片,得到一个含两层 columns 的 DataFrame。

df.loc['中国'].loc['BABA':'JD']

调位 level

如果你不喜欢 index level 的顺序,可用swaplevel将它们调位。

df.swaplevel('地区', '代号')

如果你不喜欢 columns level 的顺序,也可用 swaplevel将它们调位。

df.columns = df.columns.swaplevel(0,1)df

重设 index

有时候,一个 DataFrame 的一个或者多个 columns 适合做 index,这时可用set_index将它们设置为index,如果要将 index 还原成 columns,那么用 reset_index。

看下面这个例子。

data = {'地区': ['中国', '中国', '美国', '美国'], '代号': ['BABA', 'JD', 'MS', 'GS'], '行业': ['电商', '电商', '金融', '金融'], '价格': [176.92, 25.95, 41.79, 196.00], '交易量': [16175610, 27113291, 10132145, 2626634], '雇员': [101550, 175336, 60348, 36600] }df = pd.DataFrame( data )df

将「地区」和「代号」设置为第一层 index 和第二层 index。

df2 = df.set_index( ['地区','代号'] )df2

将所有 index 变成 columns。

df2.reset_index()

4总结

Pandas 里面的数据结构是多维数据表,细化为一维的 Series,二维的 DataFrame,三维的 Panel。

多维数据表=多维数组+描述

其中

Series=1darray+index

DataFrame=2darray+index+columns

Panel=3darray+index+columns+item

pd 多维数据表和 np 多维数组之间的类比关系如下图所示。

【创建数据表】创建 Series,DataFrame, Panel 用下面语句

pd.Series(x, index=idx)

pd.DataFrame(x, index=idx, columns=col)

pd.Panel(x, item=itm, major_axis=n1, minor_axis=n2)

DataFrame 由多个 Series 组成,Panel 有多个 DataFrame 组成。Series 非常类似于一维的 DataFrame,Panel 未来会被废掉,因此学 Pandas 把注意力放在 DataFrame 上即可。

【索引和切片数据表】在索引或切片 DataFrame,有很多种方法。最好记的而不易出错的是用基于位置的at和loc,和基于标签的 iat和iloc,具体来说,索引用at和iat,切片用loc和iloc。带i的基于位置,不带i的基于标签。

用 MultiIndex可以创建多层索引的对象,获取DataFrame df 的信息可用

df.loc[1st].loc[2nd]

df.loc[1st].iloc[2nd]

df.iloc[1st].loc[2nd]

df.iloc[1st].iloc[2nd]

要调换 level 可用

df.index.swaplevel(0,1)

df.columns.swaplevel(0,1)

要设置和重设 index 可用

df.set_index( columns )

df.reset_index

下篇讨论 Pandas 系列的后三节,分别是

「数据表的合并和连接」

「数据表的重塑和透视」

「数据表的分组和整合」

StayTuned!

如果觉得《pandas dataframe创建_Python数据分析基础之Pandas学习 (上)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。