数据处理
提取出来的数据多种多样,可能会有 URL、网页文本信息、多媒体信息。
有一部分信息会被直接存为本地常用的文档(xlsx、html、csv 等),譬如抓取好的网页文本信息。也有的信息会直接被保存到数据库,后期有需要时再调用,譬如多媒体文件。这些信息有的会存入消息队列和其他系统对接做成一个更大的系统,譬如 URL。
numpy:支持高性能的大规模数组运算,是大部分科学计算的基础库。可用于进一步的数据处理。
pandas:支持十多种常见文档格式的输入与输出,一站式搞定数据存取与处理。
数据库今年来格局逐渐明朗,关系型与非关系型数据库、图数据库、搜索引擎等等。 消息队列目前是 kafka 和 RabbitMQ 占据主导地位,随着分布式的进行,未来应该还会有更多可用的消息队列。
Numpy 数组
数组:array
很多其他科学计算的第三方库都是以 Numpy 为基础建立的。
Numpy 的一个重要特性是它的数组计算。
使用前一定要先导入 Numpy 包,导入的方法有以下几种:
import numpy
import numpy as np
from numpy import *
from numpy import array, sin
导入 numpy,最常用为这种:
import numpy as np
假如我们想将列表中的每个元素增加 1,但列表不支持这样的操作(报错):
a = [1, 2]
# a + 1 # 报错
使用 numpy.array:
a = np.array(a)
a # [1 2]
b = a + 1
b # array([2,3])
与另一个 array 相加,得到对应元素相加的结果:
c = a + b
print(c) # array([3,5])
# 对应元素相乘:
print(a * b) # [2 6]
# 对应元素乘方:
print(a ** b) # [1 8]
数组的合并
import numpy as np
a = np.array([[1, 2], [3, 4]])
b = np.arange(2) # np.array([0, 1])
print(a, b)
'''[[1 2]
[3 4]] [0 1]'''
# 正确的做法是:
np.append(a, b) # array([1, 2, 3, 4, 0, 1])
# 错误的做法是:
print(list(a)+ list(b)) # [array([1, 2]), array([3, 4]), 0, 1]
提取数组中的元素
# 提取第一个
a = np.array([1, 2, 3, 4])
print(a[0]) # 1
# 提取前两个元素:
print(a[:2]) # [1 2]
# 最后两个元素
print(a[-2:]) # [3 4]
# 相加:
print(a[:2] + a[-2:]) # [4 6]
修改数组形状
查看 array 的形状:
b = a.shape
b # (4,)
# 修改 array 的形状:
a.shape = 2, 2
a
# [[1 2]
# [3 4]]
# 多维数组
# a 现在变成了一个二维的数组,可以进行加法:
a + a
# [[2 4]
# [6 8]]
# 乘法仍然是对应元素的乘积,并不是按照矩阵乘法来计算:
a * a
# [[ 1 4]
# [ 9 16]]
Numpy 索引:index
import numpy as np
# 查看形状,会返回一个元组,每个元素代表这一维的元素数目:
a = np.array([1, 2, 3, 5])
# 1维数组,返回一个元组
a.shape
# 查看元素数目:
a.size
使用 fill 方法设定初始值
可以使用 fill 方法将数组设为指定值:
print(a)
a.fill(-4)
print(a)
# 切片,支持负索引:
a = np.array([11, 12, 13, 14, 15])
print(a[1:-2]) # [12 13]
# 省略参数:
print(a[::2]) # [11 13 15]
print(a[-2:]) # array([14, 15])
假设我们记录一辆汽车表盘上每天显示的里程数:
rec = np.array([21000, 21180, 21240, 22100, 22400])
dist = rec[1:] - rec[:-1] # 后一天减去前一天的
dist
多维数组的索引
a = np.array([[1, 2, 3], [7, 8, 9]])
a
# 查看形状:
print(a.shape)
# 查看总的元素个数:
print(a.size)
# 查看维数:
print(a.ndim)
# 对于二维数组,可以传入两个数字来索引:
print(a[1, 1])
# 索引一整行内容:
print(a[0])
多维数组的复杂一点的例子:
a = np.array([[0, 1, 2, 3, 4, 5],
[10, 11, 12, 13, 14, 15],
[20, 21, 22, 23, 24, 25],
[30, 31, 32, 33, 34, 35],
[40, 41, 42, 43, 44, 45],
[50, 51, 52, 53, 54, 55]])
# 想得到第一行的第 4 和第 5 两个元素:
print(a[0, 3:5]) # [3 4]
# 得到最后两行的最后两列:
print(a[4:, 4:]) # [[44 45][54 55]]
# 得到第三列:
print(a[:, 2]) # [ 2 12 22 32 42 52]
取出 3,5 行的奇数列:
b = a[2::2, ::2]
b
切片在内存中使用的是引用机制
引用机制意味着,Python 并没有为 b 分配新的空间来存储它的值, 而是让 b 指向了 a 所分配的内存空间,因此,改变 b 会改变 a 的值:
a = np.array([0, 1, 2, 3, 4])
b = a[2:4]
b
b[0] = 10
b
a
# 而这种现象在列表中并不会出现:
b = a[2:3]
b[0] = 12
print(a)
# 解决方法是使用copy()方法产生一个复制,这个复制会申请新的内存:
b = a[2:4].copy()
b[0] = 10
print(a, b)
一维花式索引
与 range 函数类似,我们可以使用 arange 函数来产生等差数组。
a = np.arange(0, 80, 10)
a
# 花式索引需要指定索引位置:
indices = [1, 2, -3]
y = a[indices]
y
# 还可以使用布尔数组来花式索引:
mask = np.array([0, 1, 1, 0, 0, 1, 0, 1], dtype=bool)
a[mask] # [10 20 50 70]
选出了所有大于 0.5 的值:
from numpy.random import rand
a = rand(10)
a
mask = a > 0.5
a[mask]
“不完全”索引
只给定行索引的时候,返回整行:
a = np.array([[0, 1, 2, 3, 4, 5],
[10, 11, 12, 13, 14, 15],
[20, 21, 22, 23, 24, 25],
[30, 31, 32, 33, 34, 35],
[40, 41, 42, 43, 44, 45],
[50, 51, 52, 53, 54, 55]])
b = a[:3]
b
# 这时候也可以使用花式索引取出第2,3,5行:
condition = np.array([0, 1, 1, 0, 1, 0], dtype=bool)
c = a[condition]
c
where 语句
where(array)
where 函数会返回所有非零元素的索引。
a = np.array([1, 2, 4, 6])
a > 2 # [False False True True]
b = np.where(a > 2)
b # 返回的是索引位置
# 注意到 where 的返回值是一个元组。
index = np.where(a > 2)[0]
print(index) # [2 3]
# 可以直接用 where 的返回值进行索引:
loc = np.where(a > 2)
b = a[loc]
print(b) # [4 6]
考虑二维数组:
a = np.array([[0, 12, 5, 20],
[1, 2, 11, 15]])
loc = np.where(a > 10)
print(loc) # (array([0, 0, 1, 1]), array([1, 3, 2, 3]))
# 也可以直接用来索引a:
b = a[loc]
print(b) # [12 20 11 15]
或者可以这样:
rows, cols = np.where(a > 10)
print(rows)
print(cols)
print(a[rows, cols])
例子:
a = np.arange(20)
a.shape = 5, 4
a
a > 12
b = np.where(a > 12)
b
# (array([3, 3, 3, 4, 4, 4, 4]), array([1, 2, 3, 0, 1, 2, 3]))
a[b] # [13 14 15 16 17 18 19]
Numpy 方法
Numpy 的常用方法。
import numpy as np
a = np.array([[0, 1, 2, 3], [4, 5, 6, 7]])
a
for row in a:
print(row)
所有元素的迭代器:
for i in a.flat:
print(i)
矩阵转置
print(a)
print(a.T)
print(a)
print(a.shape) # 数组形状 (m,n,o,...)
print(a.size) # 数组元素数
a.resize((4, 2))
print(a)
print(a.shape)
squeeze
把 shape 为 1 的维度去掉:
a = np.arange(10).reshape(1,10)
a
a.shape
b = np.squeeze(a)
b
b.shape
再举个多维的例子:
a = np.arange(10).reshape(1, 2, 5)
print(a)
print(a.shape)
b = np.squeeze(a)
b.shape
a.shape
复制
a = np.array([[0, 1, 2, 3], [4, 5, 6, 7]])
b = a.copy()
b[0][0] = -1
b
填充
b.fill(9)
b
# 转化为列表:
a.tolist()
复数
# 实部:
b = np.array([1 + 2j, 3 + 4j, 5 + 6j])
c = b.real
print(c)
# 虚部:
d = b.imag
print(d)
# 共轭:
print(b.conj())
# 保存成文本:
a.dump("file.txt")
import os
os.path.exists('file.txt')
with open('file.txt', 'rb') as f:
m = f.read()
m
# 字符串:
a.dumps()
# 写入文件
a.tofile('foo.csv', sep=',', format="%s")
os.path.exists('foo.csv')
with open('foo.csv') as f:
m = f.read()
m
排序
非零元素的索引:
b = a.nonzero()
a
b
# 排序:
b = np.array([3, 2, 7, 4, 1])
b.sort()
b
# 排序的索引位置:
b = np.array([2, 3, 1])
b.argsort(axis=-1) # array([2, 0, 1])
# 将 b 插入 a 中的索引,使得 a 保持有序:
a = np.array([1, 3, 4, 6])
b = np.array([0, 2, 5])
print(a.searchsorted(b))
元素的数学操作
clip,限制在一定范围:
a = np.array([[4, 1, 3], [2, 1, 5]])
a.clip(0, 2)
a
# 近似:
a = np.array([1.344, 2.449, 2.558])
b = a.round(decimals=2)
b # [ 1.34 2.45 2.56]
# 是否全部非零:
print(a.all())
import os
os.remove('foo.csv')
os.remove('file.txt')
数组与字符串的转换
tobytes 函数
a = np.array([[1, 2], [3, 4]], dtype=np.uint8)
print(a)
print(a.tobytes())
frombuffer 函数
可以使用 frombuffer 函数从字符串中读出数据,不过要指定类型:
s = a.tobytes()
b = np.frombuffer(s, dtype=np.uint8)
b
此时,返回的数组是一维的,需要重新设定维度:
b.shape = 2, 2
b
# 可以使用reshape:
b = np.frombuffer(s, dtype=np.uint8).reshape(2, 2)
b
文本中读取数组
对于读文本文件,推荐使用:
- loadtxt
- genfromtxt
- savetxt
对于二进制文本文件,推荐使用
- save
- load
- savez
loadtxt 函数
loadtxt(fname, dtype=<type 'float'>,
comments='#', delimiter=None,
converters=None, skiprows=0,
usecols=None, unpack=False, ndmin=0)
- loadtxt 有很多可选参数,其中 delimiter 就是刚才用到的分隔符参数。
- skiprows 参数表示忽略开头的行数,可以用来读写含有标题的文本
data_file = "../data/numpy/data.txt"
c = np.loadtxt(data_file, dtype=int)
c
c.shape
genfromtxt
genfromtxt 函数功能更为全面, 能处理更多的情况,但相应的速度和效率会慢一些。
help(np.genfromtxt)
g = np.genfromtxt(data_file)
g
当然,还有很笨的写法:
首先将数据转化成一个列表组成的列表,再将这个列表转换为数组:
data = []
with open(data_file) as f:
# 每次读一行
for line in f:
fileds = line.split()
row_data = [float(x) for x in fileds]
data.append(row_data)
data = np.array(data)
data
# loadtxt 的更多特性
sp_file = '../data/numpy/special_data.txt'
data = np.loadtxt(sp_file,
dtype=int,
comments='%', # 百分号为注释符
delimiter=',', # 逗号分割
skiprows=1, # 忽略第一行
usecols=(0, 1, 2, 4)) # 指定使用哪几列数据
data
loadtxt 自定义转换方法
loadtxt 返回的值为字节字符串 bytes, 对字符串解码用函数 decode(‘asii’),变成 str 格式:
import datetime
def date_converter(s):
return datetime.datetime.strptime(s.decode('ascii'), "%Y-%m-%d")
date_file = '../data/numpy/datetime_data.txt'
data = np.loadtxt(date_file,
dtype=object, # 数据类型为对象
converters={0: date_converter, # 第一列使用自定义转换方法
1: float, # 第二第三列使用浮点数转换
2: float})
data
将数组写入文件
savetxt 可以将数组写入文件,默认使用科学计数法的形式保存:
a = np.array([[1, 2, 3], [5, 6, 7]])
np.savetxt('out.txt', a)
# 可以用类似printf 的方式指定输出的格式:
a = np.array([[1, 2, 3], [5, 6, 7]])
print(a.shape)
np.savetxt('out_fmt.txt', a, fmt=['%d'] * a.shape[1], newline='\n')
with open('out_fmt.txt') as f:
for line in f:
print(line)
m = zip([1, 2, 3, 4, 5], ['a', 'b', 'c', 'd', 'e'])
m = list(m)
z = np.array(m)
print(z)
np.savetxt('out_str_fmt.txt', z, fmt=['%s'] * z.shape[1])
import os
os.remove('out.txt')
os.remove('out_fmt.txt')
os.remove('out_str_fmt.txt')
Numpy 二进制格式
保存的方法:
- save(file, arr) 保存单个数组,.npy 格式
- savez(file, *args, **kwds) 保存多个数组,无压缩的 .npz 格式
- savez_compressed(file, *args, **kwds) 保存多个数组,有压缩的 .npz 格式
a = np.array([[1, 2], [3, 4]])
np.save('out.npy', a)
# 二进制与文本大小比较
a = np.arange(10000.)
np.savetxt('a.txt', a)
# 查看大小:
import os
print(os.stat('a.txt').st_size)
# 保存为二进制
np.save('a.npy', a)
print(os.stat('a.npy').st_size)
二进制文 件大约是文本文件的三分之一。
# 保存多个数组
a = np.array([[1, 2], [3, 4]])
b = np.arange(1000)
print(a)
print(b)
np.savez('ab.npz', a=a, b=b)
# 加载数据
ab = np.load('ab.npz')
print(os.stat('ab.npz').st_size) # file size
print(ab.keys())
print(list(ab.keys()))
print(ab['a'].shape)
print(ab['b'].shape)
np.savez_compressed('ab_compressed.npz', a=a, b=b)
print(os.stat('ab_compressed.npz').st_size) # file size
os.remove('out.npy')
os.remove('a.txt')
os.remove('a.npy')
os.remove('ab.npz')
os.remove('ab_compressed.npz')
生成数组的函数
arange 生成数组,[start,stop)
arange(start, stop=None, step=1, dtype=None)
np.arange(5) # [0 1 2 3 4]
a = np.arange(0, 2 * np.pi, np.pi / 4)
a
linspace
linspace(start,stop,N)
产生 N 个等距分布在[start,stop]间的元素组成的数组,包括 start,stop
np.linspace(0, 1, 5) # [ 0. 0.25 0.5 0.75 1. ]
logspace
logspace(start, stop, N)
产生 N 个对数等距分布的数组,默认以 10 为底:
np.logspace(0, 1, 5)
产生的值为。
meshgrid
二维平面中生成一个网格
x_ticks = np.linspace(-1, 1, 5)
y_ticks = np.linspace(-1, 1, 5)
x, y = np.meshgrid(x_ticks, y_ticks)
print(x_ticks)
print(x)
图例
import matplotlib.pyplot as plt
from matplotlib import cm
def f(x, y):
# sinc 函数
r = np.sqrt(x ** 2 + y ** 2)
result = np.sin(r) / r
result[r == 0] = 1.0
return result
x_ticks = np.linspace(-10, 10, 51)
y_ticks = np.linspace(-10, 10, 51)
x, y = np.meshgrid(x_ticks, y_ticks, sparse=True)
print(x) # x, y 中有很多冗余的元素,这里提供了一个 sparse 的选项去冗余
z = f(x, y)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x, y, z,
rstride=1, cstride=1,
cmap=cm.YlGnBu_r)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.show()
内存映射
Numpy 有对内存映射的支持。
内存映射也是一种处理文件的方法,主要的函数有:
- memmap
- frombuffer
- ndarray constructor
使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行 I/O 操作, 使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。
memmap(filename,
dtype=uint8,
mode='r+'
offset=0
shape=None
order=0)
mode 表示文件被打开的类型:
- r 只读
- c 复制+写,但是不改变源文件
- r+ 读写,使用 flush 方法会将更改的内容写入文件
- w+ 写,如果存在则将数据覆盖
pandas
Pandas 的主要数据结构是 Series (一维数据)与 DataFrame(二维数据),这两种数据结构足以处理金融、统计、社会科学、工程等领域里的大多数典型用例。
Series 是一种类似于一维数组的对象,它由一组数据(各种 Numpy 数据类型)以及一组与之相关的数据标签(即索引)组成。
DataFrame 是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型值)。DataFrame 既有行索引也有列索引,它可以被看做由 Series 组成的字典(共同用一个索引)。
pandas 数据存取-csv/xlsx/xls
import pandas as pd
data = [['Google',10],['Runoob',12],['Wiki',13]]
df = pd.DataFrame(data,columns=['Site','Age'],dtype=float)
df.to_csv('file1.csv',index=False)
df = pd.read_csv('file1.csv')
df.to_excel('file1.xlsx',index=False)
df = pd.read_excel('file1.xlsx')
df.to_excel('file1.xls',index=False)
df = pd.read_excel('file1.xls')
df
'''
Site Age
0 Google 10
1 Runoob 12
2 Wiki 13
'''
pandas 数据存取-json
data =[
{
"id": "A001",
"name": "菜鸟教程",
"url": "www.runoob.com",
"likes": 61
},
{
"id": "A002",
"name": "Google",
"url": "www.google.com",
"likes": 124
},
{
"id": "A003",
"name": "淘宝",
"url": "www.taobao.com",
"likes": 45
}
]
df = pd.DataFrame(data)
df.to_json('sites.json')
df = pd.read_json('sites.json')
print(df.to_string())
'''
id name url likes
0 A001 菜鸟教程 www.runoob.com 61
1 A002 Google www.google.com 124
2 A003 淘宝 www.taobao.com 45
'''
pandas 数据存取-sql
from sqlalchemy import create_engine,text
import pandas as pd
MYSQL_HOST = '*'
MYSQL_PORT = 3306
MYSQL_USER = 'employee_u'
MYSQL_PASSWORD = 'employee_s'
MYSQL_DB = 'employee'
engine = create_engine('mysql+pymysql://{}:{}@{}:{}/{}'.format(MYSQL_USER,MYSQL_PASSWORD,MYSQL_HOST,MYSQL_PORT,MYSQL_DB),
echo = False)
dataset = pd.DataFrame({'Names':['Abhinav','Aryan',
'Manthan'],
'DOB' : ['10/01/2009','24/03/2009',
'28/02/2009']})
dataset.to_sql('Employee_Data',con = engine,index=False)
#附加到以前创建的数据库中
dataset.to_sql('Employee_Data',con = engine,index=False,if_exists = 'append')
# 查看是否写入成功
with engine.connect() as conn:
df1 = pd.read_sql('Employee_Data',con = conn,columns = ["Names"])
df2 = pd.read_sql('Employee_Data',con = conn,index_col = 'Names',columns = ["Names"])
df3 = pd.read_sql_table("Employee_Data", conn)
df4 = pd.read_sql_query(text("select * from Employee_Data"),con = conn)
df5 = conn.execute(text("select MAX(`index`) from Employee_Data")).fetchall()
df6 = conn.execute(text("select `index` from Employee_Data WHERE `index` > :index"),{"index":1}).fetchall()
print(df1)
print(df2)
print(df3)
print(df4)
print(df5)
print(df6)
快速的识别结构化数据
import numpy as np
import scipy as sp
import pandas as pd
iris_file = './iris.data'
data = pd.read_csv(iris_file, header=None, encoding='utf-8')
data
快速的操作元数据
cnames = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'class']
data.columns = cnames
data
快速过滤
data[data['petal_width'] == data.petal_width.max()]
快速切片
data.iloc[::30, :2]
快速统计
data['class'].value_counts()
for x in range(4):
s = data.iloc[:,x]
print('{0:<12}'.format(s.name), " Statistics: ",
'{0:>5} {1:>5} {2:>5} {3:>5}'.format(s.max(), s.min(), round(s.mean(),2),round(s.std(),2)))
快速“MapReduce”
slogs = lambda x:np.log(x)*x
entpy = lambda x:np.exp((slogs(x.sum())-x.map(slogs).sum())/x.sum())
data.groupby('class').agg(entpy)
Pandas 的重要数据类型
- DataFrame(二维表)
- Series(一维序列)
- Index(行索引,行级元数据)
1.1 Series:pandas 的长枪(数据表中的一列或一行,观测向量,一维数组...)
数据世界中对于任意一 个个体的全面观测,或者对于任意一组个体某一属性的观测,全部可以抽象为 Series 的概念。
用值构建一个 Series:
由默认 index 和 values 组成。
series1 = pd.Series(np.random.randn(4))
series1
print(type(series1))
print(series1.index)
print(series1.values)
Series 支持过滤的原理就如同 NumPy
series1 > 0
series1[series1 > 0]
当然也支持 Broadcasting
series1*2
series1+5
以及 Universal Function
print(series1)
print(np.exp(series1))
#NumPy Universal Function
f_np = np.frompyfunc(lambda x:np.exp(x*2 + 5), 1, 1)
f_np(series1)
在序列上就使用行标,而不是创建一个 2 列的数据表,能够轻松辨别哪里是数据,哪里是元数据:
series2 = pd.Series(series1.values, index=['norm_' + str(i) for i in range(4)])
print(series2, type(series2))
print(series2.index)
print(type(series2.index))
print(series2.values)
series2
虽然行是有顺序的,但是仍然能够通过行级的 index 来访问到数据:
(当然也不尽然像 Ordered Dict,因为行索引甚至可以重复, 不推荐重复的行索引不代表不能用)
series2[['norm_0','norm_3']]
'norm_0' in series2
'norm_6' in series2
默认行索引就像行号一样:
series1.index
从 Key 不重复的 Ordered Dict 或者从 Dict 来定义 Series 就不需要担心行索引重复:
s_dict = {"Japan":"Tokyo", "Korea":"Seoul", "China":"Beijing"}
series3 = pd.Series(s_dict)
print(series3.index)
print(series3.values)
series3
与 Dict 区别一: 有序
lst = ["Japan", "China", "Singapore", "Korea"]
series4 = pd.Series(s_dict, index =lst)
series4
print(series4.values)
print(series4.index)
print(series4.isnull())
print(series4.notnull())
与 Dict 区别二: index 内值可以重复,尽管不推荐。
lst = ['A', 'B', 'B', 'C']
series5 = pd.Series(series1.values, index=lst)
series5
series5[['B', 'A']]
整个序列级别的元数据信息:name
当数据序列以及 index 本身有了名字,就可以更方便的进行后续的数据关联啦!
series4.name
series4.index.name
series4.name = "Capital Series"
series4.index.name = "Nation"
series4
pd.DataFrame(series4)
1.2 DataFrame:pandas 的战锤(数据表 ,二维数组)
Series 的有序集合,就像 R 的 DataFrame 一样方便。
仔细想想,绝大部分的数据形式都可以表现为 DataFrame。
从 Numpy 二维数组、从文件或者从数据库定义:数据虽好,勿忘列名
data_np = np.asarray([('Japan', 'Tokyo', 4000),
('Korea', 'Seoul', 1300),
('China', 'Beijing', 9100)])
df1 = pd.DataFrame(data_np, columns=['nation','capital','GDP'])
df1
等长的列数据保存在一个字典里(JSON):很不幸,字典 key 是无序的
data_dict = {'nation': ['Japan', 'Korea', 'China'],
'capital': ['Tokyo', 'Seoul', 'Beijing'],
'GDP': [4900, 1300, 9100]}
df2 = pd.DataFrame(data_dict)
df2
从另一个 DataFrame 定义 DataFrame:啊,强迫症犯了
df21 = pd.DataFrame(df2, columns=['nation', 'capital', 'GDP'])
df21
df22 = pd.DataFrame(df2, columns=['nation', 'capital', 'GDP'], index = [2, 0, 1])
df22
从 DataFrame 中取出列?两种方法(与 JavaScript 完全一致!)
- '.'的写法容易与其他预留关键字产生冲突
- '[ ]'的写法最安全。
print(df22.nation)
print(df22.capital)
print(df22['GDP'])
df22['capital']
从 DataFrame 中取出行?(至少)两种方法
df22[0:1] # 给出的实际是DataFrame
df22.iloc[0] # 通过对应Index给出行
像 Numpy 切片一样的终极招式:iloc
df22.iloc[0,:]
df22.iloc[:,0]