Pandas 基础快速了解和查询

官方文档

Pandas 是 Python 的核心数据分析支持库, 基于 NumPy 创建, 它使 python 成为强大而高效的数据分析环境

一, 数据结构

pandas 的数据结构是基于 numpy 的, 因此其有着 numpy 的基因, 许多操作和大部分函数与 numpy 类似

pandas 的数据结构其实是 numpy 数组数据对象 array 的容器, 在 pandas 中有了索引结构, 可以利用索引来取 array 或 array 中的元素

pandas 中最重要的数据结构是 Series 和 DataFrame

1, 创建 Series 和 DataFrame

创建时若不指定索引, 将自动生成(从 0 开始)

Series 是一维, 只有行索引, 而 DataFrame 有行和列索引

创建方式灵活多变, 可以查看参数, 根据要求传参进行创建

import numpy as np  
import pandas as pd  

s = pd.Series(range(3))
s
0    0
1    1
2    2
dtype: int64
df = pd.DataFrame(range(3))  
print(df)
   0
0  0
1  1
2  2
s.values
array([0, 1, 2], dtype=int64)
df.values
array([[0],
       [1],
       [2]], dtype=int64)

可见,pandas 的数据结构,是 numpy 的 array 对象的容器,着意味着 pandas 在处理数据时,可以使用 numpy 的所有函数和方法

s = pd.Series(range(3), index=list('abc'))  
s
a    0
b    1
c    2
dtype: int64
df = pd.DataFrame({'A': range(3), 'B': list('jkl')}, index=list('abc')) 
print(df)
   A  B
a  0  j
b  1  k
c  2  l
dict_1 = {'a': 0, 'b': 1, 'c': 2}  
dict_2 = {'a': range(3), 'b': list('jkl')}  
s = pd.Series(dict_1)  
s
a    0
b    1
c    2
dtype: int64
df1 = pd.DataFrame(dict_1, index=['A'])  
print(df1)
   a  b  c
A  0  1  2
df2 = pd.DataFrame(dict_2)  
print(df2) 
   a  b
0  0  j
1  1  k
2  2  l
# df2 每一列是一个类型的 array 对象
df2["a"].values, df2["b"].values
(array([0, 1, 2], dtype=int64), array(['j', 'k', 'l'], dtype=object))

2, Series 和 DataFrame 的常用属性

大部分属性和 numpy 一样

s = pd.Series(1, index=list('abc'))  
s
a    1
b    1
c    1
dtype: int64
dict_3 = {'a': range(3), 'b': list('jkl')}  
df = pd.DataFrame(dict_3)  
print(df)  
   a  b
0  0  j
1  1  k
2  2  l
# 查看形状, 形状不包括 索引  
s.shape, df.shape  
((3,), (3, 2))
# 获取索引  
s.index, df.index, df.columns  
(Index(['a', 'b', 'c'], dtype='object'),
 RangeIndex(start=0, stop=3, step=1),
 Index(['a', 'b'], dtype='object'))
# 查看元素个数  
s.size, df.size  
(3, 6)
# 查看数据类型  
s.dtype, df.dtypes  
(dtype('int64'),
 a     int64
 b    object
 dtype: object)
# 查看值  
s.values, df.values, df['a'].values  
(array([1, 1, 1], dtype=int64),
 array([[0, 'j'],
        [1, 'k'],
        [2, 'l']], dtype=object),
 array([0, 1, 2], dtype=int64))

3, Series 和 DataFrame 结构理解

从上述可以看出, pandas 数据结构的值, 是一个 array 对象. 对于 df, 每一列的值取出来也是一个 array 对象, 并且每一列可以是不同的数据类型

需要注意的是, DataFrame 每一列取出来, 整体是一个 Series , 因此 DataFrame 又可以看成 Series 的容器

s = pd.Series(1, index=list('abc')) 
dict_3 = {'a': range(3), 'b': list('jkl')}  
df = pd.DataFrame(dict_3)  

type(s), type(df['a']), type(df)  
(pandas.core.series.Series,
 pandas.core.series.Series,
 pandas.core.frame.DataFrame)

Series 和 DataFrame 可以有多层索引

s.index = [['a', 'b', 'c'], [1, 2, 3]]
s
a  1    1
b  2    1
c  3    1
dtype: int64
df.index = [['a', 'b', 'c'], [1, 2, 3]]  
print(df)
     a  b
a 1  0  j
b 2  1  k
c 3  2  l

二, 数据结构操作, 处理与计算

1, 查看 Series 和 DataFrame 数据信息常用方法

a = np.random.randint(1, 9, (6, 2))  
s = pd.Series(a[:, 0])  
s
0    4
1    7
2    4
3    8
4    1
5    8
dtype: int32
df = pd.DataFrame(a)  
print(df) 
   0  1
0  4  4
1  7  4
2  4  8
3  8  3
4  1  3
5  8  1
# 查看前 5 行(默认)  
s.head()  
print(df.head())
   0  1
0  4  4
1  7  4
2  4  8
3  8  3
4  1  3
# 查看后 5 行(默认)  
s.tail()  
print(df.tail())  
   0  1
1  7  4
2  4  8
3  8  3
4  1  3
5  8  1
# 查看详情, Series 没有该方法  
df.info()  
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6 entries, 0 to 5
Data columns (total 2 columns):
 #   Column  Non-Null Count  Dtype
---  ------  --------------  -----
 0   0       6 non-null      int32
 1   1       6 non-null      int32
dtypes: int32(2)
memory usage: 176.0 bytes
# 查看统计量  
s.describe()  
print(df.describe())  
              0         1
count  6.000000  6.000000
mean   5.333333  3.833333
std    2.804758  2.316607
min    1.000000  1.000000
25%    4.000000  3.000000
50%    5.500000  3.500000
75%    7.750000  4.000000
max    8.000000  8.000000

2, 数据的直接计算

Series 和 DataFrame 的数据可以像 numpy 的数组一样直接进行计算, 索引相同的行、列进行计算, 索引不同的 NaN 填充

a = np.random.randint(1, 9, (6, 2))  
s = pd.Series(a[:, 0])  
df = pd.DataFrame(a)  

print(df)
   0  1
0  6  2
1  1  6
2  5  1
3  3  2
4  5  5
5  2  6
df1 = pd.DataFrame(a, columns=[1, 'b'])  
print(df1 * df)  
    0   1   b
0 NaN  12 NaN
1 NaN   6 NaN
2 NaN   5 NaN
3 NaN   6 NaN
4 NaN  25 NaN
5 NaN  12 NaN
s
0    6
1    1
2    5
3    3
4    5
5    2
dtype: int32
s1 = pd.Series(a[:, 0], index=['a', 1, 2, 3, 4, 5])  
s1
a    6
1    1
2    5
3    3
4    5
5    2
dtype: int32
s**2 + s1  
0     NaN
1     2.0
2    30.0
3    12.0
4    30.0
5     6.0
a     NaN
dtype: float64
# 笛卡儿积展开  
print(s + df)
    0  1   2   3   4   5
0  12  3 NaN NaN NaN NaN
1   7  7 NaN NaN NaN NaN
2  11  2 NaN NaN NaN NaN
3   9  3 NaN NaN NaN NaN
4  11  6 NaN NaN NaN NaN
5   8  7 NaN NaN NaN NaN

3, Series 和 DataFrame 下标和索引切片操作

3.01, Series 和 DataFrame 下标切片取值

Series 和 DataFrame 下标切片取值有许多不同之处

s1 = pd.Series(a[:, 0], index=['a', 1, 2, 3, 4, 5])  
s1
a    6
1    1
2    5
3    3
4    5
5    2
dtype: int32
a = np.random.randint(1, 9, (6, 2))  
df1 = pd.DataFrame(a, columns=[1, 'b'])  
print(df1)
   1  b
0  6  5
1  3  8
2  8  7
3  1  5
4  7  4
5  6  3
# 此方法 DataFrame 只能取行, 不能取列  
s1[1:3]
1    1
2    5
dtype: int32
print(df1[0:2])
   1  b
0  6  5
1  3  8
s1[[1, 4]]  
1    1
4    5
dtype: int32

同 numpy 一样, 可以条件取值, 此方法常用来筛选和重新赋值等

s1[s1>4]
a    6
2    5
4    5
dtype: int32
print(df1[df1>5])
     1    b
0  6.0  NaN
1  NaN  8.0
2  8.0  7.0
3  NaN  NaN
4  7.0  NaN
5  6.0  NaN
print(df1[df1 == 4])  
    1    b
0 NaN  NaN
1 NaN  NaN
2 NaN  NaN
3 NaN  NaN
4 NaN  4.0
5 NaN  NaN

3.02, Series 和 DataFrame 索引切片取值

索引切片取值, 左右都包含

s1 = pd.Series(a[:, 0], index=['a', 1, 2, 3, 4, 5])  
s1
a    6
1    3
2    8
3    1
4    7
5    6
dtype: int32
a = np.random.randint(1, 9, (6, 2))  
df1 = pd.DataFrame(a, columns=[1, 'b'])  
print(df1) 
   1  b
0  3  5
1  7  3
2  8  7
3  7  6
4  3  7
5  5  4
# 需要将索引转换类型  
s1.index = s1.index.astype(str)  
df1.index = df1.index.astype(str) 
s1['a':'2']
a    6
1    3
2    8
dtype: int32
print(df1['1':'3'])  
   1  b
1  7  3
2  8  7
3  7  6
print(df1['1':'3'][[1]])
   1
1  7
2  8
3  7
df1['b']
0    5
1    3
2    7
3    6
4    7
5    4
Name: b, dtype: int32
print(df1[['b', 1]])  
   b  1
0  5  3
1  3  7
2  7  8
3  6  7
4  7  3
5  4  5

3.03, 用 iloc 方法取值(推荐)

上述的取值太复杂麻烦, iloc 方法传入下标取值更方便且条理清晰. 存在多层索引时, iloc 按最内层索引取值

s1 = pd.Series(a[:, 0], index=['a', 1, 2, 3, 4, 5])  
s1
a    3
1    7
2    8
3    7
4    3
5    5
dtype: int32
a = np.random.randint(1, 9, (6, 2))  
df1 = pd.DataFrame(a, columns=[1, 'b'])  
print(df1) 
   1  b
0  8  8
1  6  2
2  1  6
3  6  3
4  8  3
5  3  8
# 右不包含  
s1.iloc[0:3]
a    3
1    7
2    8
dtype: int32
print(df1.iloc[0:5:2])
   1  b
0  8  8
2  1  6
4  8  3
print(df1.iloc[[1, 4, 2], 0:])  
   1  b
1  6  2
4  8  3
2  1  6

3.04, 用 loc 方法

loc 方法取值左右都包含, 传入索引标签取值

s1 = pd.Series(a[:, 0], index=['a', 1, 2, 3, 4, 5])  
s1
a    8
1    6
2    1
3    6
4    8
5    3
dtype: int32
a = np.random.randint(1, 9, (6, 2))  
df1 = pd.DataFrame(a, columns=[1, 'b'])  
print(df1) 
   1  b
0  4  3
1  6  4
2  1  6
3  6  2
4  6  1
5  2  7
# 需要将索引转换类型  
s1.index = s1.index.astype(str)  
df1.index = df1.index.astype(str) 
s1.loc['a':'2']
a    8
1    6
2    1
dtype: int32
df1.loc['1':'3', 'b']  
1    4
2    6
3    2
Name: b, dtype: int32

3.05, 利用切片修改数据

利用切片修改数据, 其实就是取值重新赋值

import numpy as np  
import pandas as pd  

df = pd.DataFrame(np.random.rand(5, 4),  
                  index=list('abcde'),  
                  columns=list('ABCD'))  
print(df[df>0.5])  
          A         B         C         D
a  0.908869       NaN       NaN  0.584259
b       NaN       NaN  0.940409       NaN
c  0.947715  0.898426  0.745999       NaN
d       NaN  0.855820       NaN  0.742919
e       NaN       NaN       NaN  0.593532
# 将大于 0.5 的数据换成 nan  
df[df>0.5] = np.nan  
print(df)  
          A         B         C         D
a       NaN  0.019952  0.004443       NaN
b  0.391594  0.406059       NaN  0.021655
c       NaN       NaN       NaN  0.067905
d  0.238486       NaN  0.232429       NaN
e  0.378054  0.422029  0.386046       NaN
# 将 A 列全部改成 1 , 增加一列 E, 值为 0  
df['A'] = 1 # 与 df.A = 1 等价  
df['E'] = 0  
print(df)  
   A         B         C         D  E
a  1  0.019952  0.004443       NaN  0
b  1  0.406059       NaN  0.021655  0
c  1       NaN       NaN  0.067905  0
d  1       NaN  0.232429       NaN  0
e  1  0.422029  0.386046       NaN  0
# 行列值互换  
df.loc[['a', 'c'], ['A', 'C']] = df.loc[['c', 'a'], ['C', 'A']].to_numpy()  
print(df)  
          A         B         C         D  E
a       NaN  0.019952  1.000000       NaN  0
b  1.000000  0.406059       NaN  0.021655  0
c  0.004443       NaN  1.000000  0.067905  0
d  1.000000       NaN  0.232429       NaN  0
e  1.000000  0.422029  0.386046       NaN  0
# 只要 B 不为 nan 的数据  
print(df[df['B'] == df['B']])  
     A         B         C         D  E
a  NaN  0.019952  1.000000       NaN  0
b  1.0  0.406059       NaN  0.021655  0
e  1.0  0.422029  0.386046       NaN  0

三, Series 和 DataFrame 的处理和计算函数

1, 索引

在 pandas 里, 索引非常重要, 一个行索引, 通常就是数据的一条记录(例如一个人的信息), 一个列索引就是数据的一个特征(例如某个人的性别, 年龄等), 通过索引能够更方便数据处理与计算

import numpy as np  
import pandas as pd  

s = pd.Series(np.random.rand(4), index=list('abcd'))  
s
a    0.930171
b    0.263544
c    0.684870
d    0.702820
dtype: float64
df = pd.DataFrame(np.random.rand(4, 4),  
                  index=list('abcd'),  
                  columns=list('ABCD'))  
print(df)  
          A         B         C         D
a  0.236401  0.972351  0.030862  0.438897
b  0.774498  0.670181  0.379171  0.941319
c  0.701424  0.732319  0.882208  0.527572
d  0.442419  0.597335  0.258880  0.420447

reindex 索引重排, 新增的索引 nan 填充, 缺少索引的数据舍弃

# 新增 e 舍弃 d, 有许多参数可以调节  
s1 = s.reindex(list('bcae'))
s1
b    0.263544
c    0.684870
a    0.930171
e         NaN
dtype: float64
df2 = df.reindex(columns=list('BCAE'))  
print(df2)
          B         C         A   E
a  0.972351  0.030862  0.236401 NaN
b  0.670181  0.379171  0.774498 NaN
c  0.732319  0.882208  0.701424 NaN
d  0.597335  0.258880  0.442419 NaN

sort_index 索引排序

# 默认 True 升序, 许多参数可调, DataFrame 只排行索引  
s2 = s.sort_index(ascending=False)
s2
d    0.702820
c    0.684870
b    0.263544
a    0.930171
dtype: float64
df2 = df.sort_index(ascending=False)  
print(df2)
          A         B         C         D
d  0.442419  0.597335  0.258880  0.420447
c  0.701424  0.732319  0.882208  0.527572
b  0.774498  0.670181  0.379171  0.941319
a  0.236401  0.972351  0.030862  0.438897

rename, set_index, reset_index 设置索引

# 注意参数及传参方式  
s3 = s.rename(index={'a': 'f'})
s3
f    0.930171
b    0.263544
c    0.684870
d    0.702820
dtype: float64
df3 = df.rename(lambda x: x + x)  
print(df3)
           A         B         C         D
aa  0.236401  0.972351  0.030862  0.438897
bb  0.774498  0.670181  0.379171  0.941319
cc  0.701424  0.732319  0.882208  0.527572
dd  0.442419  0.597335  0.258880  0.420447
# Series 没有此方法
df4 = df.set_index([['a','b','c','d'], [1, 2, 3, 4]])  
print(df4)
            A         B         C         D
a 1  0.236401  0.972351  0.030862  0.438897
b 2  0.774498  0.670181  0.379171  0.941319
c 3  0.701424  0.732319  0.882208  0.527572
d 4  0.442419  0.597335  0.258880  0.420447
# 可以将某列设为索引, 默认不保留原列, 可设参数 drop 保留  
df5 = df.set_index('A')  
print(df5)  
                 B         C         D
A                                     
0.236401  0.972351  0.030862  0.438897
0.774498  0.670181  0.379171  0.941319
0.701424  0.732319  0.882208  0.527572
0.442419  0.597335  0.258880  0.420447
# 将索引设为列(drop=True将其删除), 多层索引时可选某层  
df6 = df4.reset_index(level=1)
print(df6)
   level_1         A         B         C         D
a        1  0.236401  0.972351  0.030862  0.438897
b        2  0.774498  0.670181  0.379171  0.941319
c        3  0.701424  0.732319  0.882208  0.527572
d        4  0.442419  0.597335  0.258880  0.420447
df7 = df5.reset_index()  
print(df7)
          A         B         C         D
0  0.236401  0.972351  0.030862  0.438897
1  0.774498  0.670181  0.379171  0.941319
2  0.701424  0.732319  0.882208  0.527572
3  0.442419  0.597335  0.258880  0.420447
# 索引可以设置名字, 设置索引还可以通过获取索引重新赋值  
# DataFrame 还可以转置  
df5.index.name
'A'
df5.index = list('abcd') # 重设索引后, 索引名消失  
print(df5)
          B         C         D
a  0.972351  0.030862  0.438897
b  0.670181  0.379171  0.941319
c  0.732319  0.882208  0.527572
d  0.597335  0.258880  0.420447
print(df5.T)  
          a         b         c         d
B  0.972351  0.670181  0.732319  0.597335
C  0.030862  0.379171  0.882208  0.258880
D  0.438897  0.941319  0.527572  0.420447

多层索引

ar = [['a', 'b', 'c'], [1, 2, 3]]  
tup = list(zip(*ar))  
pd.MultiIndex.from_tuples(tup)  
MultiIndex([('a', 1),
            ('b', 2),
            ('c', 3)],
           )
index = pd.MultiIndex.from_product(ar)  
s = pd.Series(range(9), index=index)  
s  
a  1    0
   2    1
   3    2
b  1    3
   2    4
   3    5
c  1    6
   2    7
   3    8
dtype: int64
pd.MultiIndex.from_frame(pd.DataFrame(np.random.randint(1, 9, (2, 3))))  
MultiIndex([(6, 5, 3),
            (8, 1, 3)],
           names=[0, 1, 2])

2, 增删与合并数据

import numpy as np  
import pandas as pd  

df = pd.DataFrame(np.random.randint(1, 9, (4, 5)))  
print(df)
   0  1  2  3  4
0  4  8  5  3  7
1  7  3  5  2  4
2  3  2  5  7  2
3  1  2  4  8  7

insert 在指定位置前插入数据

# Series 没有该方法  
df.insert(2, 'A', 1)  
print(df)
   0  1  A  2  3  4
0  4  8  1  5  3  7
1  7  3  1  5  2  4
2  3  2  1  5  7  2
3  1  2  1  4  8  7

append 在数据最后增加数据

df1 = pd.DataFrame(np.random.rand(4, 4),  
                  index=list('abcd'),  
                  columns=list('ABCD'))  
print(df1)
          A         B         C         D
a  0.748362  0.049567  0.603201  0.383037
b  0.658722  0.225040  0.107199  0.416646
c  0.024967  0.161487  0.338823  0.889825
d  0.584625  0.582264  0.228898  0.817555
# Series 只能传 Series  
df.iloc[0].append(pd.Series(8))  
0    4
1    8
A    1
2    5
3    3
4    7
0    8
dtype: int64
# DataFrame 可以在行后面增加, 也可在列后面新增  
print(df.append([1]))
   0    1    A    2    3    4
0  4  8.0  1.0  5.0  3.0  7.0
1  7  3.0  1.0  5.0  2.0  4.0
2  3  2.0  1.0  5.0  7.0  2.0
3  1  2.0  1.0  4.0  8.0  7.0
0  1  NaN  NaN  NaN  NaN  NaN
print(df.append(df1, ignore_index=True)) 
     0    1         A    2    3    4         B         C         D
0  4.0  8.0  1.000000  5.0  3.0  7.0       NaN       NaN       NaN
1  7.0  3.0  1.000000  5.0  2.0  4.0       NaN       NaN       NaN
2  3.0  2.0  1.000000  5.0  7.0  2.0       NaN       NaN       NaN
3  1.0  2.0  1.000000  4.0  8.0  7.0       NaN       NaN       NaN
4  NaN  NaN  0.748362  NaN  NaN  NaN  0.049567  0.603201  0.383037
5  NaN  NaN  0.658722  NaN  NaN  NaN  0.225040  0.107199  0.416646
6  NaN  NaN  0.024967  NaN  NaN  NaN  0.161487  0.338823  0.889825
7  NaN  NaN  0.584625  NaN  NaN  NaN  0.582264  0.228898  0.817555

drop 删除指定数据

df['A'].drop(1), df.drop(1, axis=1)  
(0    1
 2    1
 3    1
 Name: A, dtype: int64,
    0  A  2  3  4
 0  4  1  5  3  7
 1  7  1  5  2  4
 2  3  1  5  7  2
 3  1  1  4  8  7)

concat 主要用于行索引的合并

print(df)
   0  1  A  2  3  4
0  4  8  1  5  3  7
1  7  3  1  5  2  4
2  3  2  1  5  7  2
3  1  2  1  4  8  7
print(df1)
          A         B         C         D
a  0.748362  0.049567  0.603201  0.383037
b  0.658722  0.225040  0.107199  0.416646
c  0.024967  0.161487  0.338823  0.889825
d  0.584625  0.582264  0.228898  0.817555
# 默认按列索引合并, 保留合并后的全部索引, 缺失用 nan 填充  
# join 参数可控制合并的方式: inner 只留下都有的索引  
print(pd.concat([df, df1]))
     0    1         A    2    3    4         B         C         D
0  4.0  8.0  1.000000  5.0  3.0  7.0       NaN       NaN       NaN
1  7.0  3.0  1.000000  5.0  2.0  4.0       NaN       NaN       NaN
2  3.0  2.0  1.000000  5.0  7.0  2.0       NaN       NaN       NaN
3  1.0  2.0  1.000000  4.0  8.0  7.0       NaN       NaN       NaN
a  NaN  NaN  0.748362  NaN  NaN  NaN  0.049567  0.603201  0.383037
b  NaN  NaN  0.658722  NaN  NaN  NaN  0.225040  0.107199  0.416646
c  NaN  NaN  0.024967  NaN  NaN  NaN  0.161487  0.338823  0.889825
d  NaN  NaN  0.584625  NaN  NaN  NaN  0.582264  0.228898  0.817555
df2 = pd.DataFrame(np.random.rand(5, 4),  
                  index=list('abcde'),  
                  columns=list('BCDE'))  
print(df2) 
          B         C         D         E
a  0.061604  0.505149  0.247496  0.474912
b  0.431163  0.828570  0.302236  0.695153
c  0.238852  0.998520  0.516351  0.665134
d  0.383425  0.684282  0.857654  0.621860
e  0.186235  0.006509  0.612608  0.875893
print(pd.concat([df1, df2], join='inner'))  
          B         C         D
a  0.049567  0.603201  0.383037
b  0.225040  0.107199  0.416646
c  0.161487  0.338823  0.889825
d  0.582264  0.228898  0.817555
a  0.061604  0.505149  0.247496
b  0.431163  0.828570  0.302236
c  0.238852  0.998520  0.516351
d  0.383425  0.684282  0.857654
e  0.186235  0.006509  0.612608

join 主要用于行索引的合并

# 默认以左边(df1)为基准, 相同列名需要加以区分  
# how 参数: outer 全保留, inner 只保留共同部分  
print(df1.join(df2, lsuffix='_1', rsuffix='_2'))
          A       B_1       C_1       D_1       B_2       C_2       D_2  \
a  0.748362  0.049567  0.603201  0.383037  0.061604  0.505149  0.247496   
b  0.658722  0.225040  0.107199  0.416646  0.431163  0.828570  0.302236   
c  0.024967  0.161487  0.338823  0.889825  0.238852  0.998520  0.516351   
d  0.584625  0.582264  0.228898  0.817555  0.383425  0.684282  0.857654   

          E  
a  0.474912  
b  0.695153  
c  0.665134  
d  0.621860  
print(df1.join(df2, how='outer', lsuffix='_1', rsuffix='_2'))  
          A       B_1       C_1       D_1       B_2       C_2       D_2  \
a  0.748362  0.049567  0.603201  0.383037  0.061604  0.505149  0.247496   
b  0.658722  0.225040  0.107199  0.416646  0.431163  0.828570  0.302236   
c  0.024967  0.161487  0.338823  0.889825  0.238852  0.998520  0.516351   
d  0.584625  0.582264  0.228898  0.817555  0.383425  0.684282  0.857654   
e       NaN       NaN       NaN       NaN  0.186235  0.006509  0.612608   

          E  
a  0.474912  
b  0.695153  
c  0.665134  
d  0.621860  
e  0.875893  

merge 合并

df1 = pd.DataFrame({'K': ['K0', 'K1', 'K2', 'K3'],
                    'A': ['A0', 'A1', 'M2', 'M3'],
                    'B': ['B0', 'B1', 'B2', 'B3']})
print(df1)
    K   A   B
0  K0  A0  B0
1  K1  A1  B1
2  K2  M2  B2
3  K3  M3  B3
df2 = pd.DataFrame({'K': ['K0', 'K1', 'K4', 'K5'],
                    'C': ['C0', 'C1', 'M2', 'M3'],
                    'D': ['D0', 'D1', 'D2', 'D3']})
print(df2)
    K   C   D
0  K0  C0  D0
1  K1  C1  D1
2  K4  M2  D2
3  K5  M3  D3
# 默认 inner, 全部列都保留,   
# 但只保留两者都有的列(K),且列内容相同(K0,K1)的 行, 行索引都舍弃  
print(pd.merge(df1, df2))
    K   A   B   C   D
0  K0  A0  B0  C0  D0
1  K1  A1  B1  C1  D1
# 可以选择以某一个为基准, 需要合并的列内容, 以及保留某一个的索引  
print(pd.merge(df1, df2, how='left')) # 以 df1 为准, 匹配不上的保留 df1  
    K   A   B    C    D
0  K0  A0  B0   C0   D0
1  K1  A1  B1   C1   D1
2  K2  M2  B2  NaN  NaN
3  K3  M3  B3  NaN  NaN
# df1 的 A 列与 df2 的 C 列有内容相同需要合并  
print(pd.merge(df1, df2, left_on='A', right_on='C')) 
  K_x   A   B K_y   C   D
0  K2  M2  B2  K4  M2  D2
1  K3  M3  B3  K5  M3  D3

3, 数据选择与处理

import numpy as np  
import pandas as pd  

np.random.seed(0)  
df = pd.DataFrame(np.random.randint(1, 9, (6, 6)),  
                  index=list('abcdef'),  
                  columns=list('ABCDEF'))  
print(df)
   A  B  C  D  E  F
a  5  8  6  1  4  4
b  4  8  2  4  6  3
c  5  8  7  1  1  5
d  3  2  7  8  8  7
e  1  2  6  2  6  1
f  2  5  4  1  4  6

sample 随机选择数据

# 可以指定数量, 也可以按比例选  
df.iloc[0].sample(2) # Series 也可  
E    4
B    8
Name: a, dtype: int32
print(df.sample(3))
   A  B  C  D  E  F
a  5  8  6  1  4  4
b  4  8  2  4  6  3
c  5  8  7  1  1  5
print(df.sample(frac=0.5, axis=1))  
   F  C  D
a  4  6  1
b  3  2  4
c  5  7  1
d  7  7  8
e  1  6  2
f  6  4  1

where 按条件选择数据, 且可替换, 替换的是条件之外的数据

df.A.where(df.A>3) # Series 也可  
a    5.0
b    4.0
c    5.0
d    NaN
e    NaN
f    NaN
Name: A, dtype: float64
df1 = df.where(df>1)  
print(df1)
     A  B  C    D    E    F
a  5.0  8  6  NaN  4.0  4.0
b  4.0  8  2  4.0  6.0  3.0
c  5.0  8  7  NaN  NaN  5.0
d  3.0  2  7  8.0  8.0  7.0
e  NaN  2  6  2.0  6.0  NaN
f  2.0  5  4  NaN  4.0  6.0
print(df.where(df==1, lambda x: x*x))  
    A   B   C   D   E   F
a  25  64  36   1  16  16
b  16  64   4  16  36   9
c  25  64  49   1   1  25
d   9   4  49  64  64  49
e   1   4  36   4  36   1
f   4  25  16   1  16  36

isin 生成布尔数组来选择数据

values = [3, 5, 7, 'a', 'c']  
df.C.isin(values)
a    False
b    False
c     True
d     True
e    False
f    False
Name: C, dtype: bool
df.A[df.C.isin(values)]  
c    5
d    3
Name: A, dtype: int32
print(df[df.isin(values)])
     A    B    C   D   E    F
a  5.0  NaN  NaN NaN NaN  NaN
b  NaN  NaN  NaN NaN NaN  3.0
c  5.0  NaN  7.0 NaN NaN  5.0
d  3.0  NaN  7.0 NaN NaN  7.0
e  NaN  NaN  NaN NaN NaN  NaN
f  NaN  5.0  NaN NaN NaN  NaN
print(df[df.index.isin(values)])  
   A  B  C  D  E  F
a  5  8  6  1  4  4
c  5  8  7  1  1  5

isna( isnull ) 和 notna ( notnull ) 生成布尔数组

# 可以 pd 调用, 也可 DataFrame 或 Series 调用  
pd.isna(df1.D)
a     True
b    False
c     True
d    False
e    False
f     True
Name: D, dtype: bool
df1.D.isnull()
a     True
b    False
c     True
d    False
e    False
f     True
Name: D, dtype: bool
print(df1.isna())  
       A      B      C      D      E      F
a  False  False  False   True  False  False
b  False  False  False  False  False  False
c  False  False  False   True   True  False
d  False  False  False  False  False  False
e   True  False  False  False  False   True
f  False  False  False   True  False  False

dropna 删除 nan, fillna 将 nan 填充

print(df1)
     A  B  C    D    E    F
a  5.0  8  6  NaN  4.0  4.0
b  4.0  8  2  4.0  6.0  3.0
c  5.0  8  7  NaN  NaN  5.0
d  3.0  2  7  8.0  8.0  7.0
e  NaN  2  6  2.0  6.0  NaN
f  2.0  5  4  NaN  4.0  6.0
# 默认有 nan 的行就删除, 参数 all: 全部 nan 才删除  
df1.A.dropna() # Series 也可  
a    5.0
b    4.0
c    5.0
d    3.0
f    2.0
Name: A, dtype: float64
print(df1.dropna())
     A  B  C    D    E    F
b  4.0  8  2  4.0  6.0  3.0
d  3.0  2  7  8.0  8.0  7.0
print(df1.dropna(axis=1, how='all'))  
     A  B  C    D    E    F
a  5.0  8  6  NaN  4.0  4.0
b  4.0  8  2  4.0  6.0  3.0
c  5.0  8  7  NaN  NaN  5.0
d  3.0  2  7  8.0  8.0  7.0
e  NaN  2  6  2.0  6.0  NaN
f  2.0  5  4  NaN  4.0  6.0
# 给定填充值, 默认全部填充,   
# 可以指定填充数, 填充方式  
df1.A.fillna(0) # Series 也可
a    5.0
b    4.0
c    5.0
d    3.0
e    0.0
f    2.0
Name: A, dtype: float64
print(df1.fillna(0))
     A  B  C    D    E    F
a  5.0  8  6  0.0  4.0  4.0
b  4.0  8  2  4.0  6.0  3.0
c  5.0  8  7  0.0  0.0  5.0
d  3.0  2  7  8.0  8.0  7.0
e  0.0  2  6  2.0  6.0  0.0
f  2.0  5  4  0.0  4.0  6.0
print(df1.fillna(0, limit=1)) # 每一列填充一个  
     A  B  C    D    E    F
a  5.0  8  6  0.0  4.0  4.0
b  4.0  8  2  4.0  6.0  3.0
c  5.0  8  7  NaN  0.0  5.0
d  3.0  2  7  8.0  8.0  7.0
e  0.0  2  6  2.0  6.0  0.0
f  2.0  5  4  NaN  4.0  6.0
# ffill 前面值填充, bfill 后面值填充  
print(df1.fillna(method='ffill'))
     A  B  C    D    E    F
a  5.0  8  6  NaN  4.0  4.0
b  4.0  8  2  4.0  6.0  3.0
c  5.0  8  7  4.0  6.0  5.0
d  3.0  2  7  8.0  8.0  7.0
e  3.0  2  6  2.0  6.0  7.0
f  2.0  5  4  2.0  4.0  6.0
print(df1.fillna(method='bfill'))  
     A  B  C    D    E    F
a  5.0  8  6  4.0  4.0  4.0
b  4.0  8  2  4.0  6.0  3.0
c  5.0  8  7  8.0  8.0  5.0
d  3.0  2  7  8.0  8.0  7.0
e  2.0  2  6  2.0  6.0  6.0
f  2.0  5  4  NaN  4.0  6.0

drop_duplicates 去重

df.iloc[0] = df.iloc[1]  
print(df)
   A  B  C  D  E  F
a  4  8  2  4  6  3
b  4  8  2  4  6  3
c  5  8  7  1  1  5
d  3  2  7  8  8  7
e  1  2  6  2  6  1
f  2  5  4  1  4  6
# 默认保留第 1 条数据  
df.A.drop_duplicates() # Series 也可 
a    4
c    5
d    3
e    1
f    2
Name: A, dtype: int32
print(df.drop_duplicates())  
   A  B  C  D  E  F
a  4  8  2  4  6  3
c  5  8  7  1  1  5
d  3  2  7  8  8  7
e  1  2  6  2  6  1
f  2  5  4  1  4  6

nlargest 选择某列(某几列)值最大的几条数据, 对应还有 nsmallest

print(df.nlargest(3, 'A'))
   A  B  C  D  E  F
c  5  8  7  1  1  5
a  4  8  2  4  6  3
b  4  8  2  4  6  3
print(df.nsmallest(3, 'A'))
   A  B  C  D  E  F
e  1  2  6  2  6  1
f  2  5  4  1  4  6
d  3  2  7  8  8  7
print(df.nlargest(3, ['C', 'D']))  
   A  B  C  D  E  F
d  3  2  7  8  8  7
c  5  8  7  1  1  5
e  1  2  6  2  6  1

filter 按索引查找数据, 可正则模糊查找

print(df.filter(['A', 'B']))
   A  B
a  4  8
b  4  8
c  5  8
d  3  2
e  1  2
f  2  5
print(df.filter(like='a', axis=0))
   A  B  C  D  E  F
a  4  8  2  4  6  3
print(df.filter(regex='c', axis=0))  
   A  B  C  D  E  F
c  5  8  7  1  1  5

assign 用于新增辅助列

print(df.assign(A1=df['A']/df['F']))
   A  B  C  D  E  F        A1
a  4  8  2  4  6  3  1.333333
b  4  8  2  4  6  3  1.333333
c  5  8  7  1  1  5  1.000000
d  3  2  7  8  8  7  0.428571
e  1  2  6  2  6  1  1.000000
f  2  5  4  1  4  6  0.333333
print(df.assign(A1=lambda x:x.A/x.F))  
   A  B  C  D  E  F        A1
a  4  8  2  4  6  3  1.333333
b  4  8  2  4  6  3  1.333333
c  5  8  7  1  1  5  1.000000
d  3  2  7  8  8  7  0.428571
e  1  2  6  2  6  1  1.000000
f  2  5  4  1  4  6  0.333333

clip 将过大或过小的数据去掉, 并填充指定值

# 小于指定值的填充为指定值小者, 大于的反之  
print(df.clip(2, 6))
   A  B  C  D  E  F
a  4  6  2  4  6  3
b  4  6  2  4  6  3
c  5  6  6  2  2  5
d  3  2  6  6  6  6
e  2  2  6  2  6  2
f  2  5  4  2  4  6
print(df.clip(df.A, df.A + 2, axis=0))  
   A  B  C  D  E  F
a  4  6  4  4  6  4
b  4  6  4  4  6  4
c  5  7  7  5  5  5
d  3  3  5  5  5  5
e  1  2  3  2  3  1
f  2  4  4  2  4  4

4, 数据分组聚合计算

聚合计算和 numpy 函数基本一样, 例如 sum, count, median, min, max, mean, var, std 等, 比较容易

更为重要的, 是将数据按需分组后再聚合运算

import numpy as np  
import pandas as pd  

np.random.seed(0)  
df = pd.DataFrame(np.random.randint(1, 9, (6, 6)),  
                  index=list('abcdef'),  
                  columns=list('ABCDEF'))  

df.A.where(df.A>3, 'M', inplace=True)  
df.A.where(df.A=='M', 'N', inplace=True)  
df.B.where(df.B>3, 'J', inplace=True)  
df.B.where(df.B=='J', 'K', inplace=True)  
df.C.where(df.C<5, np.nan, inplace=True)  
print(df)  
   A  B    C  D  E  F
a  N  K  NaN  1  4  4
b  N  K  2.0  4  6  3
c  N  K  NaN  1  1  5
d  M  J  NaN  8  8  7
e  M  J  NaN  2  6  1
f  M  K  4.0  1  4  6
# 默认按列加和, 将 nan 转换为 0 来计算  
df.sum()
A    NNNMMM
B    KKKJJK
C       6.0
D        17
E        29
F        26
dtype: object
df.sum(axis=1, numeric_only=True)  
a     9.0
b    15.0
c     7.0
d    23.0
e     9.0
f    15.0
dtype: float64
# 按行统计忽略 nan  
df.count(axis=1)
a    5
b    6
c    5
d    5
e    5
f    6
dtype: int64
print(df.set_index(["A", "B"]).groupby(level="A").count())  
   C  D  E  F
A            
M  1  3  3  3
N  1  3  3  3
print(df.set_index(["A", "B"]).groupby(level="B").count())  
   C  D  E  F
B            
J  0  2  2  2
K  2  4  4  4

value_counts 统计 Series 中每个值出现次数

# Series 的值统计, 也即是 DataFrame 的每一列中每个值的数量统计  
df.A.value_counts()
N    3
M    3
Name: A, dtype: int64
df.C.value_counts()  
2.0    1
4.0    1
Name: C, dtype: int64
# 可以统计索引, 可按百分比显示, 可以分组统计  
df.set_index('A').index.value_counts(normalize=True)
N    0.5
M    0.5
Name: A, dtype: float64
df.D.value_counts(bins=2)  
(0.992, 4.5]    5
(4.5, 8.0]      1
Name: D, dtype: int64

nunique 去重计数, 统计每一行或列不同值的数量

df.nunique()   
A    2
B    2
C    2
D    4
E    4
F    6
dtype: int64

quantile 计算分位数

print(df.quantile([0.3, 0.6]))
       C    D    E    F
0.3  2.6  1.0  4.0  3.5
0.6  3.2  2.0  6.0  5.0

cut 与 qcut 数据分箱

# 将某一列中的值分别分到一个范围中, 默认左不包含右包含  
# 这对分组非常有用, 例如年龄分段  
c = pd.cut(df.D, bins=[0, 3, 8], labels=['0到3', '3到8'])  
c  
a    0到3
b    3到8
c    0到3
d    3到8
e    0到3
f    0到3
Name: D, dtype: category
Categories (2, object): ['0到3' < '3到8']
# 根据数值的频率来选择间隔, 使每个分段里值的个数相同  
pd.qcut(df.D, q=2)
a    (0.999, 1.5]
b      (1.5, 8.0]
c    (0.999, 1.5]
d      (1.5, 8.0]
e      (1.5, 8.0]
f    (0.999, 1.5]
Name: D, dtype: category
Categories (2, interval[float64, right]): [(0.999, 1.5] < (1.5, 8.0]]
pd.qcut(df.D, q=2).value_counts()  
(0.999, 1.5]    3
(1.5, 8.0]      3
Name: D, dtype: int64

rank 用来给数据排名, 例如销售额, 成绩等

# 有多种排名方式可供选择, 举一例: 给 D 列排名  
df['排名'] = df.D.rank(method='dense', ascending=False)  
print(df) 
   A  B    C  D  E  F   排名
a  N  K  NaN  1  4  4  4.0
b  N  K  2.0  4  6  3  2.0
c  N  K  NaN  1  1  5  4.0
d  M  J  NaN  8  8  7  1.0
e  M  J  NaN  2  6  1  3.0
f  M  K  4.0  1  4  6  4.0

sort_values 数据排序

df.sort_values('排名', inplace=True)  
print(df)  
   A  B    C  D  E  F   排名
d  M  J  NaN  8  8  7  1.0
b  N  K  2.0  4  6  3  2.0
e  M  J  NaN  2  6  1  3.0
a  N  K  NaN  1  4  4  4.0
c  N  K  NaN  1  1  5  4.0
f  M  K  4.0  1  4  6  4.0

shift 数据移动, 索引不变

print(df.shift(2))
     A    B    C    D    E    F   排名
d  NaN  NaN  NaN  NaN  NaN  NaN  NaN
b  NaN  NaN  NaN  NaN  NaN  NaN  NaN
e    M    J  NaN  8.0  8.0  7.0  1.0
a    N    K  2.0  4.0  6.0  3.0  2.0
c    M    J  NaN  2.0  6.0  1.0  3.0
f    N    K  NaN  1.0  4.0  4.0  4.0
print(df.shift(-1, axis=1))  
   A    B  C  D  E    F  排名
d  J  NaN  8  8  7  1.0 NaN
b  K  2.0  4  6  3  2.0 NaN
e  J  NaN  2  6  1  3.0 NaN
a  K  NaN  1  4  4  4.0 NaN
c  K  NaN  1  1  5  4.0 NaN
f  K  4.0  1  4  6  4.0 NaN

agg 和 apply 传入函数进行高级聚合运算, 已存在的函数用字符串形式传入, 自定义函数传入函数名

df.agg('sum')
A     MNMNNM
B     JKJKKK
C        6.0
D         17
E         29
F         26
排名      18.0
dtype: object
print(df.agg(['max', 'min']))
     A  B    C  D  E  F   排名
max  N  K  4.0  8  8  7  4.0
min  M  J  2.0  1  1  1  1.0
print(df.apply(['max', 'min']))  
     A  B    C  D  E  F   排名
max  N  K  4.0  8  8  7  4.0
min  M  J  2.0  1  1  1  1.0

🔺🔺 groupby 按指定的列(行)中不同值分组, 与前面的聚合函数组合出无限的变化, 满足各种需求

# 分组后是一个迭代器, 可以查看分组, 获取分组  
df.groupby('A')
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000021E8A8295B0>
df.groupby('A').groups 
{'M': ['d', 'e', 'f'], 'N': ['b', 'a', 'c']}
print(df.groupby('A').get_group('M'))  
   A  B    C  D  E  F   排名
d  M  J  NaN  8  8  7  1.0
e  M  J  NaN  2  6  1  3.0
f  M  K  4.0  1  4  6  4.0
# 分别取出 M 和 N 中 F 列任意排名的数据  
def get_second(x, m, n):  
    return x[x[m].rank(method='dense', ascending=False)==n]  

# 通过修改 n 参数取出任意排名  
print(df.groupby('A').apply(get_second, m='F', n=3.0))  
     A  B    C  D  E  F   排名
A                           
M e  M  J  NaN  2  6  1  3.0
N b  N  K  2.0  4  6  3  2.0
# 将上述 cut 分箱得到的数据用来分组统计  
print(df.groupby(c).count())  
     A  B  C  D  E  F  排名
D                        
0到3  4  4  1  4  4  4   4
3到8  2  2  1  2  2  2   2
# 对不同的列作不同的分组聚合运算  
print(df.groupby('A').agg({'E': ['mean', 'max'], 'F': 'sum'})) 
          E       F
       mean max sum
A                  
M  6.000000   8  14
N  3.666667   6  12

5, 数据透视与窗口函数

import numpy as np  
import pandas as pd  

np.random.seed(0)  
df = pd.DataFrame(np.random.randint(1, 20, (4, 5)))  
df.columns = list('ABCDE')  
print(df)  
    A   B   C  D   E
0  13  16   1  4   4
1   8  10  19  5   7
2  13   2   7  8  15
3  18   6  14  9  10

melt 将列索引展开成数据

# 默认全部展开  
df1 = pd.melt(df, id_vars=['A', 'B'], var_name='F', value_name='G')  
print(df1)
     A   B  F   G
0   13  16  C   1
1    8  10  C  19
2   13   2  C   7
3   18   6  C  14
4   13  16  D   4
5    8  10  D   5
6   13   2  D   8
7   18   6  D   9
8   13  16  E   4
9    8  10  E   7
10  13   2  E  15
11  18   6  E  10
print(pd.melt(df, id_vars=['A', 'B'], value_vars=['C']))  
    A   B variable  value
0  13  16        C      1
1   8  10        C     19
2  13   2        C      7
3  18   6        C     14

pivot 将行值展开成为列索引

print(df1.pivot(columns='F', values=['A', 'B'])) 
       A                 B            
F      C     D     E     C     D     E
0   13.0   NaN   NaN  16.0   NaN   NaN
1    8.0   NaN   NaN  10.0   NaN   NaN
2   13.0   NaN   NaN   2.0   NaN   NaN
3   18.0   NaN   NaN   6.0   NaN   NaN
4    NaN  13.0   NaN   NaN  16.0   NaN
5    NaN   8.0   NaN   NaN  10.0   NaN
6    NaN  13.0   NaN   NaN   2.0   NaN
7    NaN  18.0   NaN   NaN   6.0   NaN
8    NaN   NaN  13.0   NaN   NaN  16.0
9    NaN   NaN   8.0   NaN   NaN  10.0
10   NaN   NaN  13.0   NaN   NaN   2.0
11   NaN   NaN  18.0   NaN   NaN   6.0

pivot_table 与 groupby + 聚合函数 类似, 可以对表格进行各种需求的透视

df1.index = list('LMNLMNLMNLMN')  
df1.reset_index(inplace=True)  
df1.rename(columns={'index': 'Q'}, inplace=True)  
print(df1)
    Q   A   B  F   G
0   L  13  16  C   1
1   M   8  10  C  19
2   N  13   2  C   7
3   L  18   6  C  14
4   M  13  16  D   4
5   N   8  10  D   5
6   L  13   2  D   8
7   M  18   6  D   9
8   N  13  16  E   4
9   L   8  10  E   7
10  M  13   2  E  15
11  N  18   6  E  10
print(df1.pivot_table(index=['Q', 'F'], aggfunc='mean'))  
        A   B     G
Q F                
L C  15.5  11   7.5
  D  13.0   2   8.0
  E   8.0  10   7.0
M C   8.0  10  19.0
  D  15.5  11   6.5
  E  13.0   2  15.0
N C  13.0   2   7.0
  D   8.0  10   5.0
  E  15.5  11   7.0
print(df1.pivot_table(index='Q',  
                columns='F',  
                values='A',  
                aggfunc=['mean', 'sum']))  
   mean             sum        
F     C     D     E   C   D   E
Q                              
L  15.5  13.0   8.0  31  13   8
M   8.0  15.5  13.0   8  31  13
N  13.0   8.0  15.5  13   8  31

rolling 将数据依次移动指定尺寸的窗口并进行聚合运算

df1.rolling(3)  
Rolling [window=3,center=False,axis=0,method=single]
print(df1)
    Q   A   B  F   G
0   L  13  16  C   1
1   M   8  10  C  19
2   N  13   2  C   7
3   L  18   6  C  14
4   M  13  16  D   4
5   N   8  10  D   5
6   L  13   2  D   8
7   M  18   6  D   9
8   N  13  16  E   4
9   L   8  10  E   7
10  M  13   2  E  15
11  N  18   6  E  10
# 移动 3 条数据加和一次作为一条新数据,  
# 前面默认 nan 填充  
print(df1.rolling(3).sum())  
       A     B     G
0    NaN   NaN   NaN
1    NaN   NaN   NaN
2   34.0  28.0  27.0
3   39.0  18.0  40.0
4   44.0  24.0  25.0
5   39.0  32.0  23.0
6   34.0  28.0  17.0
7   39.0  18.0  22.0
8   44.0  24.0  21.0
9   39.0  32.0  20.0
10  34.0  28.0  26.0
11  39.0  18.0  32.0
# 可以设置最小观察值(必须小于移动尺寸)  
# 可以用高级函数聚合运算  
print(df1.rolling(len(df1), min_periods=1).sum())
        A      B      G
0    13.0   16.0    1.0
1    21.0   26.0   20.0
2    34.0   28.0   27.0
3    52.0   34.0   41.0
4    65.0   50.0   45.0
5    73.0   60.0   50.0
6    86.0   62.0   58.0
7   104.0   68.0   67.0
8   117.0   84.0   71.0
9   125.0   94.0   78.0
10  138.0   96.0   93.0
11  156.0  102.0  103.0
print(df1.rolling(2).agg(['sum', np.max]))  
       A           B           G      
     sum  amax   sum  amax   sum  amax
0    NaN   NaN   NaN   NaN   NaN   NaN
1   21.0  13.0  26.0  16.0  20.0  19.0
2   21.0  13.0  12.0  10.0  26.0  19.0
3   31.0  18.0   8.0   6.0  21.0  14.0
4   31.0  18.0  22.0  16.0  18.0  14.0
5   21.0  13.0  26.0  16.0   9.0   5.0
6   21.0  13.0  12.0  10.0  13.0   8.0
7   31.0  18.0   8.0   6.0  17.0   9.0
8   31.0  18.0  22.0  16.0  13.0   9.0
9   21.0  13.0  26.0  16.0  11.0   7.0
10  21.0  13.0  12.0  10.0  22.0  15.0
11  31.0  18.0   8.0   6.0  25.0  15.0
def f(x):  
    return x.iloc[0] * x.iloc[1]  

print(df1[['A', 'G']])
     A   G
0   13   1
1    8  19
2   13   7
3   18  14
4   13   4
5    8   5
6   13   8
7   18   9
8   13   4
9    8   7
10  13  15
11  18  10
print(df1.rolling(2)['A', 'G'].apply(f))  
        A      G
0     NaN    NaN
1   104.0   19.0
2   104.0  133.0
3   234.0   98.0
4   234.0   56.0
5   104.0   20.0
6   104.0   40.0
7   234.0   72.0
8   234.0   36.0
9   104.0   28.0
10  104.0  105.0
11  234.0  150.0

6, 文本字符串处理

文本字符串处理方法基本上和 python 内建字符串方法同名, 这些方法自动忽略 nan 进行处理

方法较多, 常用的举几个例子:

s = pd.Series(['A_1', 'B_2', 'C_3', np.nan],  
              index=['A_a', 'B_b', 'C_c', 'D'])  
s  
A_a    A_1
B_b    B_2
C_c    C_3
D      NaN
dtype: object
# 取值  
s.str[0]
A_a      A
B_b      B
C_c      C
D      NaN
dtype: object
s.str[:2]
A_a     A_
B_b     B_
C_c     C_
D      NaN
dtype: object
s.index.str[2]  
Index(['a', 'b', 'c', nan], dtype='object')
# 拆分  
s.str.split('_')
A_a    [A, 1]
B_b    [B, 2]
C_c    [C, 3]
D         NaN
dtype: object
s.str.split('_').str.get(0)
A_a      A
B_b      B
C_c      C
D      NaN
dtype: object
s.str.split('_').str[1]  
A_a      1
B_b      2
C_c      3
D      NaN
dtype: object
s
A_a    A_1
B_b    B_2
C_c    C_3
D      NaN
dtype: object
print(s.str.split('_', expand=True))  
       0    1
A_a    A    1
B_b    B    2
C_c    C    3
D    NaN  NaN
# 替换, 默认正则匹配, 可传入函数高级匹配  
s.str.replace('_', '')
A_a     A1
B_b     B2
C_c     C3
D      NaN
dtype: object
s.index.str.replace('_', '')  
Index(['Aa', 'Bb', 'Cc', 'D'], dtype='object')
# 拼接  
s1 = s.str.split('_').str[0]  
s1
A_a      A
B_b      B
C_c      C
D      NaN
dtype: object
s1.str.cat() 
'ABC'
s1.str.cat(sep='_')
'A_B_C'
s1.str.cat(sep='_', na_rep='_')  
'A_B_C__'
s1.str.cat(['1', '2', '3', '4'], na_rep='_')  
A_a    A1
B_b    B2
C_c    C3
D      _4
dtype: object
# 提取  
s
A_a    A_1
B_b    B_2
C_c    C_3
D      NaN
dtype: object
print(s.str.extract(r'([ABC])_(\d)'))  
       0    1
A_a    A    1
B_b    B    2
C_c    C    3
D    NaN  NaN

三, 时间序列

时间序列对数据分析很重要, 很多数据都和时间发生的先后顺序相关

date_range 生成时间序列

import numpy as np  
import pandas as pd  

pd.date_range(start='20200701', end='20200705')  
DatetimeIndex(['2020-07-01', '2020-07-02', '2020-07-03', '2020-07-04',
               '2020-07-05'],
              dtype='datetime64[ns]', freq='D')
# 可以指定生成个数与频率等  
pd.date_range(start='6/1/2020', periods=5, freq='10D')  
DatetimeIndex(['2020-06-01', '2020-06-11', '2020-06-21', '2020-07-01',
               '2020-07-11'],
              dtype='datetime64[ns]', freq='10D')

to_datetime 转换时间格式

1970年 1 月 1 日 00:00:00 UTC+00:00 时区的时刻称为 epoch time,记为 0,当前时间就是相对于 epoch time 的秒数

# 获取本地当前时间  
from datetime import datetime  
print(datetime.now())  
d = datetime.now().timestamp()  
print(datetime.fromtimestamp(d))  
d  
2022-08-20 19:48:43.236534
2022-08-20 19:48:43.237531





1660996123.237531
# 数字形式的时间, 用 to_datetime 转换为时间格式后与上述有差别,  
# 是由于时区的原因, 转换时区即可一样  
print(pd.to_datetime(d, utc=True, unit='s'))  
d = pd.Series(d)  
pd.to_datetime(d, utc=True, unit='s').dt.tz_convert('Asia/Shanghai')  
2022-08-20 11:48:43.237530880+00:00





0   2022-08-20 19:48:43.237530880+08:00
dtype: datetime64[ns, Asia/Shanghai]
# 各种日期格式的转换  
print(pd.to_datetime(['07-17-2020', '11-07-2020'], dayfirst=True))  
print(pd.to_datetime('2020年7月17日', format='%Y年%m月%d日'))  
pd.to_datetime(['jul 17, 2020',  
                '2020-07-17',  
                '20200717',  
                '2020/07/17',  
                '2020.07.17',   
                np.nan])  
DatetimeIndex(['2020-07-17', '2020-07-11'], dtype='datetime64[ns]', freq=None)
2020-07-17 00:00:00





DatetimeIndex(['2020-07-17', '2020-07-17', '2020-07-17', '2020-07-17',
               '2020-07-17', 'NaT'],
              dtype='datetime64[ns]', freq=None)
# 可以跳过非时间, 可以转换 DataFrame 但索引名是固定的名称  
print(pd.to_datetime(['2020.07.17', '日期'], errors='coerce'))  
df = pd.DataFrame({'year': [2019, 2020],  
              'month': [6, 7],  
              'day': [4, 5]})  
pd.to_datetime(df)  
DatetimeIndex(['2020-07-17', 'NaT'], dtype='datetime64[ns]', freq=None)





0   2019-06-04
1   2020-07-05
dtype: datetime64[ns]
df = pd.DataFrame(np.random.randint(0, 10, (5, 2)),  
                  index=pd.date_range('20180717', periods=5, freq='200D'))  
print(df)
            0  1
2018-07-17  4  3
2019-02-02  0  3
2019-08-21  5  0
2020-03-08  2  3
2020-09-24  8  1

时间索引取值, between_time 取时间段

print(df['2018':'2019'])
            0  1
2018-07-17  4  3
2019-02-02  0  3
2019-08-21  5  0
print(df['2019-01':'2020-01'])  
            0  1
2019-02-02  0  3
2019-08-21  5  0
df.index = pd.date_range('20200717', periods=5, freq='2H') 
print(df)
                     0  1
2020-07-17 00:00:00  4  3
2020-07-17 02:00:00  0  3
2020-07-17 04:00:00  5  0
2020-07-17 06:00:00  2  3
2020-07-17 08:00:00  8  1
print(df.between_time('3:00', '7:00')) 
                     0  1
2020-07-17 04:00:00  5  0
2020-07-17 06:00:00  2  3

时间序列作为数据的操作

df.index = pd.date_range('20180717', periods=5, freq='100D')  
df.index.name = '日期'  
df.reset_index(inplace=True)  
print(df)
          日期  0  1
0 2018-07-17  4  3
1 2018-10-25  0  3
2 2019-02-02  5  0
3 2019-05-13  2  3
4 2019-08-21  8  1
df.日期.dt.day  
0    17
1    25
2     2
3    13
4    21
Name: 日期, dtype: int64
df['月份'] = df['日期'].dt.month  
print(df)
          日期  0  1  月份
0 2018-07-17  4  3   7
1 2018-10-25  0  3  10
2 2019-02-02  5  0   2
3 2019-05-13  2  3   5
4 2019-08-21  8  1   8
print(df[df.日期.dt.month >= 5])
          日期  0  1  月份
0 2018-07-17  4  3   7
1 2018-10-25  0  3  10
3 2019-05-13  2  3   5
4 2019-08-21  8  1   8
print(df[df.月份 >= 5])
          日期  0  1  月份
0 2018-07-17  4  3   7
1 2018-10-25  0  3  10
3 2019-05-13  2  3   5
4 2019-08-21  8  1   8
d = df.日期.astype(str).str.split('-', expand=True)  
print(d)
      0   1   2
0  2018  07  17
1  2018  10  25
2  2019  02  02
3  2019  05  13
4  2019  08  21
print(df[d[0] =='2018'])  
          日期  0  1  月份
0 2018-07-17  4  3   7
1 2018-10-25  0  3  10

四, 数据的导入导出与可视化

1, pandas 可以导入导出多种格式的数据:

read_csv, to_csv
read_json, to_json
read_html, to_html
read_excel, to_excel
read_hdf, to_hdf
等等

# 默认读取第一个 sheet, 默认第一行为列索引  
df = pd.read_excel(r'./sheet.xlsx',  
                   sheet_name=0, header=0)  
print(df)  
   名次  战队名         说明
0   1  FPX      四包二战术
1   2   G2      个人能力强
2   3   IG       喜欢打架
3   4  SKT  Faker状态低迷
4   5  GRF      上单是短板
5   6  DWG        下路弱
6   7  FNC       欧洲强队
7   8  SPY        AD强
8   9  RNG        四保一
9  10   TL       北美强队
# 可以设置将某列作为行索引, 某列作为列索引  
df1 = pd.read_excel(r'./sheet.xlsx',  
                   sheet_name=1)  

print(df1)
   名次        上单
0   1   GIMGOOM
1   2    WUNDER
2   3      KHAN
3   4   FLANDER
4   5    THESHY
5   6    NUGURI
6   7     BWIPO
7   8   IPMPACT
8   9  LICORICE
9  10      HUNI
df2 = pd.read_excel(r'./sheet.xlsx',  
                   sheet_name=1,  
                   header=1,  
                   index_col=0)  
print(df2)
     GIMGOOM
1           
2     WUNDER
3       KHAN
4    FLANDER
5     THESHY
6     NUGURI
7      BWIPO
8    IPMPACT
9   LICORICE
10      HUNI
# 有时需要根据文件调节编码和引擎参数  
df = pd.read_csv(r'./ratings_chinses.csv',  
                 engine=None,  
                 encoding='gbk')  
print(df)  
      数量   收获  评分
0      1    1   4
1      2    3   4
2      3    6   4
3      4   47   5
4      5   50   5
..   ...  ...  ..
105  106   47   5
106  107   50   3
107  108   70   5
108  109  101   4
109  110  110   5

[110 rows x 3 columns]

2, 可视化

import matplotlib.pyplot as plt  

plt.rcParams['font.family'] = 'Microsoft YaHei'   
plt.rcParams['font.size'] = 12  

df.收获.plot()   

png

df['评分'].plot(kind='hist')   

png

df.plot(x='数量', y='评分')   

png

df.评分.plot.box()  

png

jupyter附件