pandas数据结构简介

pandas数据结构简介


首先介绍基础的数据结构。 基础行为包括 data types, indexing, axis labeling / alignment, 它们试用于所以对象。

import numpy as np
import pandas as pd

有一个基础原则:**data alignment is intrinsic.**标签和数据之间的连接不会断开,除非手动断开。

首先简要介绍数据结构,然后单独介绍功能和方法的广泛类别。

Series

Series是一维标记的数组,能够保存任何类型的数据(integers,strings,floating point numbers,python objects,etc)。
axis labels被统称为index
创建Series的基础方法是:

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

其中的data参数可以是:

  • a Python dict
  • an ndarray
  • a scalar value (like 5)

其中的index参数是一个表示axis labels标签的列表。

根据data的不同,可以分为以下几种情况:

ndarray:

如果data是ndarray,index必须与data长度相同。如果没有index参数传入,那么将会自动创建index为: 0,1,2,3,…

s = pd.Series(np.random.randn(5),index=['a','b','c','d','e'])
s
a   -0.050107
b   -0.275637
c    0.022653
d    0.677512
e    0.497479
dtype: float64
s.index
Index(['a', 'b', 'c', 'd', 'e'], dtype='object')
pd.Series(np.random.randn(5))
0   -1.190514
1   -2.139007
2   -0.195262
3    0.114374
4    0.239553
dtype: float64

dict:

series可以根据dicts实例化。

d = {'b':1,'a':0,'c':2}
pd.Series(d)
b    1
a    0
c    2
dtype: int64

如果python版本<3.6或者pandas<0.23,上述的Series的index顺序是[‘a’, ‘b’, ‘c’],而不是[‘b’, ‘a’, ‘c’].

如果传入了index参数,那么dict在的key生成的index将被覆盖

Scalar value:

如果传入的data是标量数据,那么index参数必须提供,Series中的value将自动复制data,使其长度与index相等。

pd.Series(5.,index=['a','b','c'])
a    5.0
b    5.0
c    5.0
dtype: float64

Series是一个ndarray-like

Series与ndarray非常类似,并且对大多数numpy函数来说都是有效的参数。然而,切片操作等操作也切割index.

s[0]
-0.05010660876964625
s[:3]
a   -0.050107
b   -0.275637
c    0.022653
dtype: float64
s[s > s.median()]
d    0.677512
e    0.497479
dtype: float64
s[[4,2,1]]
e    0.497479
c    0.022653
b   -0.275637
dtype: float64
np.exp(s)
a    0.951128
b    0.759089
c    1.022911
d    1.968973
e    1.644570
dtype: float64
和numpy一样,Series也有一个dtype。
s.dtype
dtype('float64')

Series的dtype通常是numpy的dtype,然而,pandas和其他三方库扩展了numpy的dtpye。可以参考dtypes

使用Series.array可以查看Series的实际数组.

s.array
<PandasArray>
[-0.05010660876964625, -0.27563658449690015,  0.02265290627681807,
   0.6775122610456474,   0.4974791479965988]
Length: 5, dtype: float64

Series.array是一个extensionArray。大体上说,ExtensionArray包装了了一个或多个具体的arrays,例如numpy.ndarray。pandas知道如何获取一个ExtensionArray并将其存储在一个Series中或DataFrame的column中。

Series是一个ndarray-like,入股需要一个实际的ndarray,可以使用Series.numpy()

s.to_numpy()
array([-0.05010661, -0.27563658,  0.02265291,  0.67751226,  0.49747915])

dict-like

一个Series就像是一个固定尺寸的dict,它可以通过index label来获取和设置values。

s['a']
-0.05010660876964625
s['e']=12
s
a    -0.050107
b    -0.275637
c     0.022653
d     0.677512
e    12.000000
dtype: float64
'e' in s
True
'w' in s
False

如果不包含要查询的标签,将会返回错误。

# s['w']
# KeyError: 'f'

get()方法可以设置在没有要查询的属性时,默认返回值。如果没有设置默认值将返回None,并不会报错。

s.get('w',np.nan)
nan
print(s.get('w'))
None

序列化操作和Series的标签对齐

Series可以作为ndarray传入到numpy的方法中。

s + s
a    -0.100213
b    -0.551273
c     0.045306
d     1.355025
e    24.000000
dtype: float64
s *2
a    -0.100213
b    -0.551273
c     0.045306
d     1.355025
e    24.000000
dtype: float64
np.exp(s)
a         0.951128
b         0.759089
c         1.022911
d         1.968973
e    162754.791419
dtype: float64

Series和ndarray的一个主要区别是:Series的自动对齐是根据label的。
所以可以编写计算而不用考虑,涉及到的Series是否有相同的label。

s[1:]
b    -0.275637
c     0.022653
d     0.677512
e    12.000000
dtype: float64
s[:-1]
a   -0.050107
b   -0.275637
c    0.022653
d    0.677512
dtype: float64
s[1:]+s[:-1]
a         NaN
b   -0.551273
c    0.045306
d    1.355025
e         NaN
dtype: float64

Name属性

series有一个name属性。

s = pd.Series(np.random.randn(5),name='something')
s
0   -0.990679
1   -0.703465
2    0.689987
3    0.709681
4    0.186647
Name: something, dtype: float64

pandas.Series.rename()方法可以更改名字。

DataFrame

DataFrame是2维标签数据。它的每一列可以是不同的数据。可以把它看作是SQL table。
DataFrame接受许多不同类型的输入:

  • Dict of 1D ndarrays, lists, dicts, or Series
  • 2-D numpy.ndarray
  • Structured or record ndarray
  • A Series
  • Another DataFrame

除了data参数,还可以传入index(row labels)和columns(column labels)参数。

根据Series的dict或者dicts创建DataFrame

得到的index将是所有series的index的并集。如果没有传入columns,传入的dict的keys排序后作为columns.

d = {
    'one':pd.Series([1.,2.,3.],index=['a','b','c']),
    'two':pd.Series([1.,2.,3.,4.],index=['a','b','c','d'])
}
df=pd.DataFrame(d)
df
onetwo
a1.01.0
b2.02.0
c3.03.0
dNaN4.0
pd.DataFrame(d,index=['d','b','a'])
onetwo
dNaN4.0
b2.02.0
a1.01.0
pd.DataFrame(d, index=['d', 'b', 'a'], columns=['two', 'three'])
twothree
d4.0NaN
b2.0NaN
a1.0NaN

根据ndarrays或者lists的dict创建DataFrame

ndarrays必须长度相同。如果传入了index参数,它也必须和arrays的长度相同。

d = {'one':[1.,2.,3.,4.],
    'two':[4.,3.,2.,1.]}
pd.DataFrame(d)
onetwo
01.04.0
12.03.0
23.02.0
34.01.0
pd.DataFrame(d, index=['a', 'b', 'c', 'd'])
onetwo
a1.04.0
b2.03.0
c3.02.0
d4.01.0

根据结构化或记录数组创建DataFrame

这种情况的处理与数组的dict相同。

data = np.zeros(
    (2,),
    dtype=[('A','i4'),('B','f4'),('C','a10')]
)
data
array([(0, 0., b''), (0, 0., b'')],
      dtype=[('A', '<i4'), ('B', '<f4'), ('C', 'S10')])
data[:]=[
    (1,2.,'Hello'),
    (2,3.,'World')
]
data
array([(1, 2., b'Hello'), (2, 3., b'World')],
      dtype=[('A', '<i4'), ('B', '<f4'), ('C', 'S10')])
pd.DataFrame(data)
ABC
012.0b'Hello'
123.0b'World'
pd.DataFrame(data,index=['first','second'])
ABC
first12.0b'Hello'
second23.0b'World'
 pd.DataFrame(data, columns=['C', 'A', 'B'])
CAB
0b'Hello'12.0
1b'World'23.0

根据dicts的list创建DataFrame

data2 = [
    {'a':1,'b':2},
    {'a':5,'b':10,'c':20}
]
data2
[{'a': 1, 'b': 2}, {'a': 5, 'b': 10, 'c': 20}]
pd.DataFrame(data2)
abc
012NaN
151020.0
pd.DataFrame(data2, index=['first', 'second'])
abc
first12NaN
second51020.0
pd.DataFrame(data2, columns=['a', 'b'])
ab
012
1510

根据tuples的dict创建DataFrame

根据元组字典创建。

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}
})
ab
bacab
AB1.04.05.08.010.0
C2.03.06.07.0NaN
DNaNNaNNaNNaN9.0

根据Series创建DataFrame

创建的DataFrame的index和Series相同。column名称将会使用Series的名称。

s = pd.Series([1,2,3,4],index=['A','B','C','D'],name='test')
pd.DataFrame(s)
test
A1
B2
C3
D4
s2 = pd.Series([1,2,3,4],index=['A','B','C','D'],name='test2')

pd.DataFrame((s,s2))
ABCD
test1234
test21234

构造器

DataFrame.from_dict():

除了orient参数默认为’columns’之外,它的操作类似于DataFrame构造函数,但可以将其设置为’index’以便将dict键用作行标签。

pd.DataFrame.from_dict(dict([('A', [1, 2, 3]), ('B', [4, 5, 6])]))
AB
014
125
236
pd.DataFrame.from_dict(dict([('A', [1, 2, 3]), ('B', [4, 5, 6])]), orient='index', columns=['one', 'two', 'three'])
onetwothree
A123
B456

DataFrame.from_records():

它接受一个tuplies的list或者一个有结构化数据的ndarray参数。除了生成的DataFrame索引可能是结构化dtype的特定字段之外,它的功能与正常的DataFrame构造器类似。

data
array([(1, 2., b'Hello'), (2, 3., b'World')],
      dtype=[('A', '<i4'), ('B', '<f4'), ('C', 'S10')])
pd.DataFrame.from_records(data, index='C')
AB
C
b'Hello'12.0
b'World'23.0
pd.DataFrame.from_records(data)
ABC
012.0b'Hello'
123.0b'World'

column的选择,添加和删除

df['one']
a    1.0
b    2.0
c    3.0
d    NaN
Name: one, dtype: float64
df['three'] = df['one'] * df['two']
df['flag'] = df['one'] > 2
df
onetwothreeflag
a1.01.01.0False
b2.02.04.0False
c3.03.09.0True
dNaN4.0NaNFalse
del df['two']
df['foo'] = 'bar'
df
onethreeflagfoo
a1.01.0Falsebar
b2.04.0Falsebar
c3.09.0Truebar
dNaNNaNFalsebar

当插入series时,插入的Series可能和DataFrame的index不同,它将会遵从DataFrame的index

df['one_trunc']=df['one'][:2]
df
onethreeflagfooone_trunc
a1.01.0Falsebar1.0
b2.04.0Falsebar2.0
c3.09.0TruebarNaN
dNaNNaNFalsebarNaN

也可以插入ndarray,但是它的长度必须和DataFrame的长度保持一致。

默认情况columns插入到最后,但是也可以指定插入位置。

df.insert(1,'bar',df['one'])
df
onebarthreeflagfooone_trunc
a1.01.01.0Falsebar1.0
b2.02.04.0Falsebar2.0
c3.03.09.0TruebarNaN
dNaNNaNNaNFalsebarNaN

在方法链中赋值新的columns

assign()方法可以容易的创建源自现有columns的新columns

iris = pd.DataFrame([
    [5.1, 3.5, 1.4, 0.2,'Iris-setosa'],
    [4.9, 3.0,1.4,0.2,'Iris-setosa'],
    [4.7, 3.2,1.3, 0.2,'Iris-setosa'],
    [4.6, 3.1,1.5,0.2,'Iris-setosa'],
    [5.0, 3.6,1.4,0.2,'Iris-setosa']
],columns=[ 'SepalLength','SepalWidth','PetalLength','PetalWidth','Name'])
iris
SepalLengthSepalWidthPetalLengthPetalWidthName
05.13.51.40.2Iris-setosa
14.93.01.40.2Iris-setosa
24.73.21.30.2Iris-setosa
34.63.11.50.2Iris-setosa
45.03.61.40.2Iris-setosa
iris.assign(sepal_ratio=iris.SepalWidth / iris.SepalLength )
SepalLengthSepalWidthPetalLengthPetalWidthNamesepal_ratio
05.13.51.40.2Iris-setosa0.686275
14.93.01.40.2Iris-setosa0.612245
24.73.21.30.2Iris-setosa0.680851
34.63.11.50.2Iris-setosa0.673913
45.03.61.40.2Iris-setosa0.720000

在上面的示例中,我们插入了一个预先计算的值。 我们还可以传入一个参数的函数,以在分配给它的DataFrame上求值。

iris.assign(sepal_ratio=lambda x: (x['SepalWidth'] / x['SepalLength']))
SepalLengthSepalWidthPetalLengthPetalWidthNamesepal_ratio
05.13.51.40.2Iris-setosa0.686275
14.93.01.40.2Iris-setosa0.612245
24.73.21.30.2Iris-setosa0.680851
34.63.11.50.2Iris-setosa0.673913
45.03.61.40.2Iris-setosa0.720000

Assign始终返回数据的副本,而原始DataFrame保持不变

如果仅仅是想查看某些属性,不想把它加入到DataFrame中,assgin方法就非常有用。
以下是是一个示例:

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')
<matplotlib.axes._subplots.AxesSubplot at 0x216b3606388>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ouZQj4bh-1575951188410)(output_117_1.png)]

需要注意的是以下代码在<=python3.5版本和>3.5版本中的结果不同:

dependent = pd.DataFrame({"A": [1, 1, 1]})
dependent.assign(A=lambda x: x["A"] + 1, B=lambda x: x["A"] + 2)
AB
024
124
224

在python3.5中结果为:

AB
023
123
223

在python3.6中结果为:

AB
024
124
224

索引和选择

基础的索引操作如下:

OperationSyntaxResult
Select columndf[col]Series
Select row by labeldf.loc[label]Series
Select row by integer locationdf.iloc[loc]Series
Slice rowsdf[5:10]DataFrame
Select rows by boolean vectordf[bool_vec]DataFrame

数据对齐和计算

DataFrame有自动对齐数据的功能。

df = pd.DataFrame(np.random.randn(10, 4), columns=['A', 'B', 'C', 'D'])
df2 = pd.DataFrame(np.random.randn(7, 3), columns=['A', 'B', 'C'])
df+df2
ABCD
0-3.709482-1.3156951.034033NaN
1-1.4764411.368839-1.693066NaN
20.253196-1.5386612.305911NaN
30.8251680.032810-4.019238NaN
42.269895-0.356334-2.033594NaN
50.822753-0.6444120.445278NaN
6-1.0113800.9842490.114061NaN
7NaNNaNNaNNaN
8NaNNaNNaNNaN
9NaNNaNNaNNaN

当在DataFrame和Series上操作时,默认行为是将Series的index对齐到DataFrame的columns上。

df - df.iloc[0]
ABCD
00.0000000.0000000.0000000.000000
11.6214311.338117-1.811021-1.321338
21.543036-1.8851171.4717260.039261
32.3485540.224665-2.1749170.551201
42.216406-0.035677-0.5450851.691566
53.011986-1.166244-0.229181-0.818974
61.3260640.9133730.6342880.391074
71.7135301.888000-0.207436-1.166970
80.764998-0.5179340.7143970.869612
92.622506-1.0005900.5804700.564451
df-df['A'] # 默认是在行中查找,当没有符合的数据时,返回的都是NaN
ABCD0123456789
0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
3NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
4NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
6NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
7NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
8NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
9NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN

上面的指令应该改为:

df.sub(df['A'],axis=0)
ABCD
00.01.9523581.7214121.930427
10.01.669043-1.711040-1.012343
20.0-1.4757961.6501010.426651
30.0-0.171531-2.8020590.133073
40.0-0.299725-1.0400791.405587
50.0-2.225871-1.519755-1.900533
60.01.5396671.0296360.995437
70.02.126827-0.199555-0.950073
80.00.6694261.6708112.035041
90.0-1.670737-0.320624-0.127628

使用标量运算正如您所期望的:

df * 5 + 2
ABCD
0-7.1482422.6135481.4588172.503892
10.9589159.304131-7.596286-4.102799
20.566941-6.8120378.8174472.700196
34.5945303.736874-9.4157665.259895
43.9337882.435162-1.26660710.961723
57.911687-3.2176700.312914-1.590980
6-0.5179247.1804124.6302554.459262
71.41941012.0535470.421637-3.330956
8-3.3232510.0238795.0308046.851952
95.964286-2.3894004.3611685.326146
1 / df
ABCD
0-0.5465538.149320-9.2390159.922759
1-4.8026830.684544-0.521035-0.819296
2-3.489039-0.5674060.7334127.140856
31.9271312.878735-0.4379911.533792
42.58559811.489986-1.5306400.557928
50.845782-0.958282-2.963690-1.392378
6-1.9857630.9651741.9009562.033131
7-8.6119330.497337-3.167839-0.937918
8-0.939276-2.5302091.6497271.030513
91.261261-1.1391082.1175961.503241

布尔运算符也可以工作:

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

df1 & df2
ab
0FalseFalse
1FalseTrue
2TrueFalse

转置

df.T
0123456789
A-1.829648-0.208217-0.2866120.5189060.3867581.182337-0.503585-0.116118-1.0646500.792857
B0.1227101.460826-1.7624070.3473750.087032-1.0435341.0360822.010709-0.395224-0.877880
C-0.108237-1.9192571.363489-2.283153-0.653321-0.3374170.526051-0.3156730.6061610.472234
D0.100778-1.2205600.1400390.6519791.792345-0.7181960.491852-1.0661910.9703900.665229

DataFrame与NumPy函数的互操作

假设其中的数据是数字,则可以逐元素使用NumPy ufuncs(log,exp,sqrt等)和其他各种NumPy函数,在Series和DataFrame上都不会出现问题:

np.exp(df)
ABCD
00.1604701.1305560.8974151.106032
10.8120314.3095190.1467160.295065
20.7508030.1716313.9098131.150319
31.6801891.4153470.1019621.919335
41.4722001.0909320.5203156.003512
53.2619900.3522080.7136110.487631
60.6043602.8181551.6922361.635343
70.8903707.4686130.7292980.344317
80.3448480.6735291.8333792.638975
92.2097010.4156631.6035721.944936
np.asanyarray(df)
array([[-1.82964832,  0.12270962, -0.10823665,  0.10077842],
       [-0.20821696,  1.46082625, -1.91925727, -1.22055986],
       [-0.28661189, -1.76240741,  1.36348942,  0.14003923],
       [ 0.51890601,  0.34737476, -2.28315323,  0.65197895],
       [ 0.38675768,  0.0870323 , -0.65332134,  1.79234468],
       [ 1.18233731, -1.04353408, -0.33741721, -0.7181959 ],
       [-0.50358472,  1.03608235,  0.52605097,  0.49185231],
       [-0.11611795,  2.01070936, -0.31567263, -1.06619111],
       [-1.06465022, -0.3952242 ,  0.60616076,  0.9703904 ],
       [ 0.79285728, -0.87788004,  0.47223364,  0.66522921]])

DataFrame并不打算替代ndarray,因为它的索引语义和数据模型与n维数组在某些地方有很大的不同。

版本0.25.0中的变化:当多个系列被传递给ufunc时,它们在执行操作之前是对齐的。
例如,在两个具有不同顺序标签的系列上使用numpy. residual()将在操作之前对齐。

ser1 = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
ser2 = pd.Series([1, 3, 5], index=['b', 'a', 'c'])
ser1
a    1
b    2
c    3
dtype: int64
ser2
b    1
a    3
c    5
dtype: int64
 np.remainder(ser1, ser2) # 求余数
a    1
b    0
c    3
dtype: int64

当二进制ufunc应用于一个seriesindex时,series实现优先并,返回一个系列。

ser = pd.Series([1, 2, 3]) # 一个Series
idx = pd.Index([4, 5, 6]) # 一个Index
np.maximum(ser, idx)
0    4
1    5
2    6
dtype: int64

NumPy ufuncs可以安全地应用于由非ndarray数组支持的序列,例如SparseArray(参见稀疏计算)。如果可能,应用ufunc时不需要将底层数据转换为ndarray。

控制台显示

非常大的DataFrame将被截断以在控制台中显示它们。 您还可以使用info()获得摘要。

如果DataFrame的宽度太大时,可以通过设置display.width 选项来更改在单行上打印的数量:

pd.set_option('display.width',10)  # default is 80  在jupyter中不起作用。
pd.DataFrame(np.random.randn(3, 12))  
01234567891011
01.019574-1.1591821.3536180.6376820.813734-0.063821-0.678584-2.029914-0.334250-1.8554520.2674270.159262
1-0.644825-0.299352-1.1032111.2966742.6383830.389328-0.0785530.700434-0.7681230.101834-0.4724840.346692
20.844621-0.0827511.8017760.106621-1.4058541.1052501.174156-2.4147650.3351450.148878-0.723033-0.186628

访问DataFram的column

访问DataFrame的column主要有两种方法。

df = pd.DataFrame({'foo1': np.random.randn(5), 'foo2': np.random.randn(5)})
df
foo1foo2
0-2.011344-1.554834
10.0907041.385963
20.8840891.258341
31.756175-1.526961
40.356461-0.958286
df['foo1'] # 方法一
0   -2.011344
1    0.090704
2    0.884089
3    1.756175
4    0.356461
Name: foo1, dtype: float64
df.foo1 # 方法二
0   -2.011344
1    0.090704
2    0.884089
3    1.756175
4    0.356461
Name: foo1, dtype: float64

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值