基于针对另一列的参考表更新 Pandas 数据框列的问题

Posted

技术标签:

【中文标题】基于针对另一列的参考表更新 Pandas 数据框列的问题【英文标题】:Issue With Updating Pandas Dataframe Column Based on Reference Table Targeting Another Column 【发布时间】:2018-06-18 19:30:52 【问题描述】:

我有一个数据框,我正在尝试根据我在外部参考表中的信息(目前是一个小的 ~20 条目 csv)来更新它,我在弄清楚如何获取它时遇到了一些困难上班。

数据框如下所示:

id    company    value1    value2
1     foo        10.00     0.00
2     bar        10.00     0.00
3     lorem      15.00     0.00
4     ipsum      10.00     0.00
5     foo        50.00     0.00
6     lorem      40.00     0.00
7     foo        0.00      0.00

参考表 csv 包含将 value1 乘以得到 value2 的百分比,就像这样(它们最初是小数,但 vd = pd.read_csv('$name.csv', index_col=0).to_dict() 导致浮动点问题,所以我改为更改参考表):

company   percentage
foo       15
bar       50
ipsum     40

我正在寻找如下所示的输出:

id    company    value1    value2
1     foo        10.00     1.50
2     bar        10.00     5.00
3     lorem      15.00     15.00
4     ipsum      10.00     4.00
5     foo        50.00     7.50
6     lorem      40.00     40.00
7     foo        0.00      0.00

目前,我将引用表导入字典(作为整数),但是当我将其与数据框匹配时,结果(值 2)以 NaN 形式返回。我认为我的问题可能与匹配代码有关,目前看起来像这样:

df['value2'] = df['value1'] * (df["company"].map(vd)/100)

我在正确的轨道上吗?这是我第一次使用 pandas,所以我可能会遗漏一些明显的东西。

谢谢!

编辑:不小心忘记混淆一个变量。 “vd”只是字典导入后的名称。

【问题讨论】:

我想我之前误解了。你能告诉我vd 是什么吗?如果它是一个 DataFrame,你可以使用 vd.set_index('company')['percentage'] 而不是 vd,但你需要展示你是如何构建它们的。 不,你以前似乎是对的。摆脱字典,而是使用 vd = pd.read_csv('$name.csv', index_col=0, squeeze=True) 解决了参考表中的问题,我不在乎那些不在参考表中的(因为它们马上就被删除了)。现在我只需要添加边界检查(因为前面部分中的任何负数都需要为 0 而不是负数),然后就可以开始了。谢谢! 也鼓励你看看我的回答 ;-) @ZuR4ruukmT0YPwgs 立即尝试... ;-) 此外,如果它回答了您的问题,您可以通过单击答案旁边的灰色复选标记将其切换为绿色来接受它。 请看我上面的评论。 ^ 【参考方案1】:

map 是迄今为止完成您正在做的事情的最快方式。但这里有几个选择,以及它们的性能。

设置

首先,df -

df

   id company  value1  value2
0   1     foo    10.0     0.0
1   2     bar    10.0     0.0
2   3   lorem    15.0     0.0
3   4   ipsum    10.0     0.0
4   5     foo    50.0     0.0
5   6   lorem    40.0     0.0

接下来,vd -

vd = pd.read_csv('$name.csv')
vd = vd.set_index('company').percentage

或者,

vd = pd.read_csv('$name.csv', index_col=0, squeeze=True)  # @ayhan's suggestion 

vd

company
foo      15
bar      50
ipsum    40
Name: percentage, dtype: int64

选项 1map

df.value2 = df.value1 * df.company.map(vd).fillna(100).div(100)
df

   id company  value1  value2
0   1     foo    10.0     1.5
1   2     bar    10.0     5.0
2   3   lorem    15.0    15.0
3   4   ipsum    10.0     4.0
4   5     foo    50.0     7.5
5   6   lorem    40.0    40.0

选项 2replace

v = pd.to_numeric(df.company.replace(vd), errors='coerce')
df.value2 = df.value1 * v.fillna(100) / 100
df

   id company  value1  value2
0   1     foo    10.0     1.5
1   2     bar    10.0     5.0
2   3   lorem    15.0    15.0
3   4   ipsum    10.0     4.0
4   5     foo    50.0     7.5
5   6   lorem    40.0    40.0

选项 3merge

df = df.merge(
     (vd / 100).to_frame(), 
     left_on='company', 
     right_index=True, 
     how='left'
).fillna(1)

df.value2 = df.value1 * df.percentage 
del df['percentage']

df

   id company  value1  value2
0   1     foo    10.0     1.5
1   2     bar    10.0     5.0
2   3   lorem    15.0    15.0
3   4   ipsum    10.0     4.0
4   5     foo    50.0     7.5
5   6   lorem    40.0    40.0

性能

df = pd.concat([df] * 10000, ignore_index=True)

%timeit df.value1 * df.company.map(vd).fillna(100).div(100)
100 loops, best of 3: 6.07 ms per loop

%timeit df.value1 * pd.to_numeric(df.company.replace(vd), errors='coerce').fillna(100) / 100
10 loops, best of 3: 65.6 ms per loop

%%timeit
df2 = df.merge((vd / 100).to_frame(), left_on='company', right_index=True, how='left').fillna(1)
df2.value2 = df2.value1 * df2.percentage 
del df2['percentage']

100 loops, best of 3: 13.1 ms per loop

map 显然是这里的赢家。

【讨论】:

以上是关于基于针对另一列的参考表更新 Pandas 数据框列的问题的主要内容,如果未能解决你的问题,请参考以下文章

根据另一列的值过滤数据框列[重复]

PySpark:根据另一列的顺序收集数据框列上的集合

使用同一表中另一列的数据计数更新一列? [关闭]

Pandas 表示基于另一列的某些列(二进制值)

Oracle SQL:使用来自同一表的另一列的数据更新表

当您需要基于另一列更新列时,在 Pandas 中循环的替代方法