如何更新极坐标数据框

问题描述 投票:0回答:2

我想更新极地库数据框,

我用于此目的的极地语法/命令: 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 python-polars
2个回答
2
投票

看起来您可能正在尝试更新 DataFrame 的值,特别是在缺少值的情况下(“N/A”值)。

除了@jvz的建议,我建议使用左

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

将会

远远
更快。


0
投票

我还可以建议对代码进行两项改进,其中第二项改进可以完全避免您遇到的问题吗?

首先,一个更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 │
└─────────┴─────┘

	
© www.soinside.com 2019 - 2024. All rights reserved.