第1章 探索性数据解析

万一能将数据与事实上措施相结合,就可以在存在不确定性时解答难点并辅导决策,那就是本书的焦点。

举个例子。我的妻子在怀第一胎时,我听到了一个题材:第一胎是否常事晚于预产期出生?下边所付出的案例探究就是由这么些题材引出的。

若是用谷歌(谷歌)搜索这些难题,会看到多量的议论。有人认为首先胎的生产日期确实平日晚于预产期,有人以为那是风言风语,还有人觉得有悖于,第一胎平时会难产。

在广大此类钻探中,人们会提供数据来援救自己的见地。我发觉众多实证是上边那样的。

“我有四个朋友新近都刚生了首个男女,她们都是跨越预产期大致两周才面世临产征兆或举行催产的。”

“我的率先个孩子是过了预产期两周才落地的,我觉着首个子女或许会宫外孕两周!”

“我认为那种说法不对,因为自身大姨子是头生子,而且是羊水栓塞儿。我还有好多表兄妹也是那样。”

那么些说法都是根据未公开的数量,平常来自个人经历,因而称为轶事证据(anecdotal
evidence)。在拉扯时讲讲轶事当然无可厚非,所以我并不是要批评以上那些人。

唯独,我们兴许需求更具说服力的凭据以及更有限接济的回答。若是按照那一个正式开展衡量,轶事证据平时都靠不住,原因有如下几点。

  • 观测值数量较小
    倘诺第一胎的孕期的确偏长,那一个日子差与正规的过错相比可能很小。在那种景观下,大家也许需要比对大批量的孕期数据,才能确定那种时刻差确实存在。
  • 分选数据时存在偏倚
    大千世界因而参加那几个标题的琢磨,有可能是因为自己的第三个子女出生较晚。那样的话,那个选项数据的长河就会对结果发生潜移默化。
  • 认同数据时存在偏倚
    同情那种说法的人可能更可能提供例子进行佐证。持猜疑态度的人则更可能引用反例。
  • 不精确
    轶事常常都是私家经历,平常会记错、误传或者误解等。

那大家该怎么更好地应对那么些难点啊?

数据结构简介

原文:Intro to Data
Structures

译者:usyiyi.cn

协议:CC BY-NC-SA
4.0

大家将率先连忙,非周详地概述pandas中的基本数据结构,来让您起步。数据类型,索引和轴标记/对齐的要旨行为适用于所有目标。为了起步,请导入numpy并将pandas加载到你的命名空间中:

In [1]: import numpy as np

In [2]: import pandas as pd

以下是一个为主尺度:数量对齐是内在的。标签和数据里面的链接不会被毁掉,除非你了解这样做。

俺们将简单介绍数据结构,然后在独立的章节中,考虑所有功用和章程的大类。

1.1 计算学方法

为了然决轶事证据的局限性,大家将利用以下总计学工具。

  • 数据搜集
    我们将采用大型的全国性调查数量,这些调查专门布署用来对花旗国人口开展实用的统计测算。
  • 描述性计算
    得出计算量,对数据进行简单的集中,并评估可视化数据的两样措施。
  • 批判性数据解析
    追寻各个格局、差距,以及别的可以解决大家感兴趣的题材的性状,同时还将检查数据的分歧性,发现局限性。
  • 估计
    行使样本数量来打量一般总体的计算特征。
  • 假使检验
    倘使见到显明的作用,例如多个群组之间存在差异,将衡量该意义是还是不是是偶然发生的。

小心执行上边的手续,并避免各类不当,我们就足以取得合理性和准确性更高的下结论。

Series(序列)

Series是富含标签的一维数组,可以保存任何数据类型(整数,字符串,浮点数,Python对象等)。轴标签统称为索引。创制Series的基本格局是调用:

>>> s = pd.Series(data, index=index)

这里,data可以是多如牛毛两样的事物:

  • Python dict(字典)
  • ndarray
  • 标量值(如5)

传入的索引是轴标签的列表。因而,根据数码的类型,分为以下二种景况:

来自ndarray

如果data是ndarray,则索引必须与数据长度相同。即使没有传递索引,将创造值为[0, ..., len(data) - 1]的索引。

In [3]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])

In [4]: s
Out[4]: 
a    0.2735
b    0.6052
c   -0.1692
d    1.8298
e    0.5432
dtype: float64

In [5]: s.index
Out[5]: Index([u'a', u'b', u'c', u'd', u'e'], dtype='object')

In [6]: pd.Series(np.random.randn(5))
Out[6]: 
0    0.3674
1   -0.8230
2   -1.0295
3   -1.0523
4   -0.8502
dtype: float64

注意

从v0.8.0开头,pandas支持非唯一索引值。假设尝试进行不辅助重复索引值的操作,那么将会引发这一个。延迟的案由大致都依据品质(在计算中有那么些实例,例如
GroupBy 的有的不行使索引)。

源于字典

如果data是字典,那么一旦传入了index,则会取出数据中的值,对应于索引中的标签。否则,要是可能,将从字典的不变键构造索引。

In [7]: d = {'a' : 0., 'b' : 1., 'c' : 2.}

In [8]: pd.Series(d)
Out[8]: 
a    0.0
b    1.0
c    2.0
dtype: float64

In [9]: pd.Series(d, index=['b', 'c', 'd', 'a'])
Out[9]: 
b    1.0
c    2.0
d    NaN
a    0.0
dtype: float64

注意

NaN(不是数字)是用于pandas的正经缺失数据符号

从标量值:如果data是标量值,则必须提供索引。该值会重新,来协作索引的长度。

In [10]: pd.Series(5., index=['a', 'b', 'c', 'd', 'e'])
Out[10]: 
a    5.0
b    5.0
c    5.0
d    5.0
e    5.0
dtype: float64

1.2 全国家庭增加调查

从1973年起,美国疾病控制和预防要旨(CDC)就开端开展全国家庭增加调查(NSFG,http://cdc.ogv/nchs/nsfg.htm),以募集“与家中生活、婚姻情形、妊娠情形、生育意况、避孕情形,以及两性健康有关的信息。此项调查的结果用于……进行正常服务和正常教育类其余宏图,以及对家园、生育及常规状态展开统计然究”。

我们将选用这项调查搜集到的多少探究第一胎是或不是出生较晚,并解答一些任何难题。为了有效地使用那一个数量,我们必须驾驭那项探讨是怎么陈设的。

全国家庭增加调查是一项横截面(cross-sectional)探讨,也就是说该钻探捕获的是一个群组在某一随时的快照。在横截面研商之外,最广大的是纵向(longitudinal)研商,指在一个日子段内再度观望一个群组。

全国家庭拉长调查进展过7次,每五遍都叫作一个周期(cycle)。大家将运用第6次的多寡,其时间段为2002年十一月至二〇〇三年八月。

那项考察的目的是对一个总体(population)得出结论。全国家庭拉长调查的靶子完全是居住在美利坚合众国、年龄在15~44岁的人。理想状态下,调查要搜集那几个共同体中每个成员的数码,但那是不容许达成的。实际上,大家收集了这些共同体的一个子集的多寡,这几个子集称为样本(sample)。参预查证的人誉为查明参加者56net亚洲必赢手机,(respondent)。

平时来说,横截面研商应该是有代表性(representative)的,也就是说目标总体中每个成员参预查证的机会均等。那种优良条件在实践中很难落实,不过进展调研的人口会竭尽所能满意那么些条件。

全国家庭增加调查不富有代表性,而是特意进行过火抽样(oversample)。那项探究的设计者招募了拉美裔美利坚联邦合众国人、亚洲裔米利坚人和青少年3个群组的插足者,每个群组的征召比例都领先其在米国总人口中所占的比重,以担保各群组的参预者数量丰盛多,从而举办实用的计算测算。

自然,过度抽样也有缺点,那就是不易于从调查的统计数据中得出关于全部的定论。大家稍后会对此展开钻探。

在动用那种调查数据时,大家亟须熟习代码本(codebook),那一点极度关键。代码本记录了一项研究的宏图、使用的调查难题,以及调研中一呼百应变量的编码。你可以从花旗国疾病控制和预防中央的网站(http://www.cdc.gov/nchs/nsfg/nsfg_cycle6.htm)下载全国家庭拉长调查数据的代码本和使用手册。

Series 是类似于 ndarray 的

Series的功能与ndarray分外相像,是绝大部分NumPy函数的管事参数。但是,像切片那样的事物也会对索引切片。

In [11]: s[0]
Out[11]: 0.27348116325673794

In [12]: s[:3]
Out[12]: 
a    0.2735
b    0.6052
c   -0.1692
dtype: float64

In [13]: s[s > s.median()]
Out[13]: 
b    0.6052
d    1.8298
dtype: float64

In [14]: s[[4, 3, 1]]
Out[14]: 
e    0.5432
d    1.8298
b    0.6052
dtype: float64

In [15]: np.exp(s)
Out[15]: 
a    1.3145
b    1.8317
c    0.8443
d    6.2327
e    1.7215
dtype: float64

俺们将在独立的章节中强调基于数组的目录。

1.3 数据导入

本书所用的代码和数量都能够通过GitHub(https://github.com/AllenDowney/ThinkStats2)获取。前言中牵线了如何下载和接纳那几个代码。

下载代码后,你会拿走一个名为ThinkStats2/code的公文夹,其中富含一个名为nsfg.py的文件。运行nsfg.py会读取数据文件,执行测试,然后打印出一条音信,例如“All
test passed”。

让大家看看那个文件所实施的办事。第6次全国家庭增加调查的妊娠数据保存在名为2002FemPreg.dat.gz的文书中,那是一个纯文本(ASCII码)方式的gzip压缩文件,有定点宽度的列。这些文件中的每一行都是一个记录(record),包含五遍怀孕的数据。

2002FemPreg.dct是一个Stata字典文件,记录了数据文件的格式。Stata是一个总计软件。Stata“字典”是由变量名、变量类型及标识变量地方的索引值组成的列表。

上面几行摘自2002FemPreg.dct:

infile dictionary { 
  _column(1) str12 caseid %12s "RESPONDENT ID NUMBER" 
  _column(13) byte pregordr %2f "PREGNANCY ORDER (NUMBER)" 
}

其一字典描述了三个变量:caseid是一个长短为12的字符串,代表调查插手者的ID;pregorder是一个单字节整数,表达那条记下描述的是那位调查参加者的第四次怀孕。

下载的代码包罗一个thinkstats2.py文本,这是一个Python模块,包罗了本书中用到的很多类和函数,其中有读取Stats字典和全国家庭增加调查数据文件的函数。那多个函数在nsfg.py中的用法如下:

def ReadFemPreg(dct_file='2002FemPreg.dct', 
                dat_file='2002FemPreg.dat.gz'): 
    dct = thinkstats2.ReadStataDct(dct_file) 
    df = dct.ReadFixedWidth(dat_file, compression='gzip') 
    CleanFemPreg(df) 
    return df

ReadStataDct的参数是字典文件名,再次回到值dct是一个FixedWidthVariables对象,其中含有从字典文件中得到的音信。dct对象提供ReadFixdWidth办法举办数据文件的读取。

Series 类似于字典

Series就如一个一定大小的字典,您可以经过行使标签作为目录来获得和设置值:

In [16]: s['a']
Out[16]: 0.27348116325673794

In [17]: s['e'] = 12.

In [18]: s
Out[18]: 
a     0.2735
b     0.6052
c    -0.1692
d     1.8298
e    12.0000
dtype: float64

In [19]: 'e' in s
Out[19]: True

In [20]: 'f' in s
Out[20]: False

如若标签不存在,则会出现非常:

>>> s['f']
KeyError: 'f'

使用get方法,缺失的标签将回到None或指定的默许值:

In [21]: s.get('f')

In [22]: s.get('f', np.nan)
Out[22]: nan

另请参阅特性访问部分。

1.4 DataFrame

ReadFixedWidth办法再次回到一个DataFrame对象。DataFrame是pandas提供的根基数据结构。pandas是一个Python数据和总括包,它的使用会贯穿本书。在DataFrame中,每个记录为一行(在我们的例证中就是每个妊娠数据为一行),每个变量为一列。

除去数据,DataFrame还带有变量名和变量类型信息,并提供访问和修改数据的不二法门。

如若打印df对象,你相会到其中行列的一些数据和DataFrame的分寸:13
593行/记录,244列/变量。

>>> import nsfg
>>> df = nsfg.ReadFemPreg()
>>> df
...
[13593 rows x 244 columns]

dfcolumns特性将列名重返为一列Unicode字符串。

>>> df.columns
Index([u'caseid', u'pregordr', u'howpreg_n', u'howpreg_p', ... ])

df.columns的结果是一个Index对象,Index也是一个pandas数据结构。大家稍后会详细介绍Index,现在得以暂时将其就是一个列表。

>>> df.columns[1]
'pregordr'

要访问DataFrame中的一列,你可以将列名作为键值。

>>> pregordr = df['pregordr']
>>> type(pregordr)
<class 'pandas.core.series.Series'>

其结果是一个Series对象,那又是一个pandas数据结构。Series与Python列表类似,还可以提供部万分加功用。打印一个Series对象会得到索引和呼应的数值。

>>> pregordr
0     1
1     2
2     1
3     2
...
13590    3
13591    4
13592    5
Name: pregordr, Length: 13593, dtype: int64

那个示例中的索引是从0到13
592的平头,但一般索引可以动用另外可排序的数据类型。这一个示例中的元素也是整数,但元素得以是其他类型的。

示范中的最终一行列出了变量名、Series长度和数据类型。int64是NumPy提供的花色之一。若是在32位机器上运行那么些示例,得到的数据类型可能是int32

您能够应用整数的index和slice值访问Series中的元素。

>>> pregordr[0]
1
>>> pregordr[2:5]
2    1
3    2 
4    3
Name: pregordr, dtype: int64

index操作符的结果是int64,slice的结果要么一个Series。

您也得以使用点标记法来访问DataFrame中的列。

>>> pregordr = df.pregordr

只有当列名为官方的Python标识符时(即以字母开始,不包括空格等),才能接纳那种写法。

Series 的向量化操作和标签对齐

开展数量解析时,像原始NumPy数组一样,一个值一个值地循环遍历连串寻常不是必需的。Series
也足以传递给超过半数期望 ndarray 的 NumPy 方法。

In [23]: s + s
Out[23]: 
a     0.5470
b     1.2104
c    -0.3385
d     3.6596
e    24.0000
dtype: float64

In [24]: s * 2
Out[24]: 
a     0.5470
b     1.2104
c    -0.3385
d     3.6596
e    24.0000
dtype: float64

In [25]: np.exp(s)
Out[25]: 
a         1.3145
b         1.8317
c         0.8443
d         6.2327
e    162754.7914
dtype: float64

Series 和 ndarray 之间的严重性分歧是,Series
上的操作会依据标签自动对齐多少。因而,您可以编写计算,而不考虑所波及的
Series 是不是具备同样标签。

In [26]: s[1:] + s[:-1]
Out[26]: 
a       NaN
b    1.2104
c   -0.3385
d    3.6596
e       NaN
dtype: float64

未对齐的 Series 之间的演算结果,将所有所波及的目录的并集。倘若在一个
Series
或任何一连串中找不到某个标签,则结果将标志为NaN(缺失)。编写代码而不开展任何显式的多少对齐的能力,在交互式数据解析和钻研中提供了巨大的肆意和灵活性。pandas数据结构所集成的数量对齐特性,将pandas与用于拍卖标记数据的多数有关工具分别。

注意

相似的话,大家选择使索引不相同的靶子期间的操作的默认结果为union,来防止音信的不见。尽管缺乏数据,拥有索引标签常常是任重先生而道远音讯,作为计算的一有些。您当然可以经过dropna函数,选拔撇下带有缺失数据的标签。

1.5 变量

俺们早就运用了举国上下家庭增加调查数量集中的五个变量——caseidpregordr,还看到数据汇总共有244个变量。本书的革命性分析用到如下变量。

  • caseid:调查参预者的整数ID。
  • prglength:妊娠周数,是一个整数。
  • outcome:怀孕结果的平头代码。1意味成功生产。
  • pregordr:妊娠的顺序号。例如,一位调查参与者的第一遍怀孕为1,第二次为2,以此类推。
  • birthord:成功生产的顺序号,一位调查参加者的率先个孩子代码为1,以此类推。对尚未中标生产的别样怀孕结果,此字段为空。
  • birthwgt_lbbirthwgt_oz:新生儿体重的磅部分数值和盎司部分数值。
  • agepreg:妊娠截止时姨妈的岁数。
  • finalwgt:调查加入者的计算权重。这是一个浮点数,表示那位调查参加者在全雅观的女子口中代表的食指。

假诺您细心翻阅了代码本,就会发觉那些变量中众多都是重编码(recode),也就是说那几个不是考察收集的本来数据(raw
data),而是利用原有数据测算获得的。

诸如,假若成功生产,prglngth的值就与原有变量wksgest(妊娠周数)相等;否则,prglngth的值估计为`mosgest

  • 4.33`(妊娠月数乘以一个月的平均周数)。

重编码平常都基于一定的逻辑,这种逻辑用于检查数据的一致性和准确性。一般景色下,假诺数据中存在重编码,大家就直接使用,除非有破例的由来需求自己处理原始数据。

名称属性

Series仍能享有name属性:

In [27]: s = pd.Series(np.random.randn(5), name='something')

In [28]: s
Out[28]: 
0    1.5140
1   -1.2345
2    0.5666
3   -1.0184
4    0.1081
Name: something, dtype: float64

In [29]: s.name
Out[29]: 'something'

在大部分景色下,Series 的name会活动赋值,尤其是收获 DataFrame
的一维切片时,您将在上边看到它。

本子0.18.0中的新职能。

你可以动用pandas.Series.rename()方法来重命名
Series。

In [30]: s2 = s.rename("different")

In [31]: s2.name
Out[31]: 'different'

注意,ss2本着分化的靶子。

1.6 数据变换

导入调查数量时,平常索要检查数据中是或不是留存不当,处理非凡值,将数据转换为不相同的格式并开展测算。那么些操作都称之为数据清洗(data
cleaning)。

nsfg.py包涵一个CleanFemPreg函数,用于清洗安插选用的变量。

def CleanFemPreg(df): 
    df.agepreg /= 100.0

    na_vals = [97, 98, 99]
    df.birthwgt_lb.replace(na_vals, np.nan, inplace=True)
    df.birthwgt_oz.replace(na_vals, np.nan, inplace=True)

    df['totalwgt_lb'] = df.birthwgt_lb + df.birthwgt_oz / 16.0

agepreg带有大姑在怀孕为止时的岁数。在数据文件中,agepreg是以百分之一年为单位的整数值。由此CleanFemPreg的率先行将各类agepreg除以100,从而赢得以年为单位的浮点数值。

birthwgt_lbbirthwgt_oz含蓄成功生产时的难产儿体重,分别是磅和盎司的片段。那多少个变量还选用多少个独特的代码。

97 NOT ASCERTAINED 
98 REFUSED 
99 DON'T KNOW

用数字编码特殊值是一种危险的做法,因为一旦没有展开不易的处理,这几个数字也许暴发虚假结果,例如,99磅重的新生儿。replace措施可以将这个值替换为np.nan,那是一个奇特的浮点数值,表示“不是数字”。replace主意应用inplace标识,表明直接修改现有的Series对象,而不是开立异目的。

IEEE浮点数表示法标准中规定,在任何算术运算中,假设有参数为nan,结果都回去nan

>>> import numpy as np
>>> np.nan / 100.0
nan

因此使用nan拓展统计会取得正确的结果,而且多数的pandas函数都能恰当地处理nan。但大家常常必要处理数量缺失的题材。

CleanFemPreg函数的终极一行生成一个新列totalwgt_lb,将磅和盎司值结合在联名,获得一个以磅为单位的值。

急需注意的是,向DataFrame添加新列时,必须运用如下字典语法:

# 正确 
df['totalwgt_lb'] = df.birthwgt_lb + df.birthwgt_oz / 16.0 

而不是选拔点标记:

# 错误!
df.totalwgt_lb = df.birthwgt_lb + df.birthwgt_oz / 16.0

应用点标记的写法会给DataFrame对象添加一个新属性,而不是创建一个新列。

DataFrame(数据帧)

DataFrame是富含标签的二维数据结构,列的档次或者差别。你可以把它想象成一个电子表格或SQL表,或者
Series 对象的字典。它一般是最常用的pandas对象。像 Series 一样,DataFrame
接受广大两样品类的输入:

  • 一维数组,列表,字典或 Series 的字典
  • 二维 numpy.ndarray
  • 结构化或记录
    ndarray
  • Series
  • 另一个DataFrame

和数据一起,您可以选择传递index(行标签)和columns(列标签)参数。若是传递索引或列,则会用来转移的DataFrame的目录或列。由此,Series
的字典加上一定索引将甩掉所有不匹配传入索引的数码。

一旦轴标签未通过,则它们将基于常识规则从输入数据构造。

1.7 数据表明

当数码从一个软件条件导出,再导入另一个条件时,可能会生出错误。假使不谙习新数据集,可能会对数码举行不正确的解释,或者引入其余的误会。借使能抽出部分时光展开数据证实,就足以节省后续可能开支的小运,幸免可能出现的荒谬。

表明数据的一种格局是统计基本的总计量,并与已发表的结果开展比较。例如,全国家庭拉长调查的代码本为每个变量提供了概要表。outcome变量对每个妊娠结果开展了编码,其概要表如下:

value label       Total 
1 LIVE BIRTH          9148 
2 INDUCED ABORTION    1862 
3 STILLBIRTH           120 
4 MISCARRIAGE         1921 
5 ECTOPIC PREGNANCY    190 
6 CURRENT PREGNANCY    352

Series类提供了一个value_counts艺术,可用来计算每个值出现的次数。若是获得DataFrame中的outcome Series,大家得以行使value_counts主意,将结果与已披露的多少开展相比较。

>>> df.outcome.value_counts().sort_index()
1    9148
2    1862
3     120
4    1921 
5     190 
6     352

value_counts归来的结果是一个Series对象。sort_index办法将Series对象按索引排序,使结果按序呈现。

俺们将获取的结果与官方公布的报表举办自查自纠,outcome变量的值如同从未难点。类似地,已公布的关于birthwgt_lb的概要表如下:

value label                Total 
. INAPPLICABLE          4449 
0-5 UNDER 6 POUNDS        1125 
6 6 POUNDS              2223 
7 7 POUNDS              3049 
8 8 POUNDS              1889 
9-95 9 POUNDS OR MORE       799

birthwgt_lbvalue_counts结果如下:

>>> df.birthwgt_lb.value_counts(sort=False) 
0        8 
1       40 
2       53 
3       98 
4      229 
5      697 
6     2223 
7     3049 
8     1889 
9      623 
10     132 
11      26 
12      10 
13       3 
14       3 
15       1 
51       1

数值6、7、8的产出次数是没错的。假如统计出0~5和9~95的次数,结果也是科学的。不过,假诺再看仔细些,你会发觉有一个数值肯定是错的——一个51磅的赤子!

为了处理这几个荒唐,可以在CleanFemPreg中进入一行代码。

df.birthwgt_lb[df.birthwgt_lb > 20] = np.nan

那行代码将地下值替换为np.nan。方括号中的表达式爆发一个bool连串的Series对象,值为True表示满意该条件。当一个布尔Series用作索引时,它只拔取满意该原则的元素。

出自 Series 或字典的字典

结果的index是各个名目繁多索引的并集。借使有此外嵌套的词典,这几个将首先转换为Series。如果列没有传递,那几个列将是字典的键的平稳列表。

In [32]: d = {'one' : pd.Series([1., 2., 3.], index=['a', 'b', 'c']),
 ....:      'two' : pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}
 ....: 

In [33]: df = pd.DataFrame(d)

In [34]: df
Out[34]: 
 one  two
a  1.0  1.0
b  2.0  2.0
c  3.0  3.0
d  NaN  4.0

In [35]: pd.DataFrame(d, index=['d', 'b', 'a'])
Out[35]: 
 one  two
d  NaN  4.0
b  2.0  2.0
a  1.0  1.0

In [36]: pd.DataFrame(d, index=['d', 'b', 'a'], columns=['two', 'three'])
Out[36]: 
 two three
d  4.0   NaN
b  2.0   NaN
a  1.0   NaN

经过拜访indexcolumn品质可以分级走访行和列标签:

注意

而且传入一组特定的列和数据的字典时,传入的列将覆盖字典中的键。

In [37]: df.index
Out[37]: Index([u'a', u'b', u'c', u'd'], dtype='object')

In [38]: df.columns
Out[38]: Index([u'one', u'two'], dtype='object')

1.8 解释多少

要想有效行使数据,就必须同时在三个层面上思考难点:总结学层面和上下文层面。

譬如,让大家看一看几位调查到场者的outcome队列。由于数据文件的团伙措施,大家不可能不举行部分甩卖才能收获每位调查到场者的妊娠数据。以下函数已毕了俺们须求的拍卖:

def MakePregMap(df): 
    d = defaultdict(list) 
    for index, caseid in df.caseid.iteritems(): 
        d[caseid].append(index) 
    return d

df是富含妊娠数据的DataFrame对象。iteritems办法遍历所有妊娠记录的目录(行号)和caseid

d是将每个caseID炫耀到一列索引的字典。假设您不熟习defaultdict,可以到Python的collections模块中查看其定义。使用d,大家得以搜寻一位调查参预者,得到其怀孕数据的目录。

上面的以身作则就摸索了一位调查加入者,并打印出其怀孕结果列表:

>>> caseid = 10229
>>> indices = preg_map[caseid]
>>> df.outcome[indices].values
[4 4 4 4 4 4 1]

indices是调查到场者10229的大肚子记录索引列表。

以这些列表为索引可以访问df.outcome中指定的行,获得一个Series。上边的言传身教没有打印整个Series对象,而是选用输出values属性,那个特性是一个NumPy数组。

出口结果中的代码1代表成功分身。代码4表示新生儿窒息,即自发终止的怀孕,终止原因日常未知。

从统计学上看,那位调查参预者并无不胜。宫外孕并不少见,其余一些调研插手者的泡汤次数相同或者更加多。

只是考虑到上下文,那一个数量证实一位女性怀孕6次,每一次都以难产告终。她第7次也是近日一回怀孕成功产下了儿女。假诺我们抱着同情心看待这一个数据,就很不难被数据背后的故事打动。

全国家庭拉长调查数据汇总的每一条记下都意味一位到场者,这几个加入者诚实地回答了不少这几个私密而且难以应对的题材。我们可以利用这一个多少解答与家园生活、生育和常规城门失火的总括学难点。同时,大家有分文不取思及那几个数量所代表的出席者,对他们心存敬意和感谢。

来自 ndarrays / lists 的字典

ndarrays
必须长度相同。即便传入了目录,它必须也与数老板度相同。如若没有传到索引,结果将是range(n),其中n是数COO度。

In [39]: d = {'one' : [1., 2., 3., 4.],
 ....:      'two' : [4., 3., 2., 1.]}
 ....: 

In [40]: pd.DataFrame(d)
Out[40]: 
 one  two
0  1.0  4.0
1  2.0  3.0
2  3.0  2.0
3  4.0  1.0

In [41]: pd.DataFrame(d, index=['a', 'b', 'c', 'd'])
Out[41]: 
 one  two
a  1.0  4.0
b  2.0  3.0
c  3.0  2.0
d  4.0  1.0

1.9 练习

  • 练习1.1

    你下载的代码中应有有一个名为chap01ex.ipynb的文书,那是一个IPython记事本。你可以用如下命令从命令行启动IPython记事本:

    $ ipython notebook &

    即使系统设置了IPython,会启动一个在后台运行的服务器,并打开一个浏览器查看记事本。倘使你不熟识IPython,我提议您从IPython网站(http://ipython.org/ipython-doc/stable/notebook/notebook.html)先导攻读。

    您能够增进一个下令行选项,使图片在“行内”(即在记事本中)展现,而非弹出窗口:

    $ ipython notebook --pylab=inline &

    打开chap01ex.ipynb。记事本中有的单元已经填好了代码,能够一直实施。其余单元列出了你应当尝试的陶冶。

    本磨练的参考答案在chap01soln.ipynb中。

  • 练习1.2

    创造一个名为chp01ex.py的文本,编写代码,读取出席者文件2001FemResp.dat.gz。你可以复制nsfg.py文件并对其举办修改。

    变量pregnum是一个重编码,用于讲明每位调查参预者有过些微次怀孕经历。打印这么些变量中差异值的面世次数,将结果与全国家庭拉长调查代码本中发表的结果开展比较。

    你也得以将每人调查参预者的pregnum值与妊娠文件中的记录数举行相比,对查证参加者文件和怀孕文件进行交叉验证。

    你可以运用nsfg.MakePregMap扭转一个字典,将各样caseid辉映到妊娠DataFrame的目录列表。

    本训练的参考答案在chp01soln.py中。

  • 练习1.3

    读书总括学的最好法子是行使一个你感兴趣的品类。你想钻探“第一胎是不是都会晚出生”那样的题材吗?

    请想想一些您个人感兴趣的难题,可以是传统理念、争议话题或影响政局的题材,看是或不是可以构想出一个能以总括调查举办求证的标题。

    找寻能帮助你答应这么些难点的多少。公共研讨的多寡经常可防止费得到,因而政党网站是很好的数据来源于,如http://www.data.gov/http://www.science.gov/。倘使想博得大不列颠及北爱尔兰联合王国的数码,可以访问http://data.gov.uk/

    自我个人最热衷的七个数据集是General Social
    Survey(http://www3.norc.org/gss+website/)和European Social
    Survey(http://www.europeansocialsurvey.org)。

    借使有人接近已经解答了你的题材,那么细心检查该回应是不是创立。数据和分析中或许存在的短处都会使结论不可信。假使发现人家的解答存在难题,你可以对同样的数量开展不相同的解析,或者搜索更好的数目来源。

    假如有一篇杂谈解答了你的难题,那么您应该力所能及得到舆论使用的原本数据。很多随想小编会把数据放在网上供我们使用,但借使波及敏感新闻,你可能须求向作者来信索要,提供您安排怎样利用这一个数据的音讯,或者同意某些使用条款。百折不回就是获胜!

发源结构化或记录数组

这种场所与数组的字典相同。

In [42]: data = np.zeros((2,), dtype=[('A', 'i4'),('B', 'f4'),('C', 'a10')])

In [43]: data[:] = [(1,2.,'Hello'), (2,3.,"World")]

In [44]: pd.DataFrame(data)
Out[44]: 
 A    B      C
0  1  2.0  Hello
1  2  3.0  World

In [45]: pd.DataFrame(data, index=['first', 'second'])
Out[45]: 
 A    B      C
first   1  2.0  Hello
second  2  3.0  World

In [46]: pd.DataFrame(data, columns=['C', 'A', 'B'])
Out[46]: 
 C  A    B
0  Hello  1  2.0
1  World  2  3.0

注意

DataFrame并不打算完全类似二维NumPy ndarray一样。

1.10 术语

  • 轶事证据(anecdotal evidence)

    随便采访,而非通过精心设计的切磋取得的凭据,平常是私房证据。

  • 总体(population)

    在探究中,大家感兴趣的群组。“总体”日常指一组人,但以此词也得以用来其余对象。

  • 横截面商量(cross-sectional study)

    募集一个全部在某个特定时间点的数量的研讨。

  • 周期(cycle)

    在再一次进行的横截面研商中,每一遍啄磨称为一个周期。

  • 纵向研讨(longtitudinal study)

    在一段时间内跟踪一个完整的钻研,从同一个群体重复收集数据。

  • 记录(record)

    在数据集中,关于单个人或其余对象的音信集合。

  • 调查参加者(respondent)

    参加调研的人。

  • 样本(sample)

    一体化中用来数据收集的一个子集。

  • 有代表性(representative)

    只要完全中的每个成员被选入样本的火候都均等,那么那几个样本就是有代表性的。

  • 过度抽样(oversampling)

    一种通过扩大一个子一体化的样本数来防止因样本规模过小暴发错误的技术。

  • 本来数据(raw data)

    从未通过或只通过简单检查、统计或表明,直接采访和笔录的值。

  • 重编码(recode)

    因此测算和拔取于原来数据的其它逻辑变化的值。

  • 数码清洗(data cleaning)

    数据处理进程,包含数据讲明、错误检查,以及数据类型和表示的变换等。

from: http://www.ituring.com.cn/tupubarticle/3914

源于字典的数组

In [47]: data2 = [{'a': 1, 'b': 2}, {'a': 5, 'b': 10, 'c': 20}]

In [48]: pd.DataFrame(data2)
Out[48]: 
 a   b     c
0  1   2   NaN
1  5  10  20.0

In [49]: pd.DataFrame(data2, index=['first', 'second'])
Out[49]: 
 a   b     c
first   1   2   NaN
second  5  10  20.0

In [50]: pd.DataFrame(data2, columns=['a', 'b'])
Out[50]: 
 a   b
0  1   2
1  5  10

起点元组的字典

您可以透过传递元组字典来机关创制多索引的 DataFrame

In [51]: 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[51]: 
 a              b 
 a    b    c    a     b
A B  4.0  1.0  5.0  8.0  10.0
 C  3.0  2.0  6.0  7.0   NaN
 D  NaN  NaN  NaN  NaN   9.0

来自单个 Series

结果是一个 DataFrame,索引与输入的 Series 相同,并且单个列的名号是
Series 的原来名称(仅当没有提供任何列名时)。

缺失数据

缺失数据部分中,将对此主题展开更加多表达。为了协会具有缺失数据的DataFrame,请将np.nan用以缺失值。或者,您可以将numpy.MaskedArray作为数据参数传递给DataFrame构造函数,它屏蔽的条规将视为缺失值。

预备构造函数

DataFrame.from_dict

DataFrame.from_dict接受字典的字典或相近数组的队列的字典,并赶回DataFrame。它的操作看似DataFrame的构造函数,除了默许意况下为'columns'orient参数,但它可以安装为'index',以便将字典的键用作行标签。

DataFrame.from_records

DataFrame.from_records第二届元组的列表或带有结构化dtype的ndarray。它的干活办法接近于正规DataFrame构造函数,除了索引可能是结构化dtype的特定字段。例如:

In [52]: data
Out[52]: 
array([(1, 2.0, 'Hello'), (2, 3.0, 'World')], 
 dtype=[('A', '<i4'), ('B', '<f4'), ('C', 'S10')])

In [53]: pd.DataFrame.from_records(data, index='C')
Out[53]: 
 A    B
C 
Hello  1  2.0
World  2  3.0

DataFrame.from_items

DataFrame.from_items类似于字典的构造函数,它承受键 值对的连串,其中的键是列标签(或在orient ='index'的情事下是行标签),值是列的值(或行的值)。对于构建列为特定的各类的DataFrame,而不要传递明确的列的列表,它可怜管用:

In [54]: pd.DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])])
Out[54]: 
 A  B
0  1  4
1  2  5
2  3  6

设若你传入orient='index',键将是行标签。但在那种情景下,您还非得传递所需的列名称:

In [55]: pd.DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])],
 ....:                         orient='index', columns=['one', 'two', 'three'])
 ....: 
Out[55]: 
 one  two  three
A    1    2      3
B    4    5      6

列的精选、添加、删除

你可以在语义上,将 DataFrame 当做 Series
对象的字典来处理。列的拿走,设置和删除的方法与字典操作的语法相同:

In [56]: df['one']
Out[56]: 
a    1.0
b    2.0
c    3.0
d    NaN
Name: one, dtype: float64

In [57]: df['three'] = df['one'] * df['two']

In [58]: df['flag'] = df['one'] > 2

In [59]: df
Out[59]: 
 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

列可以像字典一样删除或弹出:

In [60]: del df['two']

In [61]: three = df.pop('three')

In [62]: df
Out[62]: 
 one   flag
a  1.0  False
b  2.0  False
c  3.0   True
d  NaN  False

当插入一个标量值时,它自然会播放来填充该列:

In [63]: df['foo'] = 'bar'

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

当插入的 Series 与 DataFrame 的目录不一样时,它将适配 DataFrame 的目录:

In [65]: df['one_trunc'] = df['one'][:2]

In [66]: df
Out[66]: 
 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 [67]: df.insert(1, 'bar', df['one'])

In [68]: df
Out[68]: 
 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

选用办法链来成立新的列

本子0.16.0中的新职能。

dplyrmutate动词的启示,DataFrame
拥有assign()方法,允许你随意创设新的列,它可能从现有列派生。

In [69]: iris = pd.read_csv('data/iris.data')

In [70]: iris.head()
Out[70]: 
 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 [71]: (iris.assign(sepal_ratio = iris['SepalWidth'] / iris['SepalLength'])
 ....:      .head())
 ....: 
Out[71]: 
 SepalLength  SepalWidth  PetalLength  PetalWidth         Name  sepal_ratio
0          5.1         3.5          1.4         0.2  Iris-setosa       0.6863
1          4.9         3.0          1.4         0.2  Iris-setosa       0.6122
2          4.7         3.2          1.3         0.2  Iris-setosa       0.6809
3          4.6         3.1          1.5         0.2  Iris-setosa       0.6739
4          5.0         3.6          1.4         0.2  Iris-setosa       0.7200

上边是插入预总结值的以身作则。我们还足以传递函数作为参数,那一个函数会在
DataFrame 上调用,结果会添加给 DataFrame。

In [72]: iris.assign(sepal_ratio = lambda x: (x['SepalWidth'] /
 ....:                                      x['SepalLength'])).head()
 ....: 
Out[72]: 
 SepalLength  SepalWidth  PetalLength  PetalWidth         Name  sepal_ratio
0          5.1         3.5          1.4         0.2  Iris-setosa       0.6863
1          4.9         3.0          1.4         0.2  Iris-setosa       0.6122
2          4.7         3.2          1.3         0.2  Iris-setosa       0.6809
3          4.6         3.1          1.5         0.2  Iris-setosa       0.6739
4          5.0         3.6          1.4         0.2  Iris-setosa       0.7200

assign 始终回到数据的副本,而保留原始DataFrame不变。

传递可调用对象,而不是要插入的实际值,当你没有存活 DataFrame
的引用时,它很有用。在操作链中采取assign时,那很宽泛。

In [73]: (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[73]: <matplotlib.axes._subplots.AxesSubplot at 0x7ff286891b50>

56net亚洲必赢手机 1

http://pandas.pydata.org/pandas-docs/version/0.19.2/\_images/basics\_assign.png

由于传入了一个函数,由此该函数在 DataFrame 上求值。主要的是,那一个DataFrame 已经过滤为 sepal 长度当先 5
的那个行。首先进行过滤,然后总结比值。那是一个示范,其中大家尚无被过滤的
DataFrame的可用引用。

assign函数的参数是**kwargs。键是新字段的列名称,值是要插入的值(例如,Series或NumPy数组),或者是个函数,它在DataFrame上调用。再次来到原始DataFrame的副本,它插入了新值。

警告

由于assign的函数签名为**kwargs,由此不可以确保在发生的DataFrame中,新列的依次与传递的依次一致。为了使业务可预测,条目按字典序(按键)插入到
DataFrame 的结尾。

首先总计有所表明式,然后赋值。由此,在assign的一样调用中,您不可能引用要赋值的另一列。例如:

In [74]: # Don't do this, bad reference to `C`
 df.assign(C = lambda x: x['A'] + x['B'],
 D = lambda x: x['A'] + x['C'])
In [2]: # Instead, break it into two assigns
 (df.assign(C = lambda x: x['A'] + x['B'])
 .assign(D = lambda x: x['A'] + x['C']))

索引 / 选取

目录的焦点措施如下:

操作 语法 结果
选择列 df[col] Series
按标签选择行 df.loc[label] Series
按整数位置选择行 df.iloc[loc] Series
对行切片 df[5:10] DataFrame
通过布尔向量选择行 df[bool_vec] DataFrame

譬如,行的取舍重返 Series,其索引是 DataFrame 的列:

In [75]: df.loc['b']
Out[75]: 
one              2
bar              2
flag         False
foo            bar
one_trunc        2
Name: b, dtype: object

In [76]: df.iloc[2]
Out[76]: 
one             3
bar             3
flag         True
foo           bar
one_trunc     NaN
Name: c, dtype: object

对此更扑朔迷离的依照标签的目录和切片的更详细的拍卖,请参阅索引章节。我们将在重索引章节中,强调重索引/适配新标签集的基本原理。

数据对齐和算术

DataFrame对象之间的数据自动依照列和目录(行标签)对齐。同样,生成的靶子拥有列和行标签的并集。

In [77]: df = pd.DataFrame(np.random.randn(10, 4), columns=['A', 'B', 'C', 'D'])

In [78]: df2 = pd.DataFrame(np.random.randn(7, 3), columns=['A', 'B', 'C'])

In [79]: df + df2
Out[79]: 
 A       B       C   D
0  0.5222  0.3225 -0.7566 NaN
1 -0.8441  0.2334  0.8818 NaN
2 -2.2079 -0.1572 -0.3875 NaN
3  2.8080 -1.0927  1.0432 NaN
4 -1.7511 -2.0812  2.7477 NaN
5 -3.2473 -1.0850  0.7898 NaN
6 -1.7107  0.0661  0.1294 NaN
7     NaN     NaN     NaN NaN
8     NaN     NaN     NaN NaN
9     NaN     NaN     NaN NaN

实践 DataFrame和Series之间的操作时,默许行为是,将Dataframe
列****索引与 Series
对齐,从而按行广播。例如:

In [80]: df - df.iloc[0]
Out[80]: 
 A       B       C       D
0  0.0000  0.0000  0.0000  0.0000
1 -2.6396 -1.0702  1.7214 -0.7896
2 -2.7662 -1.6918  2.2776 -2.5401
3  0.8679 -3.5247  1.9365 -0.1331
4 -1.9883 -3.2162  2.0464 -1.0700
5 -3.3932 -4.0976  1.6366 -2.1635
6 -1.3668 -1.9572  1.6523 -0.7191
7 -0.7949 -2.1663  0.9706 -2.6297
8 -0.8383 -1.3630  1.6702 -2.0865
9  0.8588  0.0814  3.7305 -1.3737

在处理时间连串数据的超常规情状下,DataFrame索引也包涵日期,广播是按列的艺术:

In [81]: index = pd.date_range('1/1/2000', periods=8)

In [82]: df = pd.DataFrame(np.random.randn(8, 3), index=index, columns=list('ABC'))

In [83]: df
Out[83]: 
 A       B       C
2000-01-01  0.2731  0.3604 -1.1515
2000-01-02  1.1577  1.4787 -0.6528
2000-01-03 -0.7712  0.2203 -0.5739
2000-01-04 -0.6356 -1.1703 -0.0789
2000-01-05 -1.4687  0.1705 -1.8796
2000-01-06 -1.2037  0.9568 -1.1383
2000-01-07 -0.6540 -0.2169  0.3843
2000-01-08 -2.1639 -0.8145 -1.2475

In [84]: type(df['A'])
Out[84]: pandas.core.series.Series

In [85]: df - df['A']
Out[85]: 
 2000-01-01 00:00:00  2000-01-02 00:00:00  2000-01-03 00:00:00  \
2000-01-01                  NaN                  NaN                  NaN 
2000-01-02                  NaN                  NaN                  NaN 
2000-01-03                  NaN                  NaN                  NaN 
2000-01-04                  NaN                  NaN                  NaN 
2000-01-05                  NaN                  NaN                  NaN 
2000-01-06                  NaN                  NaN                  NaN 
2000-01-07                  NaN                  NaN                  NaN 
2000-01-08                  NaN                  NaN                  NaN 

 2000-01-04 00:00:00 ...  2000-01-08 00:00:00   A   B   C 
2000-01-01                  NaN ...                  NaN NaN NaN NaN 
2000-01-02                  NaN ...                  NaN NaN NaN NaN 
2000-01-03                  NaN ...                  NaN NaN NaN NaN 
2000-01-04                  NaN ...                  NaN NaN NaN NaN 
2000-01-05                  NaN ...                  NaN NaN NaN NaN 
2000-01-06                  NaN ...                  NaN NaN NaN NaN 
2000-01-07                  NaN ...                  NaN NaN NaN NaN 
2000-01-08                  NaN ...                  NaN NaN NaN NaN 

[8 rows x 11 columns]

警告

df - df['A']

现已弃用,将在将来的本子中除去。复现此行为的首选办法是

df.sub(df['A'], axis=0)

对于显式控制非常和播放行为,请参阅灵活的二元运算一节。

标量的操作正如你的预料:

In [86]: df * 5 + 2
Out[86]: 
 A       B       C
2000-01-01  3.3655  3.8018 -3.7575
2000-01-02  7.7885  9.3936 -1.2641
2000-01-03 -1.8558  3.1017 -0.8696
2000-01-04 -1.1781 -3.8513  1.6056
2000-01-05 -5.3437  2.8523 -7.3982
2000-01-06 -4.0186  6.7842 -3.6915
2000-01-07 -1.2699  0.9157  3.9217
2000-01-08 -8.8194 -2.0724 -4.2375

In [87]: 1 / df
Out[87]: 
 A       B        C
2000-01-01  3.6616  2.7751  -0.8684
2000-01-02  0.8638  0.6763  -1.5318
2000-01-03 -1.2967  4.5383  -1.7424
2000-01-04 -1.5733 -0.8545 -12.6759
2000-01-05 -0.6809  5.8662  -0.5320
2000-01-06 -0.8308  1.0451  -0.8785
2000-01-07 -1.5291 -4.6113   2.6019
2000-01-08 -0.4621 -1.2278  -0.8016

In [88]: df ** 4
Out[88]: 
 A       B           C
2000-01-01   0.0056  0.0169  1.7581e+00
2000-01-02   1.7964  4.7813  1.8162e-01
2000-01-03   0.3537  0.0024  1.0849e-01
2000-01-04   0.1632  1.8755  3.8733e-05
2000-01-05   4.6534  0.0008  1.2482e+01
2000-01-06   2.0995  0.8382  1.6789e+00
2000-01-07   0.1829  0.0022  2.1819e-02
2000-01-08  21.9244  0.4401  2.4219e+00

布尔运算符也一如既往有效:

In [89]: df1 = pd.DataFrame({'a' : [1, 0, 1], 'b' : [0, 1, 1] }, dtype=bool)

In [90]: df2 = pd.DataFrame({'a' : [0, 1, 1], 'b' : [1, 1, 0] }, dtype=bool)

In [91]: df1 & df2
Out[91]: 
 a      b
0  False  False
1  False   True
2   True  False

In [92]: df1 | df2
Out[92]: 
 a     b
0  True  True
1  True  True
2  True  True

In [93]: df1 ^ df2
Out[93]: 
 a      b
0   True   True
1   True  False
2  False   True

In [94]: -df1
Out[94]: 
 a      b
0  False   True
1   True  False
2  False  False

转置

对于转置,访问T属性(transpose函数也是),类似于ndarray:

# only show the first 5 rows
In [95]: df[:5].T
Out[95]: 
 2000-01-01  2000-01-02  2000-01-03  2000-01-04  2000-01-05
A      0.2731      1.1577     -0.7712     -0.6356     -1.4687
B      0.3604      1.4787      0.2203     -1.1703      0.1705
C     -1.1515     -0.6528     -0.5739     -0.0789     -1.8796

DataFrame 与 NumPy 函数的互操作

逐元素的 NumPy
ufunc(log,exp,sqrt,…)和各类其余NumPy函数可以无缝用于DataFrame,即使其中的数量是数字:

In [96]: np.exp(df)
Out[96]: 
 A       B       C
2000-01-01  1.3140  1.4338  0.3162
2000-01-02  3.1826  4.3873  0.5206
2000-01-03  0.4625  1.2465  0.5633
2000-01-04  0.5296  0.3103  0.9241
2000-01-05  0.2302  1.1859  0.1526
2000-01-06  0.3001  2.6034  0.3204
2000-01-07  0.5200  0.8050  1.4686
2000-01-08  0.1149  0.4429  0.2872

In [97]: np.asarray(df)
Out[97]: 
array([[ 0.2731,  0.3604, -1.1515],
 [ 1.1577,  1.4787, -0.6528],
 [-0.7712,  0.2203, -0.5739],
 [-0.6356, -1.1703, -0.0789],
 [-1.4687,  0.1705, -1.8796],
 [-1.2037,  0.9568, -1.1383],
 [-0.654 , -0.2169,  0.3843],
 [-2.1639, -0.8145, -1.2475]])

DataFrame上的dot方法达成了矩阵乘法:

In [98]: df.T.dot(df)
Out[98]: 
 A       B       C
A  11.1298  2.8864  6.0015
B   2.8864  5.3895 -1.8913
C   6.0015 -1.8913  8.6204

类似地,Series上的dot方法完毕了点积:

In [99]: s1 = pd.Series(np.arange(5,10))

In [100]: s1.dot(s1)
Out[100]: 255

DataFrame不打算作为ndarray的替代品,因为它的索引语义和矩阵是万分分裂的。

控制台显示

那多少个大的DataFrames将被截断,来在控制杜阿拉显得。您也足以选取info()取得摘要。(这里我从plyr
R软件包中,读取CSV版本的棒球数据集):

In [101]: baseball = pd.read_csv('data/baseball.csv')

In [102]: print(baseball)
 id     player  year  stint  ...   hbp   sh   sf  gidp
0   88641  womacto01  2006      2  ...   0.0  3.0  0.0   0.0
1   88643  schilcu01  2006      1  ...   0.0  0.0  0.0   0.0
..    ...        ...   ...    ...  ...   ...  ...  ...   ...
98  89533   aloumo01  2007      1  ...   2.0  0.0  3.0  13.0
99  89534  alomasa02  2007      1  ...   0.0  0.0  0.0   0.0

[100 rows x 23 columns]

In [103]: baseball.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100 entries, 0 to 99
Data columns (total 23 columns):
id        100 non-null int64
player    100 non-null object
year      100 non-null int64
stint     100 non-null int64
team      100 non-null object
lg        100 non-null object
g         100 non-null int64
ab        100 non-null int64
r         100 non-null int64
h         100 non-null int64
X2b       100 non-null int64
X3b       100 non-null int64
hr        100 non-null int64
rbi       100 non-null float64
sb        100 non-null float64
cs        100 non-null float64
bb        100 non-null int64
so        100 non-null float64
ibb       100 non-null float64
hbp       100 non-null float64
sh        100 non-null float64
sf        100 non-null float64
gidp      100 non-null float64
dtypes: float64(9), int64(11), object(3)
memory usage: 18.0+ KB

但是,使用to_string将回来表格方式的DataFrame的字符串表示,但并不一而再适合控制台宽度:

In [104]: print(baseball.iloc[-20:, :12].to_string())
 id     player  year  stint team  lg    g   ab   r    h  X2b  X3b
80  89474  finlest01  2007      1  COL  NL   43   94   9   17    3    0
81  89480  embreal01  2007      1  OAK  AL    4    0   0    0    0    0
82  89481  edmonji01  2007      1  SLN  NL  117  365  39   92   15    2
83  89482  easleda01  2007      1  NYN  NL   76  193  24   54    6    0
84  89489  delgaca01  2007      1  NYN  NL  139  538  71  139   30    0
85  89493  cormirh01  2007      1  CIN  NL    6    0   0    0    0    0
86  89494  coninje01  2007      2  NYN  NL   21   41   2    8    2    0
87  89495  coninje01  2007      1  CIN  NL   80  215  23   57   11    1
88  89497  clemero02  2007      1  NYA  AL    2    2   0    1    0    0
89  89498  claytro01  2007      2  BOS  AL    8    6   1    0    0    0
90  89499  claytro01  2007      1  TOR  AL   69  189  23   48   14    0
91  89501  cirilje01  2007      2  ARI  NL   28   40   6    8    4    0
92  89502  cirilje01  2007      1  MIN  AL   50  153  18   40    9    2
93  89521  bondsba01  2007      1  SFN  NL  126  340  75   94   14    0
94  89523  biggicr01  2007      1  HOU  NL  141  517  68  130   31    3
95  89525  benitar01  2007      2  FLO  NL   34    0   0    0    0    0
96  89526  benitar01  2007      1  SFN  NL   19    0   0    0    0    0
97  89530  ausmubr01  2007      1  HOU  NL  117  349  38   82   16    3
98  89533   aloumo01  2007      1  NYN  NL   87  328  51  112   19    1
99  89534  alomasa02  2007      1  NYN  NL    8   22   1    3    1    0

从0.10.0版本开端,默许景况下,宽的 DataFrames 以多行打印:

In [105]: pd.DataFrame(np.random.randn(3, 12))
Out[105]: 
 0         1         2         3         4         5         6   \
0  2.173014  1.273573  0.888325  0.631774  0.206584 -1.745845 -0.505310 
1 -1.240418  2.177280 -0.082206  0.827373 -0.700792  0.524540 -1.101396 
2  0.269598 -0.453050 -1.821539 -0.126332 -0.153257  0.405483 -0.504557 

 7         8         9         10        11 
0  1.376623  0.741168 -0.509153 -2.012112 -1.204418 
1  1.115750  0.294139  0.286939  1.709761 -0.212596 
2  1.405148  0.778061 -0.799024 -0.670727  0.086877 

您可以由此设置display.width选拔,更改单行上的打印量:

In [106]: pd.set_option('display.width', 40) # default is 80

In [107]: pd.DataFrame(np.random.randn(3, 12))
Out[107]: 
 0         1         2   \
0  1.179465  0.777427 -1.923460 
1  0.054928  0.776156  0.372060 
2 -0.243404 -1.506557 -1.977226 

 3         4         5   \
0  0.782432  0.203446  0.250652 
1  0.710963 -0.784859  0.168405 
2 -0.226582 -0.777971  0.231309 

 6         7         8   \
0 -2.349580 -0.540814 -0.748939 
1  0.159230  0.866492  1.266025 
2  1.394479  0.723474 -0.097256 

 9         10        11 
0 -0.994345  1.478624 -0.341991 
1  0.555240  0.731803  0.219383 
2  0.375274 -0.314401 -2.363136 

你可以因此设置display.max_colwidth来调动各列的最大开间

In [108]: datafile={'filename': ['filename_01','filename_02'],
 .....:           'path': ["media/user_name/storage/folder_01/filename_01",
 .....:                    "media/user_name/storage/folder_02/filename_02"]}
 .....: 

In [109]: pd.set_option('display.max_colwidth',30)

In [110]: pd.DataFrame(datafile)
Out[110]: 
 filename  \
0  filename_01 
1  filename_02 

 path 
0  media/user_name/storage/fo... 
1  media/user_name/storage/fo... 

In [111]: pd.set_option('display.max_colwidth',100)

In [112]: pd.DataFrame(datafile)
Out[112]: 
 filename  \
0  filename_01 
1  filename_02 

 path 
0  media/user_name/storage/folder_01/filename_01 
1  media/user_name/storage/folder_02/filename_02 

你也可以透过expand_frame_repr选择停用此作用。这将表打印在一个块中。

DataFrame 列属性访问和 IPython 补全

万一DataFrame列标签是可行的Python变量名,则足以像属性一样访问该列:

In [113]: df = pd.DataFrame({'foo1' : np.random.randn(5),
 .....:                    'foo2' : np.random.randn(5)})
 .....: 

In [114]: df
Out[114]: 
 foo1      foo2
0 -0.412237  0.213232
1 -0.237644  1.740139
2  1.272869 -0.241491
3  1.220450 -0.868514
4  1.315172  0.407544

In [115]: df.foo1
Out[115]: 
0   -0.412237
1   -0.237644
2    1.272869
3    1.220450
4    1.315172
Name: foo1, dtype: float64

这一个列还一而再了IPython补全机制,由此得以经过制表符补全:

In [5]: df.fo<TAB>
df.foo1  df.foo2

Panel(面板)

Panel是一个不怎么不常用的器皿,不过对于三维数据如故主要。术语面板数据源自计量艺术学,是pandas名称的局部来自:pan(el)-da(ta)-s。
五个轴旨在提供部分语义上的意思,来讲述涉及面板数据的操作,尤其是面板数据的计算分析。不过,出于切割DataFrame对象的集纳的阴毒目标,您可能会发现轴名称稍有自由:

  • items(条目):轴0,每个条目对应于其中饱含的DataFrame
  • major_axis(主轴):轴1,它是种种DataFrame的index(行)
  • minor_axis(副轴):轴2,它是各类DataFrames的columns(列)

Panel 的构造正如你的希望:

起点三维 ndarray 和可选的轴标签

In [116]: wp = pd.Panel(np.random.randn(2, 5, 4), items=['Item1', 'Item2'],
 .....:               major_axis=pd.date_range('1/1/2000', periods=5),
 .....:               minor_axis=['A', 'B', 'C', 'D'])
 .....: 

In [117]: wp
Out[117]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 5 (major_axis) x 4 (minor_axis)
Items axis: Item1 to Item2
Major_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00
Minor_axis axis: A to D

发源 DataFrame 对象的字典

In [118]: data = {'Item1' : pd.DataFrame(np.random.randn(4, 3)),
 .....:         'Item2' : pd.DataFrame(np.random.randn(4, 2))}
 .....: 

In [119]: pd.Panel(data)
Out[119]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 4 (major_axis) x 3 (minor_axis)
Items axis: Item1 to Item2
Major_axis axis: 0 to 3
Minor_axis axis: 0 to 2

只顾,字典中的值只需求可更换为DataFrame。因而,它们得以是DataFrame的别样其它有效输入,像上边一样。

一个得力的工厂方法是Panel.from_dict,它接受地点的DataFrames的字典,以及以下命名参数:

参数 默认 描述
intersect(交集) False 丢弃索引没有对齐的元素
orient(方向) items 使用minor将DataFrames的列用作 Panel 的条目

比如说,与地方的布局相比较:

In [120]: pd.Panel.from_dict(data, orient='minor')
Out[120]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 3 (items) x 4 (major_axis) x 2 (minor_axis)
Items axis: 0 to 2
Major_axis axis: 0 to 3
Minor_axis axis: Item1 to Item2

Orient对于混合类型的DataFrames更加有用。若是你传递一个DataFrame对象的字典,它的列是勾兑类型,所有的数量将更换为dtype=object,除非你传递orient='minor'

In [121]: df = pd.DataFrame({'a': ['foo', 'bar', 'baz'],
 .....:                    'b': np.random.randn(3)})
 .....: 

In [122]: df
Out[122]: 
 a         b
0  foo -1.142863
1  bar -1.015321
2  baz  0.683625

In [123]: data = {'item1': df, 'item2': df}

In [124]: panel = pd.Panel.from_dict(data, orient='minor')

In [125]: panel['a']
Out[125]: 
 item1 item2
0   foo   foo
1   bar   bar
2   baz   baz

In [126]: panel['b']
Out[126]: 
 item1     item2
0 -1.142863 -1.142863
1 -1.015321 -1.015321
2  0.683625  0.683625

In [127]: panel['b'].dtypes
Out[127]: 
item1    float64
item2    float64
dtype: object

注意

不好的是,面板比Series和DataFrame更不常用,在特色方面略有忽略。DataFrame中提供的浩大格局和挑选在Panel中不可用。那将会取得处理,当然,是鹏程的本子中。就算你投入自己的代码库,会更快。

来自 DataFrame,使用to_panel 方法

此办法在v0.7中引入,来替换LongPanel.to_long,并将富有二级索引的DataFrame转换为Panel。

In [128]: midx = pd.MultiIndex(levels=[['one', 'two'], ['x','y']], labels=[[1,1,0,0],[1,0,1,0]])

In [129]: df = pd.DataFrame({'A' : [1, 2, 3, 4], 'B': [5, 6, 7, 8]}, index=midx)

In [130]: df.to_panel()
Out[130]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 2 (major_axis) x 2 (minor_axis)
Items axis: A to B
Major_axis axis: one to two
Minor_axis axis: x to y

条目接纳 / 添加 / 删除

类似于DataFrame作为 Series 的字典,Panel就像是DataFrames的字典:

In [131]: wp['Item1']
Out[131]: 
 A         B         C         D
2000-01-01 -0.729430  0.427693 -0.121325 -0.736418
2000-01-02  0.739037 -0.648805 -0.383057  0.385027
2000-01-03  2.321064 -1.290881  0.105458 -1.097035
2000-01-04  0.158759 -1.261191 -0.081710  1.390506
2000-01-05 -1.962031 -0.505580  0.021253 -0.317071

In [132]: wp['Item3'] = wp['Item1'] / wp['Item2']

用于插入和删除的API与DataFrame相同。和DataFrame一样,如若条目是一个卓有作用的Python标识符,您可以用作一个属性访问它,并在IPython中补全它。

转置

可以应用 Panel
transpose办法(除非数据是异构的,否则它不会默许制作副本)来重新排列它:

In [133]: wp.transpose(2, 0, 1)
Out[133]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 4 (items) x 3 (major_axis) x 5 (minor_axis)
Items axis: A to D
Major_axis axis: Item1 to Item3
Minor_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00

索引 / 选取

操作 语法 结果
选取条目 wp[item] DataFrame
选取主轴标签 wp.major_xs(val) DataFrame
选取副轴标签 wp.minor_xs(val) DataFrame

比如说,使用之前的演示数据,我们得以实施:

In [134]: wp['Item1']
Out[134]: 
 A         B         C         D
2000-01-01 -0.729430  0.427693 -0.121325 -0.736418
2000-01-02  0.739037 -0.648805 -0.383057  0.385027
2000-01-03  2.321064 -1.290881  0.105458 -1.097035
2000-01-04  0.158759 -1.261191 -0.081710  1.390506
2000-01-05 -1.962031 -0.505580  0.021253 -0.317071

In [135]: wp.major_xs(wp.major_axis[2])
Out[135]: 
 Item1     Item2     Item3
A  2.321064 -0.538606 -4.309389
B -1.290881  0.791512 -1.630905
C  0.105458 -0.020302 -5.194337
D -1.097035  0.184430 -5.948253

In [136]: wp.minor_axis
Out[136]: Index([u'A', u'B', u'C', u'D'], dtype='object')

In [137]: wp.minor_xs('C')
Out[137]: 
 Item1     Item2     Item3
2000-01-01 -0.121325  1.413524 -0.085832
2000-01-02 -0.383057  1.243178 -0.308127
2000-01-03  0.105458 -0.020302 -5.194337
2000-01-04 -0.081710 -1.811565  0.045105
2000-01-05  0.021253 -1.040542 -0.020425

挤压

更改目的的维度的另一种办法是squeeze(挤压)长度为 1
的对象,类似于wp['Item1']

In [138]: wp.reindex(items=['Item1']).squeeze()
Out[138]: 
 A         B         C         D
2000-01-01 -0.729430  0.427693 -0.121325 -0.736418
2000-01-02  0.739037 -0.648805 -0.383057  0.385027
2000-01-03  2.321064 -1.290881  0.105458 -1.097035
2000-01-04  0.158759 -1.261191 -0.081710  1.390506
2000-01-05 -1.962031 -0.505580  0.021253 -0.317071

In [139]: wp.reindex(items=['Item1'], minor=['B']).squeeze()
Out[139]: 
2000-01-01    0.427693
2000-01-02   -0.648805
2000-01-03   -1.290881
2000-01-04   -1.261191
2000-01-05   -0.505580
Freq: D, Name: B, dtype: float64

转换为 DataFrame

Panel 可以以二维格局表示为层次索引的
DataFrame。详细新闻,请参阅层次索引一节。为了将Panel转换为DataFrame,请使用to_frame方法:

In [140]: panel = pd.Panel(np.random.randn(3, 5, 4), items=['one', 'two', 'three'],
 .....:                  major_axis=pd.date_range('1/1/2000', periods=5),
 .....:                  minor_axis=['a', 'b', 'c', 'd'])
 .....: 

In [141]: panel.to_frame()
Out[141]: 
 one       two     three
major      minor 
2000-01-01 a     -1.876826 -0.383171 -0.117339
 b     -1.873827 -0.172217  0.780048
 c     -0.251457 -1.674685  2.162047
 d      0.027599  0.762474  0.874233
2000-01-02 a      1.235291  0.481666 -0.764147
 b      0.850574  1.217546 -0.484495
 c     -1.140302  0.577103  0.298570
 d      2.149143 -0.076021  0.825136
2000-01-03 a      0.504452  0.720235 -0.388020
 b      0.678026  0.202660 -0.339279
 c     -0.628443 -0.314950  0.141164
 d      1.191156 -0.410852  0.565930
2000-01-04 a     -1.145363  0.542758 -1.749969
 b     -0.523153  1.955407 -1.402941
 c     -1.299878 -0.940645  0.623222
 d     -0.110240  0.076257  0.020129
2000-01-05 a     -0.333712 -0.897159 -2.858463
 b      0.416876 -1.265679  0.885765
 c     -0.436400 -0.528311  0.158014
 d      0.999768 -0.660014 -1.981797

Panel4D 和 PanelND (废弃)

警告

在0.19.0
中,Panel4DPanelND已弃用,并且将在后来的版本中去除。表示那一个类其余n维数据的引荐方法是使用xarray软件包。Pandas提供了一个to_xarray()办法来机关执行此转换。

那个目的的文档,请参见此前版本的文档

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图