核心数据结构
pandas最核心的就是Series和DataFrame两个数据结构。
名称维度说明
Series
1维
带有标签的同构类型数组
DataFrame
2维
表格结构,带有标签,大小可变,且可以包含异构的数据列
DataFrame可以看做是Series的容器,即:一个DataFrame中可以包含若干个Series。
series
由于Series是一堆结构的数据,我们可以直接通过数组来创建这种数据,像这样:
importpandas as pdimportnumpy as np
series1= pd.Series([1, 2, 3, 4])print("series1:\n{}\n".format(series1))#series1:#0 1#1 2#2 3#3 4#dtype: int64
输出的最后一行是Series中数据的类型,这里的数据都是int64类型的。
数据在第二列输出,第一列是数据的索引
我们分别打印出Series中的数据和索引
print("series1.values: {}\n".format(series1.values))print("series1.index: {}\n".format(series1.index))#series1.values: [1 2 3 4]#series1.index: RangeIndex(start=0, stop=4, step=1)
我们可以指定索引的类型,例如字符串
series2 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=["C", "D", "E", "F", "G", "A", "B"])print("series2:\n{}\n".format(series2))print("E is {}\n".format(series2["E"]))#series2:#C 1#D 2#E 3#F 4#G 5#A 6#B 7#dtype: int64
#E is 3
DataFrame
通过Numpy接口来创建一个4x4的矩阵,以此来创建DataFrame
1 importpandas as pd2 importnumpy as np3
4 df1 = pd.DataFrame(np.arange(16).reshape(4,4))5 print("df1:\n{}\n".format(df1))6
7 #df1:
8 #0 1 2 3
9 #0 0 1 2 3
10 #1 4 5 6 7
11 #2 8 9 10 11
12 #3 12 13 14 15
View Code
默认的索引和列名都是[0,N-1]的形式,同样我们可以指定列名和索引,
1 importpandas as pd2 importnumpy as np3
4 df2 = pd.DataFrame(np.arange(16).reshape(4,4),5 columns=["column1", "column2", "column3", "column4"],6 index=["a", "b", "c", "d"])7 print("df2:\n{}\n".format(df2))8
9 #df2:
10 #column1 column2 column3 column4
11 #a 0 1 2 3
12 #b 4 5 6 7
13 #c 8 9 10 11
14 #d 12 13 14 15
View Code
我们也可以指定结构来创建DataFrame
1 importpandas as pd2 importnumpy as np3
4 df3 = pd.DataFrame({"note" : ["C", "D", "E", "F", "G", "A", "B"],5 "weekday": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]})6 print("df3:\n{}\n".format(df3))7
8 #df3:
9 #note weekday
10 #0 C Mon
11 #1 D Tue
12 #2 E Wed
13 #3 F Thu
14 #4 G Fri
15 #5 A Sat
16 #6 B Sun
View Code
注意:
DataFrame的不同列可以是不同的数据类型
如果以Series数组来创建DataFrame,每个Series将成为一行,而不是一列
1 importpandas as pd2 importnumpy as np3
4 noteSeries = pd.Series(["C", "D", "E", "F", "G", "A", "B"],5 index=[1, 2, 3, 4, 5, 6, 7])6 weekdaySeries = pd.Series(["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],7 index=[1, 2, 3, 4, 5, 6, 7])8 df4 =pd.DataFrame([noteSeries, weekdaySeries])9 print("df4:\n{}\n".format(df4))10
11 #df4:
12 #1 2 3 4 5 6 7
13 #0 C D E F G A B
14 #1 Mon Tue Wed Thu Fri Sat Sun
View Code
我们还可以“添加”或“删除”列数据
1 importpandas as pd2 importnumpy as np3
4 df3 = pd.DataFrame({"note" : ["C", "D", "E", "F", "G", "A", "B"],5 "weekday": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]})6 df3["No."] = pd.Series([1, 2, 3, 4, 5, 6, 7])7 print("df3:\n{}\n".format(df3))8
9 del df3["weekday"]10 print("df3:\n{}\n".format(df3))11
12 #df3:
13 #note weekday No.
14 #0 C Mon 1
15 #1 D Tue 2
16 #2 E Wed 3
17 #3 F Thu 4
18 #4 G Fri 5
19 #5 A Sat 6
20 #6 B Sun 7
21
22 #df3:
23 #note No.
24 #0 C 1
25 #1 D 2
26 #2 E 3
27 #3 F 4
28 #4 G 5
29 #5 A 6
30 #6 B 7
View Code
index对象与数据访问
同样可以通过索引来获取DataFrame的行和列
1 print("df3.columns\n{}\n".format(df3.columns))2 print("df3.index\n{}\n".format(df3.index))3
4 #df3.columns
5 #Index(['note', 'No.'], dtype='object')
6
7 #df3.index
8 #RangeIndex(start=0, stop=7, step=1)
View Code
注意:
Index并非集合,因此其中可以包含重复的数据
Index对象的值是不可以改变,因此可以通过它安全的访问数据
DataFrane提供了下面两个操作符来访问其中的数据
loc:通过行和列的索引来访问数据
iloc:通过行和列的下标来访问数据
1 print("Note C, D is:\n{}\n".format(df3.loc[[0, 1], "note"]))2 print("Note C, D is:\n{}\n".format(df3.iloc[[0, 1], 0]))3
4 #Note C, D is:
5 #0 C
6 #1 D
7 #Name: note, dtype: object
8
9 #Note C, D is:
10 #0 C
11 #1 D
12 #Name: note, dtype: object
View Code
第一行代码访问了行索引为0和1,列索引为“note”的元素,第二行代码访问了行下标为0和1对于df3来说,行索引和行下标刚好是一样的,所以这里都是0和1,但它们却是不同的含义),列下标为0的元素。
文件操作
读取Excel文件
注:要读取Excel文件,还需要安装另外一个库;xlrd
pip install xlrd
1 importpandas as pd2 importnumpy as np3
4 df1 = pd.read_excel("data/test.xlsx")5 print("df1:\n{}\n".format(df1))6
7 #df1:
8 #C Mon
9 #0 D Tue
10 #1 E Wed
11 #2 F Thu
12 #3 G Fri
13 #4 A Sat
14 #5 B Sun
View Code
读取csv文件
1 C,Mon2 D,Tue3 E,Wed4 F,Thu5 G,Fri6 A,Sat
第一个CSV文件内容
1 C|Mon2 D|Tue3 E|Wed4 F|Thu5 G|Fri6 A|Sat
第二个CSV文件的内容
读取CSV文件
1 importpandas as pd2 importnumpy as np3 df2 = pd.read_csv("data/test1.csv")4 print("df2:\n{}\n".format(df2))5 #df3 = pd.read_csv("data/test2.csv", sep="|")
6 #print("df3:\n{}\n".format(df3))
View Code
我们可以发现,第二个CSV文件并不是通过逗号分隔的,我们通常指定分隔符的方式来读取这个文件。
read_csv支持非常多的参数用来调整读取的参数
参数说明
path
文件路径
sep或者delimiter
字段分隔符
header
列名的行数,默认是0(第一行)
index_col
列号或名称用作结果中的行索引
names
结果的列名称列表
skiprows
从起始位置跳过的行数
na_values
代替NA的值序列
comment
以行结尾分隔注释的字符
parse_dates
尝试将数据解析为datetime。默认为False
keep_date_col
如果将列连接到解析日期,保留连接的列。默认为False。
converters
列的转换器
dayfirst
当解析可以造成歧义的日期时,以内部形式存储。默认为False
data_parser
用来解析日期的函数
nrows
从文件开始读取的行数
iterator
返回一个TextParser对象,用于读取部分内容
chunksize
指定读取块的大小
skip_footer
文件末尾需要忽略的行数
verbose
输出各种解析输出的信息
encoding
文件编码
squeeze
如果解析的数据只包含一列,则返回一个Series
thousands
千数量的分隔符
详细的read_csv函数说明请参见这里:pandas.read_csv
处理无效值
主要有两种处理方法:直接忽略这些无效值;或者将无效值替换成有效值。
我们先创建一个包含无效值的数据结构。然后通过pandas.isna函数来确认哪些值是无效的:
1 importpandas as pd2 importnumpy as np3
4 df = pd.DataFrame([[1.0, np.nan, 3.0, 4.0],5 [5.0, np.nan, np.nan, 8.0],6 [9.0, np.nan, np.nan, 12.0],7 [13.0, np.nan, 15.0, 16.0]])8
9 print("df:\n{}\n".format(df));10 print("df:\n{}\n".format(pd.isna(df)))11
12 #df:
13 #0 1 2 3
14 #0 1.0 NaN 3.0 4.0
15 #1 5.0 NaN NaN 8.0
16 #2 9.0 NaN NaN 12.0
17 #3 13.0 NaN 15.0 16.0
18
19 #df:
20 #0 1 2 3
21 #0 False True False False
22 #1 False True True False
23 #2 False True True False
24 #3 False True False False
View Code
忽略无效值
我们可以通过pandas.DataFrame.dropna函数抛弃无效值
1 importpandas as pd2 importnumpy as np3
4 df = pd.DataFrame([[1.0, np.nan, 3.0, 4.0],5 [5.0, np.nan, np.nan, 8.0],6 [9.0, np.nan, np.nan, 12.0],7 [13.0, np.nan, 15.0, 16.0]])8
9 print("df.dropna():\n{}\n".format(df.dropna()));10
11 #df.dropna():
12 #Empty DataFrame
13 #Columns: [0, 1, 2, 3]
14 #Index: []
View Code
对于原先的结构,当无效值全部被抛弃之后,将不再是一个有效的DataFrame,所以才会是以上结果
我们也可以选择抛弃整列都是无效值的那一列:
1 importpandas as pd2 importnumpy as np3
4 df = pd.DataFrame([[1.0, np.nan, 3.0, 4.0],5 [5.0, np.nan, np.nan, 8.0],6 [9.0, np.nan, np.nan, 12.0],7 [13.0, np.nan, 15.0, 16.0]])8
9 print("df.dropna(axis=1,how='all'):\n{}\n".format(df.dropna(axis=1, how='all')));10
11 #df.dropna(axis=1, how='all'):
12 #0 2 3
13 #0 1.0 3.0 4.0
14 #1 5.0 NaN 8.0
15 #2 9.0 NaN 12.0
16 #3 13.0 15.0 16.0
View Code
注:axis=1表示列的轴。how可以取值’any’或者’all’,默认是前者。
替换无效值
我们也可以通过fillna函数将无效值替换成为有效值
1 importpandas as pd2 importnumpy as np3
4 df = pd.DataFrame([[1.0, np.nan, 3.0, 4.0],5 [5.0, np.nan, np.nan, 8.0],6 [9.0, np.nan, np.nan, 12.0],7 [13.0, np.nan, 15.0, 16.0]])8
9 print("df:\n{}\n".format(df));10
11 print("df.fillna(1):\n{}\n".format(df.fillna(1)));12
13 #df:
14 #0 1 2 3
15 #0 1.0 NaN 3.0 4.0
16 #1 5.0 NaN NaN 8.0
17 #2 9.0 NaN NaN 12.0
18 #3 13.0 NaN 15.0 16.0
19
20 #df.fillna(1):
21 #0 1 2 3
22 #0 1.0 1.0 3.0 4.0
23 #1 5.0 1.0 1.0 8.0
24 #2 9.0 1.0 1.0 12.0
25 #3 13.0 1.0 15.0 16.0
View Code
将无效值全部替换成同样的数据可能意义不大,因此我们可以指定不同的数据来进行填充。为了便于操作,在填充之前,我们可以先通过rename方法修改行和列的名称:
1 importpandas as pd2 importnumpy as np3
4 df = pd.DataFrame([[1.0, np.nan, 3.0, 4.0],5 [5.0, np.nan, np.nan, 8.0],6 [9.0, np.nan, np.nan, 12.0],7 [13.0, np.nan, 15.0, 16.0]])8
9 print("df:\n{}\n".format(df));10 print("df:\n{}\n".format(pd.isna(df)))11
12 df.rename(index={0: 'index1', 1: 'index2', 2: 'index3', 3: 'index4'},13 columns={0: 'col1', 1: 'col2', 2: 'col3', 3: 'col4'},14 inplace=True);15 df.fillna(value={'col2': 2}, inplace=True) #把第2列的空值变成2
16 df.fillna(value={'col3': 7}, inplace=True) #把第3列的空值变成7
17 print("df:\n{}\n".format(df));18
19 #df:
20 #0 1 2 3
21 #0 1.0 NaN 3.0 4.0
22 #1 5.0 NaN NaN 8.0
23 #2 9.0 NaN NaN 12.0
24 #3 13.0 NaN 15.0 16.0
25
26 #df:
27 #0 1 2 3
28 #0 False True False False
29 #1 False True True False
30 #2 False True True False
31 #3 False True False False
32
33 #df:
34 #col1 col2 col3 col4
35 #index1 1.0 2.0 3.0 4.0
36 #index2 5.0 2.0 7.0 8.0
37 #index3 9.0 2.0 7.0 12.0
38 #index4 13.0 2.0 15.0 16.0
View Code
处理字符串
Series的str字段包含了一系列的函数用来处理字符串。并且,这些函数会自动处理无效值。
1 importpandas as pd2
3 s1 = pd.Series(['1', '2', '3', '4', '5']);4 print("s1.str.rstrip():\n{}\n".format(s1.str.lstrip()))5 print("s1.str.strip():\n{}\n".format(s1.str.strip()))6 print("s1.str.isdigit():\n{}\n".format(s1.str.isdigit()))7
8 #s1.str.rstrip():
9 #0 1
10 #1 2
11 #2 3
12 #3 4
13 #4 5
14 #dtype: object
15
16 #s1.str.strip():
17 #0 1
18 #1 2
19 #2 3
20 #3 4
21 #4 5
22 #dtype: object
23
24 #s1.str.isdigit():
25 #0 False
26 #1 False
27 #2 False
28 #3 True
29 #4 True
30 #dtype: bool
View Code
我们还能对字符串进行大写、小写、以及字符串长度的处理。
1 importpandas as pd2
3 s2 = pd.Series(['Stairway to Heaven', 'Eruption', 'Freebird',4 'Comfortably Numb', 'All Along the Watchtower'])5 print("s2.str.lower():\n{}\n".format(s2.str.lower()))6 print("s2.str.upper():\n{}\n".format(s2.str.upper()))7 print("s2.str.len():\n{}\n".format(s2.str.len()))8
9 #s2.str.lower():
10 #0 stairway to heaven
11 #1 eruption
12 #2 freebird
13 #3 comfortably numb
14 #4 all along the watchtower
15 #dtype: object
16
17 #s2.str.upper():
18 #0 STAIRWAY TO HEAVEN
19 #1 ERUPTION
20 #2 FREEBIRD
21 #3 COMFORTABLY NUMB
22 #4 ALL ALONG THE WATCHTOWER
23 #dtype: object
24
25 #s2.str.len():
26 #0 18
27 #1 8
28 #2 8
29 #3 16
30 #4 24
31 #dtype: int64
View Code
参考文献