我想更新极地库数据框,
我用于此目的的极地语法/命令: df[0, 'A'] = '某个值'
但是上面的代码给出了错误: ValueError:无法设置列表/元组作为值;使用标量值 我正在使用极坐标 0.13.55
上述代码之前适用于极地 0.13.51
重现问题的最少代码:
df = pl.DataFrame( { "IP": ['1.1.1.1', '2.2.2.2'], "ISP" :
["N/A", "N/A"] } )
isp_names = { '1.1.1.1' : 'ABC', '2.2.2.2' : 'XYZ' }
i = 0
for row in df.rows():
for ip, isp in isp_names.items():
if(row[0] == ip):
df[i, 'ISP'] = isp #**This line gives the Value error**
i = i + 1
看起来您可能正在尝试更新 DataFrame 的值,特别是在缺少值的情况下(“N/A”值)。
join
来达到你的目的,而不是使用字典和for循环。 使用 for 循环“非常”慢,应该避免。 相比之下,左 join
的性能非常好,并且正是针对这些类型的情况而构建的。我们将逐步采取这一措施。
首先,让我们先扩展您的示例。
df = pl.DataFrame(
{"IP": ["1.1.1.1", "2.2.2.2", "3.3.3.3", "4.4.4.4"],
"ISP": ["N/A", "N/A", "PQR", "N/A"]}
)
df
shape: (4, 2)
┌─────────┬─────┐
│ IP ┆ ISP │
│ --- ┆ --- │
│ str ┆ str │
╞═════════╪═════╡
│ 1.1.1.1 ┆ N/A │
│ 2.2.2.2 ┆ N/A │
│ 3.3.3.3 ┆ PQR │
│ 4.4.4.4 ┆ N/A │
└─────────┴─────┘
请注意,我们有三行具有“N/A”值,但一行已经具有有效值“PQR”。
接下来,让我们将更新的 ISP 值的字典转换为 DataFrame,以便我们可以连接两个 DataFrame。
isp_df = pl.DataFrame(
data=[[key, value] for key, value in isp_names.items()],
schema=["IP", "ISP_updated"],
orient="row",
)
isp_df
shape: (2, 2)
┌─────────┬─────────────┐
│ IP ┆ ISP_updated │
│ --- ┆ --- │
│ str ┆ str │
╞═════════╪═════════════╡
│ 1.1.1.1 ┆ ABC │
│ 2.2.2.2 ┆ XYZ │
└─────────┴─────────────┘
现在,我们只需
join
两个 DataFrame。
how="left"
确保我们保留 df
中的所有行,即使 isp_df
中没有对应的行。df.join(isp_df, on="IP", how="left")
shape: (4, 3)
┌─────────┬─────┬─────────────┐
│ IP ┆ ISP ┆ ISP_updated │
│ --- ┆ --- ┆ --- │
│ str ┆ str ┆ str │
╞═════════╪═════╪═════════════╡
│ 1.1.1.1 ┆ N/A ┆ ABC │
│ 2.2.2.2 ┆ N/A ┆ XYZ │
│ 3.3.3.3 ┆ PQR ┆ null │
│ 4.4.4.4 ┆ N/A ┆ null │
└─────────┴─────┴─────────────┘
注意
null
中的
ISP_updated
值。 在这些情况下,您没有特定 IP
值的更新值。为了完成该过程,对于 fill_null
没有特定
ISP
值的更新的情况,我们使用 ISP_updated
将值从 isp_df
列复制到 IP
列。(
df
.join(isp_df, on="IP", how="left")
.with_columns(
pl.col("ISP_updated").fill_null(pl.col("ISP"))
)
)
shape: (4, 3)
┌─────────┬─────┬─────────────┐
│ IP ┆ ISP ┆ ISP_updated │
│ --- ┆ --- ┆ --- │
│ str ┆ str ┆ str │
╞═════════╪═════╪═════════════╡
│ 1.1.1.1 ┆ N/A ┆ ABC │
│ 2.2.2.2 ┆ N/A ┆ XYZ │
│ 3.3.3.3 ┆ PQR ┆ PQR │
│ 4.4.4.4 ┆ N/A ┆ N/A │
└─────────┴─────┴─────────────┘
现在,您的
ISP_updated
列包含每个 ISP 的更新值。 如果需要,您可以删除并重命名列,以便最后一列标记为
ISP
。(
df
.join(isp_df, on="IP", how="left")
.with_columns(
pl.col("ISP_updated").fill_null(pl.col("ISP"))
)
.drop("ISP")
.rename({"ISP_updated": "ISP"})
)
shape: (4, 2)
┌─────────┬─────┐
│ IP ┆ ISP │
│ --- ┆ --- │
│ str ┆ str │
╞═════════╪═════╡
│ 1.1.1.1 ┆ ABC │
│ 2.2.2.2 ┆ XYZ │
│ 3.3.3.3 ┆ PQR │
│ 4.4.4.4 ┆ N/A │
└─────────┴─────┘
随着 DataFrame 的大小变大,您肯定会希望避免使用 for 循环。 使用
join
将会
远远更快。
我还可以建议对代码进行两项改进,其中第二项改进可以完全避免您遇到的问题吗?
首先,一个更Pythonic的版本:
df = pl.DataFrame( {"IP": ['1.1.1.1', '2.2.2.2'],
"ISP": ["N/A", "N/A"] } )
isp_names = { '1.1.1.1' : 'ABC', '2.2.2.2' : 'XYZ' }
for i, row in enumerate(df.rows()):
df[i, 'ISP'] = isp_names[row[0]]
即,使用
enumerate
来保持
i
与 row
对齐,并且不要单独循环 isp_names
而是简单地通过键获取值。其次,Polars 有一个优秀的 表达式系统,这意味着你不必预先分配 ISP
列或编写循环:
df = pl.DataFrame( { "IP": ['1.1.1.1', '2.2.2.2']})
isp_names = { '1.1.1.1' : 'ABC', '2.2.2.2' : 'XYZ' }
df.with_column(pl.col("IP").map_elements(isp_names.get).alias("ISP"))
返回
df
为:
shape: (2, 2)
┌─────────┬─────┐
│ IP ┆ ISP │
│ --- ┆ --- │
│ str ┆ str │
╞═════════╪═════╡
│ 1.1.1.1 ┆ ABC │
│ 2.2.2.2 ┆ XYZ │
└─────────┴─────┘