288 Pandas 读取 URL 路径的文件

数据输入路径,可以是文件路径,也可以是 URL,或者实现 read 方法的任意对象。

如下经典的数据集 iris,直接通过 URL 获取。

In [160]: pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data')
Out[160]:5.1  3.5  1.4  0.2     Iris-setosa
0    4.9  3.0  1.4  0.2     Iris-setosa
1    4.7  3.2  1.3  0.2     Iris-setosa
2    4.6  3.1  1.5  0.2     Iris-setosa
3    5.0  3.6  1.4  0.2     Iris-setosa
4    5.4  3.9  1.7  0.4     Iris-setosa
..   ...  ...  ...  ...             ...
144  6.7  3.0  5.2  2.3  Iris-virginica
145  6.3  2.5  5.0  1.9  Iris-virginica
146  6.5  3.0  5.2  2.0  Iris-virginica
147  6.2  3.4  5.4  2.3  Iris-virginica
148  5.9  3.0  5.1  1.8  Iris-virginica[149 rows x 5 columns]

289 Pandas 读取文件之 sep 分隔符

默认为逗号,注意:如果分割字符长度大于1,且不是 \s+, 启动 Python 引擎解析。

举例:test.csv 文件分割符为 \t, 如果使用 sep 默认的逗号分隔符,读入后的数据混为一体。

# 创建并保存数据
In [1]: d = {'id':[1,2],'name':['gz','lh'],'age':[10,12]}
In [2]: df = pd.DataFrame(d)
In [3]: df.to_csv('test.csv',sep='\t')#读取数据
In [4]: df = pd.read_csv('test.csv')
In [5]: df
Out[5]:\tid\tname\tage
0    0\t1\tgz\t10
1    1\t2\tlh\t12

sep 必须设置为 '\t',数据分割才会正常。

In [6]: df = pd.read_csv('test.csv',sep='\t')
In [6]: df
Out[6]:Unnamed: 0  id name  age
0           0   1   gz   10
1           1   2   lh   12

290 Pandas 读取之列选择属性

参数用于选取数据文件的哪些列到 DataFrame 中,如下所示,只想使用源数据文件的 id 和 age 两列,那么可以为 usecols 参数赋值为 ['id','name']:

In [1]: df = pd.read_csv('test.csv',delim_whitespace=True,usecols=['id','name'])In [2]: df
Out[2]:id name
0   1   gz
1   2   lh

291 Pandas 读取之空值处理

参数可以配置哪些值需要处理成Na/NaN, 类型为字典,键指明哪一列,值为看做 Na/NaN 的字符。

假设我们的数据文件如下,date 列中有一个 # 值,我们想把它处理成 NaN 值。

In [1]: d = {'id':[1,2],'name':['gz','lh'],'age':[10,12],'date':['2020-03-10','#']}
In [2]: df = pd.DataFrame(d)
In [3]: df.to_csv('test_date.csv',sep=' ',index=False)In [4]: df = pd.read_csv('test_date.csv',sep='\s+')

可以使用,na_values 实现:

In [37]:  df = pd.read_csv('test_date.csv',sep='\s+',na_values=['#'])In [38]: df
Out[38]:id name  age        date
0   1   gz   10  2020-03-10
1   2   lh   12         NaN

keepdefaultna 是和 navalues 搭配的,如果前者为 True,则 navalues 被解析为 Na/NaN 的字符除了用户设置外,还包括默认值。

292 Pandas 之分块读入数据

iterator 取值 boolean, 默认为 False, 返回一个 TextFileReader 对象,以便逐块处理文件。

这个在文件很大时,内存无法容纳所有数据文件,此时分批读入,依次处理。

具体操作演示如下,我们的文件数据域一共有 2 行。

先读入一行,get_chunk 设置为 1 表示一次读入一行

In [64]: chunk = pd.read_csv('test.csv',sep='\s+',iterator=True)In [65]: chunk.get_chunk(1)
Out[65]:id name  age
0   1   gz   10

再读入下一行,

In [66]: chunk.get_chunk(1)
Out[66]:id name  age
1   2   lh   12

此时已到文件末尾,再次读入会报异常,

In [108]: chunk.get_chunk(1)  StopIteration

293 Pandas 之随机选取一部分数据案例

对于动辄就几十或几百个 G 的数据,在读取的这么大数据的时候,我们有没有办法随机选取一小部分数据,然后读入内存,快速了解数据和开展 EDA ?

使用 Pandas 的 skiprows 和 概率知识,就能做到。

下面解释具体怎么做。

如下所示,读取某 100 G 大小的 big_data.csv 数据

1) 使用 skiprows 参数,

2) x > 0 确保首行读入,

3) np.random.rand() > 0.01 表示 99% 的数据都会被随机过滤掉

言外之意,只有全部数据的 1% 才有机会选入内存中。

import pandas as pd
import numpy as npdf = pd.read_csv("big_data.csv",
skiprows =
lambda x: x>0 and np.random.rand() > 0.01)print("The shape of the df is {}.
It has been reduced 100 times!".format(df.shape))

使用这种方法,读取的数据量迅速缩减到原来的 1% ,对于迅速展开数据分析有一定的帮助。

294 Pandas 之一维数组 Series

Series 是 pandas 两大数据结构中(DataFrame,Series) 的一种,先从 Series 的定义说起,Series 是一种类似于一维数组的对象,它由一组数据域以及一组与之相关联的数据标签和索引组成。

Series 对象也是一个 NumPy 的数组,因此 NumPy 的数组处理函数可以直接对 Series 进行处理。

与此同时,Series 除了可以使用位置索引作为下标存取元素之外,还可以使用标签下标存取元素,这一点和字典相似,每个 Series 对象都由两个数组组成:

  1. index:它是从 NumPy 数组继承的 Index 对象,保存标签信息。
  2. values:保存值的 NumPy 数组。

接下来,分别介绍 Series 内元素的增加、删除、修改、访问。

295 Pandas 之创建 Series

Series 的标准构造函数, 列举常用的几个参数:

Series(data=None, index=None, dtype=None, name=None)

其中,data 为数据部分,index 为标签部分,省略下默认为自增整数索引,dtype 为 str, numpy.dtype, or ExtensionDtype。

创建一个 series,如下:

In [85]: ps = pd.Series(data=[-3,2,1],index=['a','f','b'],dtype=np.float32)     In [86]: ps
Out[86]:
a   -3.0
f    2.0
b    1.0
dtype: float32

296 Series 之增加元素

在 ps 基础上增加一个元素,使用 append,如下:

In [112]: ps.append(pd.Series(data=[-8.0],index=['f']))
Out[112]:
a    4.0
f    2.0
b    1.0
f   -8.0
dtype: float64

可以看到,Pandas 允许包含重复的标签

In [114]: psn = ps.append(pd.Series(data=[-8.0],index=['f']))                   In [115]: psn
Out[115]:
a    4.0
f    2.0
b    1.0
f   -8.0
dtype: float64In [116]: psn['f']
Out[116]:
f    2.0
f   -8.0
dtype: float64

利用标签访问元素,返回所有带标签的数据。

297 Series之删除元素

使用 drop 删除指定标签的数据,如下:

In [119]: ps
Out[119]:
a    4.0
f    2.0
b    1.0
dtype: float32In [120]: psd = ps.drop('f')
In [121]: psd
Out[121]:
a    4.0
b    1.0
dtype: float32

注意不管是 append 操作,还是 drop 操作,都是发生在原数据的副本上,不是原数据上。

298 Series 之修改元素

通过标签修改对应数据,如下所示:

In [123]: psn
Out[123]:
a    4.0
f    2.0
b    1.0
f   -8.0
dtype: float64In [124]: psn['f'] = 10.0
In [125]: psn
Out[125]:
a     4.0
f    10.0
b     1.0
f    10.0
dtype: float64

标签相同的数据,都会被修改。

299 Series 之访问元素

访问元素,Pandas 提供两种方法,

  • 一种通过默认的整数索引,在 Series 对象未被显示的指定 label 时,都是通过索引访问;
  • 另一种方式是通过标签访问。
In [126]: ps
Out[126]:
a    4.0
f    2.0
b    1.0
dtype: float32In [128]: ps[2] # 索引访问
Out[128]: 1.0In [127]: ps['b']  # 标签访问
Out[127]: 1.0

300 Pandas 之二维数组 DataFrame

DataFrame, Pandas 两个重要数据结构中的另一个,可以看做是 Series 的容器。

DataFrame 同时具有行、列标签,是二维的数组,行方向轴 axis 为 0, 列方向 axis 为 1,如下:

axis : {0 or 'index', 1 or 'columns'}

创建 DataFrame

DataFrame 构造函数如下:

DataFrame(data=None, index=None, columns=None, dtype=None, copy=False)

参数意义与 Series 相似,不再赘述。

创建 DataFrame 的常用方法:

In [134]: df = pd.DataFrame([['gz',4.0,'2019-01-01'],['lg',1.2,'2019-06-01']],index = ['a','f'], columns = ['nm', 'y','da'])                          In [135]: df
Out[135]: nm    y          da
a  gz  4.0  2019-01-01
f  lg  1.2  2019-06-01

也可以通过字典传入,得到一样的 DataFrame,如下:

In [136]: df2 = pd.DataFrame({'nm':['gz','lg'],'y':[4.0,1.2], 'da':['2019-01-01', '2019-06-01']},index = ['a','f'])
In [137]: df2
Out[137]: nm    y          da
a  gz  4.0  2019-01-01
f  lg  1.2  2019-06-01

301 DataFrame 之增加数据

通过增加一个 Series,扩充到 DataFrame 中,如下所示:

In [143]: dfn = df.append(pd.Series(data=['zx',3.6,'2019-05-01'],index=['nm','y','da'],name='b'))
In [144]: dfn
Out[144]: nm    y          da
a  gz  4.0  2019-01-01
f  lg  1.2  2019-06-01
b  zx  3.6  2019-05-01

Series 的 index 与 DataFrame 的 column 对齐,name 与 DataFrame 的 index 对齐。

302 DataFrame 之删除数据

与 Series 删除类似,也是使用 drop 删除指定索引或标签的数据。如下,注意删除仍然是在 dfn 的副本上进行,像下面这样删除对 dfn 没有任何影响。

In [145]: dfn.drop('b')
Out[145]: nm    y          da
a  gz  4.0  2019-01-01
f  lg  1.2  2019-06-01

如果要删除某列,需要设定 axis 为 1, 如下所示:

In [147]: dfn.drop('y',axis=1)
Out[147]: nm          da
a  gz  2019-01-01
f  lg  2019-06-01
b  zx  2019-05-01

303 DataFrame 之修改数据

修改依然是先通过索引或标签定位到数据,然后修改,如下所示:

In [151]: dfn.loc['a','da']='2019-04-01'
In [152]: dfn
Out[152]: nm    y          da
a  gz  4.0  2019-04-01
f  lg  1.2  2019-06-01
b  zx  3.6  2019-05-01

作为入门或许理解到这里就够了,但要想进阶,还必须要了解一个关键点:链式赋值( chained assignment)。

使用 Pandas 链式赋值,经常会触发一个警告:SettingWithCopyWarning,类似下面一串警告:

SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation

归根结底,是因为代码中出现链式操作,那么什么是链式操作 ? 如下,就是一次链式赋值:

tmp = df[df.a<4]
tmp['c'] = 200

出现此 Warning, 需要理会它吗?还是需要!

import pandas as pddf = pd.DataFrame({'a':[1,3,5],'b':[4,2,7],'c':[0,3,1]})
print(df)tmp = df[df.a<4]
tmp['c'] = 200
print('-----原 df 没有改变------')
print(df)

输出结果:

   a  b  c
0  1  4  0
1  3  2  3
2  5  7  1
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value insteadSee the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copytmp['c'] = 200
-----原 df 没有改变------a  b  c
0  1  4  0
1  3  2  3
2  5  7  1

以上发生链式赋值,本意想改变 df,但是 df 未发生任何变化。因为 tmp 是 df 的 copy,而并非 view.

因此,如何创建 df 的 view, 而确保不发生链式操作,建议使用 .loc,如下调用:

import pandas as pddf = pd.DataFrame({'a':[1,3,5],'b':[4,2,7],'c':[0,3,1]})
print(df)df.loc[df.a<4,'c'] = 100
print(df)

输出结果:

   a  b  c
0  1  4  0
1  3  2  3
2  5  7  1a  b    c
0  1  4  100
1  3  2  100
2  5  7    1

304 Pandas 之访问数据

Pandas 推荐使用访问接口 iloc、loc 访问数据,详细使用如下:

In [153]: df
Out[153]: nm    y          da
a  gz  4.0  2019-01-01
f  lg  1.2  2019-06-01In [154]: df.iloc[1,:]
Out[154]:
nm            lg
y            1.2
da    2019-06-01
Name: f, dtype: objectIn [155]: df.loc['f',:]
Out[155]:
nm            lg
y            1.2
da    2019-06-01
Name: f, dtype: objectIn [156]: df.loc['f','nm']
Out[156]: 'lg'

iloc 索引访问,loc 标签访问。

305 Pandas 强大的 [ ] 操作符

原生 Python 中,[] 操作符常见的是与 list 搭配使用,并且 [] 操作符支持的对象只能是:整型,切片,例如:

a= [1, 3, 5]
# 以下OK:
a[1]
a[True]
a[:2]
a[:6]

list等可迭代对象是禁止的,如下:

# 不OK:
a[[1,2]]

为了更好地发挥 Python 的强大威力,Pandas 的 [] 操作符支持 list 对象。

为了演示,生成一个 DataFrame 实例 df1

import pandas as pd
import numpy as  npnp.random.seed(1)
df1=pd.DataFrame(np.random.randint(1,10,(4,3)),
index=['r1','r2','r3','r4'],
columns=['c1','c2','c3'])#结果c1  c2  c3
r1  6  9  6
r2  1  1  2
r3  8  7  3
r4  5  6  3

[] 操作符支持 list 对象,对 c1 和 c3 列索引:

df1[['c1','c3']]
#测试支持列索引c1  c3
r1  6  6
r2  1  2
r3  8  3
r4  5  3

注意这种支持也仅仅是对列索引;对于行索引,依然不支持,如下:

df1[['r1', 'r4']]
#测试结果,会出现以下报错:
KeyError: "None of [Index(['r1', 'r4'], dtype='object')] are in the [columns]"

利用行切片整数索引,获取 DataFrame,Pandas 依然延续了原生 Python 的风格,如下:

In [7]: df1[1:3]
Out[7]:c1  c2  c3
r2   1   1   2
r3   8   7   3

Pandas 还对此做了增强,同时支持行切片标签索引获取 DataFrame,注意包括终止标签

In [9]: df1['r1':'r3']
Out[9]:c1  c2  c3
r1   6   9   6
r2   1   1   2
r3   8   7   3

[] 操作符除了支持以上对象类型外,还支持哪些对象类型?

306 DataFrame 与标量结合

仅仅一行 df1>4 就能实现逐元素与 4 比较,大于 4 为 True,否则为 False。

然后返回一个新的 DataFrame,如下所示:

In [10]: df1 > 4
Out[10]:c1     c2     c3
r1   True   True   True
r2  False  False  False
r3   True   True  False
r4   True   True  False

结合 Pandas 的方括号 []后,便能实现元素级的操作,不大于 4 的元素被赋值为 NaN:

In [11]: df1[df1>4]
Out[11]:c1   c2   c3
r1  6.0  9.0  6.0
r2  NaN  NaN  NaN
r3  8.0  7.0  NaN
r4  5.0  6.0  NaN

df1>4 操作返回一个元素值为 True 或 False 的 DataFrame

(df1>4).values.tolist() 得到原生的 python list 对象:

In [15]: inner = ((df1>4).values).tolist()In [16]: inner
Out[16]:
[[True, True, True],[False, False, False],[True, True, False],[True, True, False]]In [17]: type(inner)
Out[17]: list

DataFrame, [] 和 list 实例结合会出现如下的结果:

In [18]: df1[inner]
Out[18]:c1  c2  c3
r1   6   9   6
r1   6   9   6
r1   6   9   6
r3   8   7   3
r3   8   7   3
r4   5   6   3
r4   5   6   3

仅仅改变为 df1[python list],而不是原来的 df1[DataFrame] 后,返回的结果迥异。

307 iterrows 和 itertuples

尽管 Pandas 已经尽可能向量化,让使用者尽可能避免 for 循环,但是有时不得以,还得要遍历 DataFrame. Pandas 提供 iterrows, itertuples 两种行级遍历。

这两种遍历效率上有什么不同,下面使用 Kaggle 上泰坦尼克号数据集的训练部分,测试遍历时的效率。

import pandas as pd
df = pd.read_csv('dataset/titanic_train_data.csv',sep=',')

df 一共有 891 行。

使用 iterrows 遍历打印所有行,在 Ipython 里输入以下行:

def iterrows_time(df):for i,row in df.iterrows():print(row)

然后使用魔法指令 %time,直接打印出此行的运行时间:

In [77]: %time iterrows_time(df)

实验 10 次,平均耗时:920 ms

然后,使用 itertuples 遍历打印每行:

def itertuples_time(df):for nt in df.itertuples():print(nt)

操作平均耗时 132 ms

也就是说打印 891 行, itertuples 遍历能节省 6倍时间,这对于处理几十万、几百万级别的数据时,效率优势会更加凸显。

分析 iterrows 慢的原因,通过分析源码,我们看到每次遍历时,Pandas 都会把 v 包装为一个 klass 对象,klass(v, index=columns, name=k) 操作耗时。

def iterrows(self):columns = self.columnsklass = self._constructor_slicedfor k, v in zip(self.index, self.values):s = klass(v, index=columns, name=k)yield k, s

因此,平时涉及遍历时,建议使用 itertuples 。

308 DataFrame 之列转 index

有时,我们想把现有的数据框的某些列转化为 index,为之后的更多操作做准备。

某列转为 index 的实现方法如下:

import pandas as pdIn [19]: df1 = pd.DataFrame({'a':[1,3,5],'b':[9,4,12]})In [20]: df1
Out[20]:a   b
0  1   9
1  3   4
2  5  12

a 列转为 index,分别不保留、保留原来的 a 列:

In [21]: df1.set_index('a',drop=False)
Out[21]:a   b
a
1  1   9
3  3   4
5  5  12In [22]: df1.set_index('a',drop=True)
Out[22]:b
a
1   9
3   4
5  12

对于频繁使用的列,建议转化为索引,效率会更高。

309 DataFrame 之 index 转列

使用 reset_index,将 index 转化为 DataFrame 的列,操作如下:

In [92]: df1 = pd.DataFrame({'a':[1,3,5],'b':[9,4,12]})In [93]: df2 = df1.set_index('a',drop=True)In [94]: df2.reset_index('a',drop=True)
Out[94]:b
0   9
1   4
2  12In [95]: df2.reset_index('a',drop=False)
Out[95]:a   b
0  1   9
1  3   4
2  5  12

310 DataFrame 之 reindex

如果想按照某种规则,按照行重新排序数据,靠 reindex 函数可以实现:

In [96]: df1 = pd.DataFrame({'a':[1,3,5],'b':[9,4,12]})In [97]: df1
Out[97]:a   b
0  1   9
1  3   4
2  5  12In [26]: df1.reindex([0,3,2,1])
Out[26]:a     b
0  1.0   9.0
3  NaN   NaN
2  5.0  12.0
1  3.0   4.0

df1 原来有的行索引会重新按照最新的索引[0,3,2,1]重新对齐,原来没有的行索引 3,默认数据都填充为 NaN.

列数据的调整,也一样通过 reindex 实现,如下:

In [27]: df1.reindex(columns=['b','a','c'])
Out[27]:b  a   c
0   9  1 NaN
1   4  3 NaN
2  12  5 NaN

以上是关于 index 调整的方法,在实际中很有用,希望读者们能掌握。

311 数据清洗的主要几个步骤?

数据清洗 (data cleaning) 是机器学习和深度学习进入算法步前的一项重要任务,总结为下面几个步骤。

步骤 1:读入 csv 数据;

步骤 2:预览数据;

步骤 3:统计每一列的空值;

步骤 4:填充空值

步骤 5:特征工程,子步骤包括:删除一些特征列;创建新的特征列;创建数据分箱;

步骤 6:对分类列编码,常用的包括,调用 Sklearn 中 LabelEncode 编码 ;Pandas 中哑编码;

步骤 7:再验证核实

今天使用泰坦尼克数据集,完整介绍以上步骤的具体操作过程。

312 Pandas 读入数据后预览技巧

使用 Pandas, 读入 csv 训练数据,然后了解每个字段的含义,数据有多少行和多少列等。

import pandas as pddata_raw = pd.read_csv('train.csv')
data_raw

结果如下,一共训练集有 891 行数据,12 列

PassengerId: 乘客的 Id;

Survived:乘客生还情况,取值 1,2;

Pclass:乘客等级,取值:1,2,3;

SibSp:乘客的兄弟姐妹和配偶在船上的人数;

Parch:乘客的父母和孩子在船上的人数;

Fare:乘船的费用;

Cabin:舱的编号;

Embarked:分类变量,取值 S, C, Q;

其他几个特征比较好辨别,不再解释。

Pandas 提供 2 个好用的方法:infodescribe

info 统计出数据的每一列类型、是否为 null 和个数;

describe 统计出数据每一列的统计学属性信息,平均值,方差,中位数,分位数等。

data_raw.info()
data_raw.describe(include='all')

结果:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
PassengerId    891 non-null int64
Survived       891 non-null int64
Pclass         891 non-null int64
Name           891 non-null object
Sex            891 non-null object
Age            714 non-null float64
SibSp          891 non-null int64
Parch          891 non-null int64
Ticket         891 non-null object
Fare           891 non-null float64
Cabin          204 non-null object
Embarked       889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB

313 检查 null 值

实际使用的数据,null 值在所难免。如何快速找出 DataFrame 每一列的 null 值个数?

使用 Pandas 能非常方便实现,只需下面一行代码:

data1_null = data1.isnull().sum()

data.isnull() : 逐行逐元素查找元素值是否为 null.

sum(): 默认在 axis 为 0 上完成一次 reduce 求和。

结果:

PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age            177
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         2
dtype: int64

查看每列的空值占比:

import matplotlib.pyplot as plt
import seaborn as snsx_raw = data1.columns
null_rate = data1_null.values / len(data1)
plt.bar(x_raw,null_rate)
plt.xticks(rotation=90)
plt.show()

Cabin 列空值比重最大,接近 80%,如此大的空值占比,可以直接删除。

314 补全空值

Age 列和 Embarked 列也存在空值,空值一般用此列的平均值、中位数、众数等填充。

观察 Age 列的取值分布直方图和箱型图

plt.figure(figsize=[10,8])
notnull_age_index = data1['Age'].notnull()
plt.subplot(221)
plt.hist(x = data1[notnull_age_index]['Age'], color = ['orange'])
plt.subplot(222)
plt.boxplot(x = data1[notnull_age_index]['Age'], showmeans = True, meanline = True)
plt.show()

集中在 20-40 岁,使用中位数填充空值:

data1['Age'].fillna(data1['Age'].median(), inplace = True)

Embarked 属于分类型变量,使用众数填充:

data1['Embarked'].fillna(data1['Embarked'].mode()[0], inplace = True)

填充完成后,检查这两列的空值是否全部填充成功。

data1.isnull().sum()
PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age              0
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         0
dtype: int64

315 Pandas 特征工程之删除特征列

因为 Cabin 缺失率较大,所以直接删除此列。

使用 Pandas 删除 列 Cabinaxis 参数设置为 1,表示轴为列方向,inplace 为 True 表示就地删除。

data1.drop('Cabin', axis=1, inplace = True)

另外两列,PassengerId, Ticket 都是 ID 类型的,对预测乘客能否逃离没有关系,也直接删除。

drop_column = ['PassengerId','Ticket']
data1.drop(drop_column, axis=1, inplace = True)

316 Pandas 特征工程之增加特征列

增加一列 FamilySize ,计算公式如下:

data1['FamilySize'] = data1 ['SibSp'] + data1['Parch'] + 1
data1.head(3)

再创建一列 IsAlone,如果 FamilySize 为 0,则表示只有一个人,IsAlone 为 True.

应用前面介绍的 where 函数,非常简洁地实现 IsAlone 列的赋值。

data1['IsAlone'] = np.where(data1['FamilySize'] > 1,0,1)

再创建一列 Title,它是从 Name 列中提取出头衔或称谓。

Name 列的前三行,如下:

0                              Braund, Mr. Owen Harris
1    Cumings, Mrs. John Bradley (Florence Briggs Th...
2                               Heikkinen, Miss. Laina
Name: Name, dtype: object

Pandas 中使用 str 属性,直接拿到整个此列的字符串值,然后使用前面介绍的字符串分隔方法 split

data1['Title'] = data1['Name'].str.split(", ", expand=True)[1].str.split(".", expand=True)[0]
data1

数据前三行使用上面代码,提取后结果如下:

0      Mr
1     Mrs
2    Miss
Name: 0, dtype: object

317 Pandas 特征工程之分箱

Pandas 提供两种数据分箱方法:qcut, cut.

qcut 方法是基于分位数的分箱技术,cut 基于区间长度切分为若干。使用方法如下:

a = [3,1,5, 7,6, 5, 4, 6, 3]
pd.qcut(a,3)

结果如下,共划分为 3 个分类:

[(0.999, 3.667], (0.999, 3.667], (3.667, 5.333], (5.333, 7.0], (5.333, 7.0], (3.667, 5.333], (3.667, 5.333], (5.333, 7.0], (0.999, 3.667]]
Categories (3, interval[float64]): [(0.999, 3.667] < (3.667, 5.333] < (5.333, 7.0]]

a 元素这 3 个分类中的个数相等:

dfa = pd.DataFrame(a)
len1 = dfa[(0.999 < dfa[0]) & (dfa[0] <= 3.667)].shape
len2 = dfa[(3.667 < dfa[0]) & (dfa[0] <= 5.333)].shape
len3 = dfa[(5.333 < dfa[0]) & (dfa[0] <= 7.0)].shape
len1,len2,len3

结果如下,每个区间内都有 3 个元素

((3, 1), (3, 1), (3, 1))

cut 方法:

a = [3,1,5, 7,6, 5, 4, 6, 3]
pd.cut(a,3)

得到结果,与 qcut 划分出的 3 个区间不同,cut 根据 a 列表中最大与最小值间隔,均分,第一个左区间做一定偏移。

[(0.994, 3.0], (0.994, 3.0], (3.0, 5.0], (5.0, 7.0], (5.0, 7.0], (3.0, 5.0], (3.0, 5.0], (5.0, 7.0], (0.994, 3.0]]
Categories (3, interval[float64]): [(0.994, 3.0] < (3.0, 5.0] < (5.0, 7.0]]

除此之外,1992 年 Kerber 在论文中提出 ChiMerge 算法,自底向上的先分割再合并的分箱思想,具体算法步骤:

1) 设置 step 初始值

2) while 相邻区间的 merge 操作:

  • 计算相邻区间的卡方值
  • 合并卡方值最小的相邻区间
  • 判断:是否所有相邻区间的卡方值都大于阈值,若是 break,否则继续 merge.

论文中 m 取值为 2 ,即计算 2 个相邻区间的卡方值,计算方法如下:

k : 类别个数

Ri : 第 i 个分箱内样本总数

Cj : 第 j 类别的样本总数

分别对 Fare 和 Age 列使用 qcut, cut 完成分箱,分箱数分别为 4 份,6 份。

data1['FareCut'] = pd.qcut(data1['Fare'], 4)
data1['AgeCut'] = pd.cut(data1['Age'].astype(int), 6)
data1.head(3)

结果:

318 数值编码常用方法:LabelEncoder 和 get_dummies

本节介绍 2 种常用的分类型变量编码方法,一种是分类变量直接编码,LabelEncoder;另一种对分类变量创建哑变量( dummy variables).

LabelEncoder 方法

使用 Sklearn 的 LabelEncoder 方法,对分类型变量完成编码。

from sklearn.preprocessing import LabelEncoder

泰坦尼克预测数据集中涉及的分类型变量有: Sex, Embarked, Title,还有我们新创建的2 个分箱列:AgeCut, FareCut.

label = LabelEncoder()
data1['Sex_Code'] = label.fit_transform(data1['Sex'])
data1['Embarked_Code'] = label.fit_transform(data1['Embarked'])
data1['Title_Code'] = label.fit_transform(data1['Title'])
data1['AgeBin_Code'] = label.fit_transform(data1['AgeCut'])
data1['FareBin_Code'] = label.fit_transform(data1['FareCut'])
data1.head(3)

使用 LabelEncoder 完成编码后,数据的前三行打印显示:

get_dummies 方法

Pandas 的 get_dummies 方法,也能实现对分类型变量实现哑编码, 将长 DataFrame 变为宽 DataFrame.

数据集中 Sex 分类型列取值有 2 种: female, male DataFrame:

pd.get_dummies(data1['Sex'])

使用 get_dummies ,返回 2 列,分别为 female, male 列,结果如下:

female    male
0    0   1
1    1   0
2    1   0
3    1   0
4    0   1
...    ... ...
886    0   1
887    1   0
888    1   0
889    0   1
890    0   1
891 rows × 2 columns

而 LabelEncoder 编码后,仅仅是把 Female 编码为 0, male 编码为 1.

label.fit_transform(data1['Sex'])
0      1
1      0
2      0
3      0
4      1..
886    1
887    0
888    0
889    1
890    1
Name: Sex_Code, Length: 891, dtype: int64

对以下变量实现哑编码:

data1_dummy = pd.get_dummies(data1[['Sex', 'Embarked', 'Title','AgeCut','FareCut']])
data1_dummy

结果:

319 Pandas 数据分析之 melt 透视

melt 函数,将宽 DataFrame 透视为长 DataFrame.

构造一个 DataFrame:

d = {\
"district_code": [12345, 56789, 101112, 131415],
"apple": [5.2, 2.4, 4.2, 3.6],
"banana": [3.5, 1.9, 4.0, 2.3],
"orange": [8.0, 7.5, 6.4, 3.9]
}df = pd.DataFrame(d)
df

打印结果:

district_code    apple   banana  orange
0    12345   5.2 3.5 8.0
1    56789   2.4 1.9 7.5
2    101112  4.2 4.0 6.4
3    131415  3.6 2.3 3.9

5.2 表示 12345 区域的 apple 价格,并且 apple, banana, orange,这三列都是一种水果,使用 melt 把这三列合并为一列。方法如下:

dfm = df.melt(\
id_vars = "district_code",
var_name = "fruit_name",
value_name = "price")
dfm

打印结果:

district_code    fruit_name  price
0    12345   apple   5.2
1    56789   apple   2.4
2    101112  apple   4.2
3    131415  apple   3.6
4    12345   banana  3.5
5    56789   banana  1.9
6    101112  banana  4.0
7    131415  banana  2.3
8    12345   orange  8.0
9    56789   orange  7.5
10    101112  orange  6.4
11    131415  orange  3.9

320 Pandas 数据分析之 pivot 和 pivot_table透视

pivot 将长 DataFrame 透视为宽 DataFrame,与 melt 函数透视方向相反。函数的主要参数说明:

1). index 指明哪个列变为新 DataFrame 的 index; 2). columns 指明哪些列变为 columns; 3). values 指明哪些列变为新 DataFrame 的数据域,如果不指明,则默认除了被指明 index 和 columns 的其他列。

对上面使用 melt 透视后的 dfm ,使用 pivot 函数,将长 DataFrame 变形为宽 DataFrame:

dfp = dfm.pivot(index='district_code',columns='fruit_name',values=['price'])
dfp

结果:

price
fruit_name    apple   banana  orange
district_code
12345    5.2 3.5 8.0
56789    2.4 1.9 7.5
101112    4.2 4.0 6.4
131415    3.6 2.3 3.9

打印透视后的 dfp 的列:

dfp.columns

结果如下,为多索引列:

MultiIndex([('price',  'apple'),('price', 'banana'),('price', 'orange')],names=[None, 'fruit_name'])

因此,透视后访问某列,就得使用多索引列:

dfp[('price',  'apple')]

结果:

district_code
12345     5.2
56789     2.4
101112    4.2
131415    3.6
Name: (price, apple), dtype: float64

pivot 函数是没有聚合功能的。

但是,pandas 中提供的 pivot_table()提供聚合功能。因此,pivot_table 可看是 pivot 函数的升级版。

pivot_table

为了演示,pivot_table 的聚合透视功能,先生成一个 DataFrame:

d = {\
"district_code": [12345, 12345, 56789, 101112, 131415,12345, 12345, 56789, 101112, 131415],
"fruit_name": ['apple', 'apple', 'orange', 'banana', 'orange','apple', 'apple', 'orange', 'banana', 'orange'],
"price":      [3.5, 3.7, 1.9, 4.0, 2.3,4.5, 4.7, 2.9, 5.0, 3.3]
}df2 = pd.DataFrame(d)
df2

结果:

district_code    fruit_name  price
0    12345   apple   3.5
1    12345   apple   3.7
2    56789   orange  1.9
3    101112  banana  4.0
4    131415  orange  2.3
5    12345   apple   4.5
6    12345   apple   4.7
7    56789   orange  2.9
8    101112  banana  5.0
9    131415  orange  3.3

pivot_table 函数,不仅具有 pivot 函数将长 DataFrame 透视为宽 DataFrame, 同时还具有 sum 聚合功能:

dfp2 = df2.pivot_table(index='district_code',columns='fruit_name',values=['price'],aggfunc=[np.sum])
dfp2

结果如下,district_code 为 12345 的区域,apple 价格求和已经聚合为 16.4

一次可以使用多个聚合方法,如下,使用求和、求平均值聚合:

dfp3 = df2.pivot_table(index='district_code',columns='fruit_name',values=['price'],aggfunc=[np.sum,np.mean])
dfp3

结果:

Pandas 还提供一个透视功能更加专一的函数,按照频次透视函数: crosstab

321 Pandas 数据分析之 crosstab 频次透视

有 2 个必传递的参数 index, colmns ,分别为透视后的行、列索引。

crosstabpivot_table 很相似,看一个例子。

a = np.array(['apple','apple', 'orange', 'banana', 'orange'], dtype=object)
b = np.array(['china','china', 'ameri', 'ameri', 'korea'], dtype=object)
c = np.array([ 'good','good','good','good','better'],dtype=object)
pd.crosstab(a,[b,c])

结果为:

以上,实质等价于:

for it in zip(a,b,c):    print(it)

可以看到 apple, china, good 这项出现的频次为 2,其他频次都是 1.

('apple', 'china', 'good')
('apple', 'china', 'good')
('orange', 'ameri', 'good')
('banana', 'ameri', 'good')
('orange', 'korea', 'better')

同理,

pd.crosstab([a,b],[c])

结果为:

还是只有一项(apple, china, good)频次为2,和上面的原理一样。

例子

df = pd.DataFrame({'类别':['水果','水果','水果','蔬菜','蔬菜','肉类','肉类'],'产地':['美国','中国','中国','中国','新西兰','新西兰','美国'],'水果':['苹果','梨','草莓','番茄','黄瓜','羊肉','牛肉'],'数量':[5,5,9,3,2,10,8],'价格':[5,5,10,3,3,13,20]})
df #显示df

结果:

类别    产地  水果  数量  价格
0    水果  美国  苹果  5   5
1    水果  中国  梨   5   5
2    水果  中国  草莓  9   10
3    蔬菜  中国  番茄  3   3
4    蔬菜  新西兰 黄瓜  2   3
5    肉类  新西兰 羊肉  10  13
6    肉类  美国  牛肉  8   20

类别列设置为 index, 产地列设置为 columns,统计词条出现频次:

pd.crosstab(df['类别'],df['产地'],margins=True)

结果:

如果想使用聚合函数,aggfun 参数,必须指明 values 列,如下:

pd.crosstab(df['类别'],df['产地'],values=df['价格'],aggfunc=np.max, margins=True)

结果如下:

crosstab本质:按照指定的 index 和 columns 统计 DataFrame 中出现(index, columns)的频次。

值得注意,这些透视函数,melt, pivot, pivot_table, crosstab,都基于 groupby 分组基础上,而分组大家是更容易理解的,所以在理解这些透视函数时,可以结合分组思想。

322 4 种表连接方法详解

给定两个 DataFrame,它们至少存在一个名称相同的列,如何连接两个表?使用merge 函数连接两个 DataFrame,连接方式共有 4 种,分别为:left, right, inner,outer. 如何区分这 4 种连接关系

2 个 DataFrame 分别为 left、 right,名称相同的列为 key,left 的 key 取值为:k0, k1, k2 ; right表的 key 取值为:k0, k0, k1

1) 如果 left 的 key 指向 right ,此连接方式为: left : 关系图表达为:

left    right
k0      k0k0
k1      k1
k2      NaN

2) 如果 right 的 key 指向 left,则称此连接方式为: right

right  left
k0      k0
k0
k1      k1

3) 如果只拿 left 和 right 公有 key (也就是交集)建立关系 ,称此连接方式为: inner

left  right
k0     k0
k0     k0
k1     k1

4) 如果 left 和 right 的 key合并(也就是并集)再建立关系后,称此连接方式为: outer

left  right
k0     k0k0
k1     k1
k2     NaN

以上就是 merge 连接 2 个DataFrame 时,根据 key 节点建立关系的 4 种方法。

下面举例说明:

left 和 right 分别为:

left

   age1   key
0   10   k0
1   20   k1
2   30   k2

right

   age2   key
0   40   k0
1   50   k0
2   60   k1

如果连接方法参数 how 取值为 'left'

pd.merge(left,right,how='left',on='key')

结果:

   age1   key   age2
0   10   k0   40.0
1   10   k0   50.0
2   20   k1   60.0
3   30   k2   NaN

如果连接方法参数 how 取值为 'right'

pd.merge(left,right,how='right',on='key')

结果:

age1   key   age2
0   10   k0   40
1   10   k0   50
2   20   k1   60

如果连接方法参数 how 取值为 'inner'

pd.merge(left,right,how='inner',on='key')

结果:

age1   key   age2
0   10   k0   40
1   10   k0   50
2   20   k1   60

如果连接方法参数 how 取值为 'outer'

pd.merge(left,right,how='outer',on='key')

结果:

age1   key   age2
0   10   k0   40.0
1   10   k0   50.0
2   20   k1   60.0
3   30   k2   NaN

323 Pandas 使用技巧:生成时间序列的数据集

与时间序列相关的问题,平时挺常见。如何用 Pandas 快速生成时间序列数据?使用

pd.util.testing.makeTimeDataFrame

只需要一行代码,便能生成一个 index 为时间序列的 DataFrame:

import pandas as pdpd.util.testing.makeTimeDataFrame(10)

结果:

A    B   C   D
2000-01-03    0.932776    -1.509302   0.285825    0.941729
2000-01-04    0.565230    -1.598449   -0.786274   -0.221476
2000-01-05    -0.152743   -0.392053   -0.127415   0.841907
2000-01-06    1.321998    -0.927537   0.205666    -0.041110
2000-01-07    0.324359    1.512743    0.553633    0.392068
2000-01-10    -0.566780   0.201565    -0.801172   -1.165768
2000-01-11    -0.259348   -0.035893   -1.363496   0.475600
2000-01-12    -0.341700   -1.438874   -0.260598   -0.283653
2000-01-13    -1.085183   0.286239    2.475605    -1.068053
2000-01-14    -0.057128   -0.602625   0.461550    0.033472

时间序列的间隔还能配置,默认的 A B C D 四列也支持配置。

import numpy as npdf = pd.DataFrame(np.random.randint(1,1000,size=(10,3)),columns = ['商品编码','商品销量','商品库存'])
df.index = pd.util.testing.makeDateIndex(10,freq='H')

结果:

    商品编码    商品销量    商品库存
2000-01-01 00:00:00    99  264 98
2000-01-01 01:00:00    294 406 827
2000-01-01 02:00:00    89  221 931
2000-01-01 03:00:00    962 153 956
2000-01-01 04:00:00    538 46  374
2000-01-01 05:00:00    226 973 750
2000-01-01 06:00:00    193 866 7
2000-01-01 07:00:00    300 129 474
2000-01-01 08:00:00    966 372 835
2000-01-01 09:00:00    687 493 910

324 Pandas 使用技巧: apply(type) 做类型检查

有时肉眼所见的列类型,未必就是你预期的类型,如下 DataFrame 销量这一列,看似为浮点型。

实际上,我们是这样生成 DataFrame 的,

d = {"商品":["A", "B", "C", "D", "E"], "销量":[100, "100", 50, 550.20, "375.25"]}
df = pd.DataFrame(d)
df

所以直接在销量这一列上求平均值,就会报错。

df['销量'].sum()
TypeError: unsupported operand type(s) for +: 'int' and 'str'

所以在计算前,检查此列每个单元格的取值类型就很重要。

df['销量'].apply(type)
0      <class 'int'>
1      <class 'str'>
2      <class 'int'>
3    <class 'float'>
4      <class 'str'>
Name: 销量, dtype: object

上面是打印结果,看到取值有 int , str, float. 有的读者就问了,这才几行,如果上千上百行,也有一个一个瞅吗,当然不能,使用 value_counts 统计下各种值的频次。

df['销量'].apply(type).value_counts()
<class 'int'>      2
<class 'str'>      2
<class 'float'>    1
Name: 销量, dtype: int64

325 Pandas使用技巧: 标签和位置选择数据

读入数据,本专栏使用到的数据集都会打包发给各位读者。

df = pd.read_csv("drinksbycountry.csv", index_col="country")
df

使用位置,iloc 选择前 10 行数据:

df.iloc[:10, :]

标签和 loc 选择两列数据

df.iloc[:10, :].loc[:, "spirit_servings":"wine_servings"]

也可以直接使用 iloc ,得到结果如上面一样。

df.iloc[:10, 1:3]

326 Pandas 使用技巧: 空值检查

实际使用的数据,null 值在所难免。如何快速找出 DataFrame 所有列的 null 值个数?

使用 Pandas 能非常方便实现,只需下面一行代码:

data.isnull().sum()

data.isnull(): 逐行逐元素查找元素值是否为 null.

.sum(): 默认在 axis 为 0 上完成一次 reduce 求和。

如下 DataFrame:

检查 null 值:

data.isnull().sum()

结果:

PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age            177
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         2
dtype: int64

Age 列 177 个 null 值

Cabin 列 687 个 null 值

Embarked 列 2 个 null 值

327 Pandas 使用技巧: replace 做清洗

Pandas 的强项在于数据分析,自然就少不了对数据清洗的支持。一个快速清洗数据的小技巧,在某列上使用 replace 方法和正则,快速完成值的清洗。

源数据:

d = {"customer": ["A", "B", "C", "D"],
"sales":[1100, "950.5", "$400", " $1250.75"]}df = pd.DataFrame(d)
df

打印结果:

customer    sales
0    A   1100
1    B   950.5
2    C   $400
3    D   $1250.75

看到 sales 列的值,有整型,还有美元+整型,美元+浮点型。

我们的目标:清洗掉$ 符号,字符串型转化为浮点型。

一行代码搞定:(点击代码区域,向右滑动,查看完整代码)

df["sales"] = df["sales"].replace("[$]", "", regex = True).astype("float")

使用正则替换,将要替换的字符放到列表中 [$],替换为空字符,即 ""

最后使用 astype 转为 float

打印结果:

customer    sales
0    A   1100.00
1    B   950.50
2    C   400.00
3    D   1250.75

如果不放心,再检查下值的类型:

df["sales"].apply(type)

打印结果:

0    <class 'float'>
1    <class 'float'>
2    <class 'float'>
3    <class 'float'>

328 Pandas 使用技巧: 转 datetime

已知年和 dayofyear,怎么转 datetime?

原 DataFrame

d = {\
"year": [2019, 2019, 2020],
"day_of_year": [350, 365, 1]
}
df = pd.DataFrame(d)
df

打印结果:

  year    day_of_year
0    2019    350
1    2019    365
2    2020    1

下面介绍如何转 datetime 的 trick

Step 1: 创建整数

df["int_number"] = df["year"]*1000 + df["day_of_year"]
df

打印结果:

year    day_of_year int_number
0    2019    350 2019350
1    2019    365 2019365
2    2020    1   2020001

Step 2: to_datetime

df["date"] = pd.to_datetime(df["int_number"], format = "%Y%j")
df

注意 "%Y%j" 中转化格式 j,正是对应 dayofyear 参数

打印结果:

    year    day_of_year int_number  date
0    2019    350 2019350 2019-12-16
1    2019    365 2019365 2019-12-31
2    2020    1   2020001 2020-01-01

329 Pandas 使用技巧:小分类值的替换

分类中出现次数较少的值,如何统一归为 others,该怎么做到?

这也是我们在数据清洗、特征构造中经常会面临的一个任务。

如下 DataFrame:

d = {"name":['Jone','Alica','Emily','Robert','Tomas','Zhang','Liu','Wang','Jack','Wsx','Guo'],"categories": ["A", "C", "A", "D", "A", "B", "B", "C", "A", "E", "F"]}
df = pd.DataFrame(d)
df

结果:

    name    categories
0    Jone    A
1    Alica   C
2    Emily   A
3    Robert  D
4    Tomas   A
5    Zhang   B
6    Liu B
7    Wang    C
8    Jack    A
9    Wsx E
10    Guo F

D、E、F 仅在分类中出现一次,A 出现次数较多。

步骤 1:统计频次,并归一化

frequencies = df["categories"].value_counts(normalize = True)
frequencies

结果:

A    0.363636
B    0.181818
C    0.181818
F    0.090909
E    0.090909
D    0.090909
Name: categories, dtype: float64

步骤 2:设定阈值,过滤出频次较少的值

threshold = 0.1
small_categories = frequencies[frequencies < threshold].index
small_categories

结果:

Index(['F', 'E', 'D'], dtype='object')

步骤 3:替换值

df["categories"] = df["categories"].replace(small_categories, "Others")

替换后的 DataFrame:

    name    categories
0    Jone    A
1    Alica   C
2    Emily   A
3    Robert  Others
4    Tomas   A
5    Zhang   B
6    Liu B
7    Wang    C
8    Jack    A
9    Wsx Others
10    Guo Others

330 Pandas 使用技巧:重新排序列

某些场景需要重新排序 DataFrame 的列,如下 DataFrame:

如何将列快速变为:

先构造数据:

df = pd.DataFrame(np.random.randint(0,20,size=(5,7)),columns=list('ABCDEFG'))
df

方法1,直接了当:

df2 = df[["A", "C", "D", "F", "E", "G", "B"]]
df2

结果:

方法2,也了解下:

cols = df.columns[[0, 2 , 3, 5, 4, 6, 1]]
df3 = df[cols]
df3

也能得到方法1的结果。

331 Pandas 使用技巧: 时间数据下采样

步长为小时的时间序列数据,有没有小技巧,快速完成下采样,采集成按天的数据呢?

先生成测试数据:

import pandas as pd
import numpy as npdf = pd.DataFrame(np.random.randint(1,10,
size=(240,3)),
columns = ['商品编码','商品销量','商品库存'])df.index = pd.util.testing.makeDateIndex(240,freq='H')
df

生成 240 行步长为小时间隔的数据:

使用 resample 方法,合并为天(D)

day_df = df.resample("D")["商品销量"].sum().to_frame()
day_df

结果如下,10 行,240 小时,正好为 10 天:

332 Pandas 使用技巧:map 做特征工程

DataFrame 上快速对某些列展开特征工程,如何做到?

先生成数据:

d = {
"gender":["male", "female", "male","female"],
"color":["red", "green", "blue","green"],
"age":[25, 30, 15, 32]
}df = pd.DataFrame(d)
df

gender 列上做如下映射:

d = {"male": 0, "female": 1}
df["gender2"] = df["gender"].map(d)

333 Pandas 使用技巧: 结合使用 where 和 isin

如下 DataFrame:

d = {"genre": ["A", "C", "A", "A", "A", "B", "B", "C", "D", "E", "F"]}
df = pd.DataFrame(d)
df
genre
0    A
1    C
2    A
3    A
4    A
5    B
6    B
7    C
8    D
9    E
10    F

除了 3个出现频率最高的值外,统一替换其他值为 others.

首先找到出现频率最高的 3 个值:

top3 = df["genre"].value_counts().nlargest(3).index
top3

结果:

Index(['A', 'C', 'B'], dtype='object')

使用 isin:

df_update = df.where(df["genre"].isin(top3), other = "others")
df_update

使用 where, 不满足第一个参数条件的,都会被替换为 others.

结果:

    genre
0    A
1    C
2    A
3    A
4    A
5    B
6    B
7    C
8    others
9    others
10    others

结合使用 where, isin 做数据工程,特征清洗非常方便。

Python 全栈 400 之Pandas数据分析练习相关推荐

  1. Python 全栈 400 之画图练习

    354 10行代码看matplotlib绘图基本原理 from matplotlib.figure import Figure from matplotlib.backends.backend_agg ...

  2. 美国AI博士指出:60天掌握Python全栈需要...

    我见过市面上很多的 Python 讲解教程和书籍,他们大都这样讲 Python 的: 先从 Python 的发展历史开始,介绍 Python 的基本语法规则,Python 的 list, dict, ...

  3. Python技术栈与Spark交叉数据分析双向整合技术实战--大数据ML样本集案例实战

    版权声明:本套技术专栏是作者(秦凯新)平时工作的总结和升华,通过从真实商业环境抽取案例进行总结和分享,并给出商业应用的调优建议和集群环境容量规划等内容,请持续关注本套博客.QQ邮箱地址:1120746 ...

  4. 牛!Python 全栈必备的 150 个实战案例,一次性获得!

    Python 全栈将是你升职加薪的硬通货. 我见过很多的 Python 讲解教程和书籍,它们大都这样讲 Python 的: 先从 Python 的发展历史开始,介绍 Python 的基本语法规则,Py ...

  5. 学python有前途吗-Python全栈开发有前景吗,是否值得学习?

    谢邀 一.什么是Python web全栈工程师? 全栈工程师是指掌握多种技能,并能利用多种技能独立完成产品的人.也叫全端工程师(同时具备前端和后台能力),英文Full Stack developer. ...

  6. 月薪40K起,什么是Python全栈工程师?全栈工程师薪资为何这么高?

    我们经常听到全栈工程师这个词语.那么很多小伙伴还是不明所以,什么是全栈工程师?为什么全栈开发用Python?Python web全栈开发到底有多高薪?今天就来为大家解读一下. 什么是Python we ...

  7. python26章_44G-26章节Python盖世修炼最新实战 全新升级版Python全栈架构师高级课程 从零实战...

    44G-26章节Python盖世修炼最新实战 全新升级版Python全栈架构师高级课程 从零实战 ===============课程目录=============== 课程目录过长,下面只列出了章节目 ...

  8. 2017最新整理python全栈工程师系统培训之路精品课程(全套)

    百度搜索"一起自学吧"做大数据专家,不做第一,只做唯一. 课程介绍: 本课程由一起自学吧论坛打造,目的是给想成为Python全栈工程师的同学提供一套完整,全面而系统的培训课程,课程 ...

  9. 美国 AI 博士:什么都不会怎么学 Python?60 天知识脉络图,快速挑战 Python 全栈

    我见过市面上很多的 Python 讲解教程和书籍,他们大都这样讲 Python 的: 先从 Python 的发展历史开始,介绍 Python 的基本语法规则,Python 的 list, dict, ...

最新文章

  1. Database design best practice(1):关于primary key及其它
  2. 提升10倍生产力:IDEA远程一键部署SpringBoot到Docker
  3. uva 12167(强连通分支)
  4. 2015.1.3 让CombBox自动弹出下拉框
  5. Spring Boot 2.x基础教程:使用Spring Data JPA访问MySQL
  6. 写给用我的“新闻推荐项目”做毕设的同学们
  7. 前端基础之CSS_1
  8. 如何实现一个线程安全的 ConcurrentHashSet ?
  9. 如何开始一个深度学习项目
  10. 解答:一个perl操作config.ini的出现的 cannot find file or dirctionary,可明明文件存在
  11. 94. Ext.MessageBox消息框
  12. 腾讯云 cos计费说明
  13. STORM启动与部署TOPOLOGY
  14. 成都电子地图 高清15、17、19级别 谷歌电子地图资源
  15. 针对IE安全控件的爬虫
  16. t470键盘拆解_看完你就想买——绝对良心级做工品质的ThinkPad T470拆解
  17. 关于PMP考试的流程,很实用
  18. 《c 语言程序设计》宝钏,【黄钟】醉花阴_宝钏松金髻
  19. vue.js not detected问题解决
  20. 公交IC卡刷卡数据分析

热门文章

  1. matlab实现疲劳驾驶监测
  2. 全网最全面的 Node.js 资源汇总推荐,4W Star!
  3. 易流科技数字食安聚焦校园食品安全问题
  4. arcmap十进制度和度分秒相互转换
  5. 如何实现一个动态的背景渐变效果?
  6. python安装psutil_记录安装psutil模块
  7. 通熟易懂的 Elasticsearch入门
  8. linux提取文件最后一行,sed或awk处理文件最后一行的实现方法
  9. 长江游艇俱乐部算法题
  10. 【软件测试阶段及策略】