图解Pandas的assign函数

公众号:尤而小屋
作者:Peter
编辑:Peter

大家好,我是Peter~

本文介绍的是Pandas库中一个非常有用的函数:assign

在我们处理数据的时候,有时需要根据某个列进行计算得到一个新列,以便后续使用,相当于是根据已知列得到新的列,这个时候assign函数非常方便。下面通过实例来说明函数的的用法。

Pandas文章

本文是Pandas文章连载系列的第21篇,主要分为3类:

基础部分:1-16篇,主要是介绍Pandas中基础和常用操作,比如数据创建、检索查询、排名排序、缺失值/重复值处理等常见的数据处理操作

进阶部分:第17篇开始讲解Pandas中的高级操作方法

对比SQL,学习Pandas:将SQL和Pandas的操作对比起来进行学习

image

参数

assign函数的参数只有一个:DataFrame.assign(**kwargs)。

**kwargs: dict of {str: callable or Series}

关于参数的几点说明:

  • 列名是关键字keywords
  • 如果列名是可调用的,那么它们将在DataFrame上计算并分配给新的列
  • 如果列名是不可调用的(例如:Series、标量scalar或者数组array),则直接进行分配

最后,这个函数的返回值是一个新的DataFrame数据框,包含所有现有列和新生成的列

导入库

import pandas as pd
import numpy as np
# 模拟数据

df = pd.DataFrame({
  "col1":[12, 16, 18],
  "col2":["xiaoming","peter", "mike"]})

df

<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}

.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}

</style>

<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>col1</th>
<th>col2</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>12</td>
<td>xiaoming</td>
</tr>
<tr>
<th>1</th>
<td>16</td>
<td>peter</td>
</tr>
<tr>
<th>2</th>
<td>18</td>
<td>mike</td>
</tr>
</tbody>
</table>

</div>

实例

当值是可调用的,我们直接在数据框上进行计算:

方式1:直接调用数据框

# 方式1:数据框df上调用
# 使用数据框df的col1属性,生成col3

df.assign(col3=lambda x: x.col1 / 2 + 20)  

<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}

.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}

</style>

<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>col1</th>
<th>col2</th>
<th>col3</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>12</td>
<td>xiaoming</td>
<td>26.0</td>
</tr>
<tr>
<th>1</th>
<td>16</td>
<td>peter</td>
<td>28.0</td>
</tr>
<tr>
<th>2</th>
<td>18</td>
<td>mike</td>
<td>29.0</td>
</tr>
</tbody>
</table>

</div>

我们可以查看原来的df,发现它是不变的

df  # 原数据框不变的

<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}

.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}

</style>

<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>col1</th>
<th>col2</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>12</td>
<td>xiaoming</td>
</tr>
<tr>
<th>1</th>
<td>16</td>
<td>peter</td>
</tr>
<tr>
<th>2</th>
<td>18</td>
<td>mike</td>
</tr>
</tbody>
</table>

</div>

操作字符串类型的数据:

df.assign(col3=df["col2"].str.upper())
image

方式2:调用Series数据

可以通过直接引用现有的Series或序列来实现相同的行为:

# 方式2:调用现有的Series来计算

df.assign(col4=df["col1"] * 3 / 4 + 25)
image
df  # 原数据不变

<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}

.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}

</style>

<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>col1</th>
<th>col2</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>12</td>
<td>xiaoming</td>
</tr>
<tr>
<th>1</th>
<td>16</td>
<td>peter</td>
</tr>
<tr>
<th>2</th>
<td>18</td>
<td>mike</td>
</tr>
</tbody>
</table>

</div>

在Python3.6+中,我们可以在同一个赋值中创建多个列,并且其中一个列还可以依赖于同一个赋值中定义的另一列,也就是中间生成的新列可以直接使用

df.assign(
    col5=lambda x: x["col1"] / 2 + 10,         
    col6=lambda x: x["col5"] * 5,  # 在col6计算中直接使用col5        
    col7=lambda x: x.col2.str.upper(),         
    col8=lambda x: x.col7.str.title()  # col8中使用col7
)
image
df   # 原数据不变

<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}

.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: left;
}

</style>

<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>col1</th>
<th>col2</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>12</td>
<td>xiaoming</td>
</tr>
<tr>
<th>1</th>
<td>16</td>
<td>peter</td>
</tr>
<tr>
<th>2</th>
<td>18</td>
<td>mike</td>
</tr>
</tbody>
</table>

</div>

如果我们重新分配的是一个现有的列,那么这个现有列的值将会被覆盖:

df.assign(col1=df["col1"] / 2)  # col1直接被覆盖

<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}

.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: left;
}

</style>

<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>col1</th>
<th>col2</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>6.0</td>
<td>xiaoming</td>
</tr>
<tr>
<th>1</th>
<td>8.0</td>
<td>peter</td>
</tr>
<tr>
<th>2</th>
<td>9.0</td>
<td>mike</td>
</tr>
</tbody>
</table>

</div>

对比apply函数

我们在pandas中同样可以使用apply函数来实现

df  # 原数据

<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}

.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: left;
}

</style>

<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>col1</th>
<th>col2</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>12</td>
<td>xiaoming</td>
</tr>
<tr>
<th>1</th>
<td>16</td>
<td>peter</td>
</tr>
<tr>
<th>2</th>
<td>18</td>
<td>mike</td>
</tr>
</tbody>
</table>

</div>

生成一个副本,我们直接在副本上操作:

df1 = df.copy()  # 生成副本,直接在副本上操作
df2 = df.copy()

df1

<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}

.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: left;
}

</style>

<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>col1</th>
<th>col2</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>12</td>
<td>xiaoming</td>
</tr>
<tr>
<th>1</th>
<td>16</td>
<td>peter</td>
</tr>
<tr>
<th>2</th>
<td>18</td>
<td>mike</td>
</tr>
</tbody>
</table>

</div>

df1.assign(col3=lambda x: x.col1 / 2 + 20)  

<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}

.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: left;
}

</style>

<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>col1</th>
<th>col2</th>
<th>col3</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>12</td>
<td>xiaoming</td>
<td>26.0</td>
</tr>
<tr>
<th>1</th>
<td>16</td>
<td>peter</td>
<td>28.0</td>
</tr>
<tr>
<th>2</th>
<td>18</td>
<td>mike</td>
<td>29.0</td>
</tr>
</tbody>
</table>

</div>

df1  # df1保持不变

<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}

.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: left;
}

</style>

<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>col1</th>
<th>col2</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>12</td>
<td>xiaoming</td>
</tr>
<tr>
<th>1</th>
<td>16</td>
<td>peter</td>
</tr>
<tr>
<th>2</th>
<td>18</td>
<td>mike</td>
</tr>
</tbody>
</table>

</div>

df1["col3"] = df1["col1"].apply(lambda x:x / 2 + 20)

df1  # df1已经发生了变化

<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}

.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: left;
}

</style>

<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>col1</th>
<th>col2</th>
<th>col3</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>12</td>
<td>xiaoming</td>
<td>26.0</td>
</tr>
<tr>
<th>1</th>
<td>16</td>
<td>peter</td>
<td>28.0</td>
</tr>
<tr>
<th>2</th>
<td>18</td>
<td>mike</td>
<td>29.0</td>
</tr>
</tbody>
</table>

</div>

我们发现:通过assign函数的操作,原数据是不变的,但是通过apply操作的数据已经变化了

BMI

最后在模拟一份数据,计算每个人的BMI。

身体质量指数,是BMI指数,简称体质指数,是国际上常用的衡量人体胖瘦程度以及是否健康的一个标准。

{BMI} = \frac {体重}{身高^2}

其中:体重单位是kg,身高单位是m

df2 = pd.DataFrame({
    "name":["xiaoming","xiaohong","xiaosu"],
    "weight":[78,65,87],
    "height":[1.82,1.75,1.89]
})

df2

<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}

.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: left;
}

</style>

<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>name</th>
<th>weight</th>
<th>height</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>xiaoming</td>
<td>78</td>
<td>1.82</td>
</tr>
<tr>
<th>1</th>
<td>xiaohong</td>
<td>65</td>
<td>1.75</td>
</tr>
<tr>
<th>2</th>
<td>xiaosu</td>
<td>87</td>
<td>1.89</td>
</tr>
</tbody>
</table>

</div>

# 使用assign函数实现

df2.assign(BMI=df2["weight"] / (df2["height"] ** 2))
image
df2 # 不变

<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}

.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: left;
}

</style>

<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>name</th>
<th>weight</th>
<th>height</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>xiaoming</td>
<td>78</td>
<td>1.82</td>
</tr>
<tr>
<th>1</th>
<td>xiaohong</td>
<td>65</td>
<td>1.75</td>
</tr>
<tr>
<th>2</th>
<td>xiaosu</td>
<td>87</td>
<td>1.89</td>
</tr>
</tbody>
</table>

</div>

df2["BMI"] = df2["weight"] / (df2["height"] ** 2)

df2  # df2生成了一个新的列:BMI
image

总结

通过上面的例子,我们发现:

  1. 使用assign函数生成的DataFrame是不会改变原来的数据,这个DataFrame是新的
  2. assign函数能够同时操作多个列名,并且中间生成的列名能够直接使用
  3. assign和apply的主要区别在于:前者不改变原数据,apply函数是在原数据的基础上添加新列
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,635评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,628评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,971评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,986评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,006评论 6 394
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,784评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,475评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,364评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,860评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,008评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,152评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,829评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,490评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,035评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,428评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,127评论 2 356

推荐阅读更多精彩内容