使用索引设置 pandas DataFrame 中特定单元格的值

2024-12-12 08:40:00
admin
原创
146
摘要:问题描述:我已经创建了一个 Pandas DataFramedf = DataFrame(index=['A','B','C'], columns=['x','y']) 现在,我想为特定单元格(例如 rowC和 column )分配一个值x。换句话说,我想执行以下转换: x y ...

问题描述:

我已经创建了一个 Pandas DataFrame

df = DataFrame(index=['A','B','C'], columns=['x','y'])

现在,我想为特定单元格(例如 rowC和 column )分配一个值x。换句话说,我想执行以下转换:

     x    y             x    y
A  NaN  NaN        A  NaN  NaN
B  NaN  NaN   ⟶   B  NaN  NaN
C  NaN  NaN        C   10  NaN

使用以下代码:

df.xs('C')['x'] = 10

但是,的内容df没有改变。数据框再次仅包含NaNs。我该怎么做?


解决方案 1:

RukTech 的答案比df.set_value('C', 'x', 10)我下面建议的选项快得多。但是,它已被列入弃用名单

展望未来,推荐的方法是.iat/.at


为什么df.xs('C')['x']=10不工作:

df.xs('C')默认情况下,返回一个带有数据副本的新数据框,因此

df.xs('C')['x']=10

仅修改这个新的数据框。

df['x']返回数据框的视图df,因此

df['x']['C'] = 10

修改df自身。

警告:有时很难预测操作是否返回副本或视图。因此,文档建议避免使用“链式索引”进行分配。


因此建议的替代方案是

df.at['C', 'x'] = 10

确实修改了df


In [18]: %timeit df.set_value('C', 'x', 10)
100000 loops, best of 3: 2.9 µs per loop

In [20]: %timeit df['x']['C'] = 10
100000 loops, best of 3: 6.31 µs per loop

In [81]: %timeit df.at['C', 'x'] = 10
100000 loops, best of 3: 9.2 µs per loop

解决方案 2:

更新:该.set_value方法将被弃用。.iat/.at是很好的替代品,不幸的是熊猫提供的文档很少


最快的方法是使用set_value。此方法比方法快约 100 倍.ix。例如:

df.set_value('C', 'x', 10)

解决方案 3:

您还可以使用条件查找,.loc如下所示:

df.loc[df[<some_column_name>] == <condition>, [<another_column_name>]] = <value_to_add>

其中<some_column_name是您要检查<condition>变量的列,<another_column_name>是您要添加的列(可以是新列或已经存在的列)。<value_to_add>是您要添加到该列/行的值。

这个例子并不完全适用于当前的问题,但对于想要根据条件添加特定值的人来说可能很有用。

解决方案 4:

尝试使用df.loc[row_index,col_indexer] = value

解决方案 5:

设置值的推荐方法(根据维护人员的说法)是:

df.ix['x','C']=10

使用“链式索引”(df['x']['C'])可能会导致问题。

看:

解决方案 6:

这是唯一对我有用的东西!

df.loc['C', 'x'] = 10

详细了解.loc 这里。

解决方案 7:

要设置值,请使用:

df.at[0, 'clm1'] = 0
  • 推荐的最快设置变量的方法。

  • set_valueix已被弃用。

  • 没有警告,不像ilocloc

解决方案 8:

我建议:

df.loc[index_position, "column_name"] = some_value

要同时修改多个单元格:

df.loc[start_idx_pos: End_idx_pos, "column_name"] = some_value

解决方案 9:

.iat/.at是一个很好的解决方案。假设您有这个简单的 data_frame:

   A   B   C
0  1   8   4 
1  3   9   6
2  22 33  52

如果我们想修改单元格的值,[0,"A"]可以使用以下解决方案之一:

  1. df.iat[0,0] = 2

  2. df.at[0,'A'] = 2

下面是一个完整的示例,说明如何iat获取和设置单元格的值:

def prepossessing(df):
  for index in range(0,len(df)): 
      df.iat[index,0] = df.iat[index,0] * 2
  return df

y_train 之前:

    0
0   54
1   15
2   15
3   8
4   31
5   63
6   11

y_train 在调用预设函数后iat变为将每个单元格的值乘以 2:

     0
0   108
1   30
2   30
3   16
4   62
5   126
6   22

解决方案 10:

避免使用链式索引进行赋值

您正在处理带有链式索引的作业,这将导致SettingWithCopy 警告。应尽一切努力避免这种情况。

您的任务必须使用单个.loc[].iloc[]切片,如此处所述。因此,在您的情况下:

df.loc['C', 'x'] = 10

解决方案 11:

在我的示例中我只是在选定的单元格中更改它

    for index, row in result.iterrows():
        if np.isnan(row['weight']):
            result.at[index, 'weight'] = 0.0

'result' 是一个带有 'weight' 列的数据字段

解决方案 12:

以下是所有用户提供的有效解决方案的摘要,针对由整数和字符串索引的数据框。

df.ilocdf.loc适用df.at于两种类型的数据框,df.iloc仅适用于行/列整数索引,df.locdf.at支持使用列名和/或整数索引设置值。

当指定的索引不存在时,df.locdf.at都会将新插入的行/列附加到现有数据框,但df.iloc会引发"IndexError: positional indexers are out-of-bounds"。在 Python 2.7 和 3.7 中测试的工作示例如下:

import numpy as np, pandas as pd

df1 = pd.DataFrame(index=np.arange(3), columns=['x','y','z'])
df1['x'] = ['A','B','C']
df1.at[2,'y'] = 400

# rows/columns specified does not exist, appends new rows/columns to existing data frame
df1.at['D','w'] = 9000
df1.loc['E','q'] = 499

# using df[<some_column_name>] == <condition> to retrieve target rows
df1.at[df1['x']=='B', 'y'] = 10000
df1.loc[df1['x']=='B', ['z','w']] = 10000

# using a list of index to setup values
df1.iloc[[1,2,4], 2] = 9999
df1.loc[[0,'D','E'],'w'] = 7500
df1.at[[0,2,"D"],'x'] = 10
df1.at[:, ['y', 'w']] = 8000

df1
>>> df1
     x     y     z     w      q
0   10  8000   NaN  8000    NaN
1    B  8000  9999  8000    NaN
2   10  8000  9999  8000    NaN
D   10  8000   NaN  8000    NaN
E  NaN  8000  9999  8000  499.0

解决方案 13:

使用带条件索引的一种方法是首先获取满足条件的所有行的索引,然后以多种方式简单地使用这些行索引

conditional_index = df.loc[ df['col name'] <condition> ].index

示例条件如下

==5, >10 , =="Any string", >= DateTime

然后你可以用各种方式使用这些行索引,例如

  1. 替换 conditional_index 的一列值

df.loc[conditional_index , [col name]]= <new value>
  1. 替换条件索引的多个列的值

df.loc[conditional_index, [col1,col2]]= <new value>
  1. 保存conditional_index的一个好处是,你可以将一列的值分配给具有相同行索引的另一列

df.loc[conditional_index, [col1,col2]]= df.loc[conditional_index,'col name']

这一切都是可能的,因为 .index 返回一个索引数组,.loc 可以使用直接寻址,从而避免一次又一次地遍历。

解决方案 14:

您可以使用.iloc

df.iloc[[2], [0]] = 10

解决方案 15:

set_value()已被弃用。

从 0.23.4 版本开始,Pandas“宣布未来”……

>>> df
                   Cars  Prices (U$)
0               Audi TT        120.0
1 Lamborghini Aventador        245.0
2      Chevrolet Malibu        190.0
>>> df.set_value(2, 'Prices (U$)', 240.0)
__main__:1: FutureWarning: set_value is deprecated and will be removed in a future release.
Please use .at[] or .iat[] accessors instead

                   Cars  Prices (U$)
0               Audi TT        120.0
1 Lamborghini Aventador        245.0
2      Chevrolet Malibu        240.0

考虑到这个建议,这里是如何使用它们的演示:

  • 按行/列整数位置


>>> df.iat[1, 1] = 260.0
>>> df
                   Cars  Prices (U$)
0               Audi TT        120.0
1 Lamborghini Aventador        260.0
2      Chevrolet Malibu        240.0
  • 按行/列标签


>>> df.at[2, "Cars"] = "Chevrolet Corvette"
>>> df
                  Cars  Prices (U$)
0               Audi TT        120.0
1 Lamborghini Aventador        260.0
2    Chevrolet Corvette        240.0

参考:

  • pandas.DataFrame.iat

  • pandas.DataFrame.at

解决方案 16:

对 loc 和 .iloc 给出的多个答案感到沮丧,例如

df.loc[index_position, "column_name"] = some_value

因为尝试这样做时,它们会继续抛出错误或警告,例如

Must have equal len keys and value when setting with an iterable

SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame

但是,我想向遇到此问题的人澄清一下

df.at[2, "Cars"] = mystuff

消除了我的警告并且非常有效!

解决方案 17:

我测试过,输出速度df.set_value稍微快一些,但官方方法df.at看起来是最快的、非弃用的方法。

import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.rand(100, 100))

%timeit df.iat[50,50]=50 # ✓
%timeit df.at[50,50]=50 #  ✔
%timeit df.set_value(50,50,50) # will deprecate
%timeit df.iloc[50,50]=50
%timeit df.loc[50,50]=50

7.06 µs ± 118 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
5.52 µs ± 64.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
3.68 µs ± 80.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
98.7 µs ± 1.07 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
109 µs ± 1.42 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

注意,这是为单个单元格设置值。对于向量lociloc应该是更好的选择,因为它们是矢量化的。

解决方案 18:

如果想要将 df 位置 (0,0) 的单元格更改为字符串(例如'"236"76"'),则可以使用以下选项:

df[0][0] = '"236"76"'
# %timeit df[0][0] = '"236"76"'
# 938 µs ± 83.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

或者使用pandas.DataFrame.at

df.at[0, 0] = '"236"76"'
#  %timeit df.at[0, 0] = '"236"76"' 
#15 µs ± 2.09 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)

或者使用pandas.DataFrame.iat

df.iat[0, 0] = '"236"76"'
#  %timeit df.iat[0, 0] = '"236"76"'
# 41.1 µs ± 3.09 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

或者使用pandas.DataFrame.loc

df.loc[0, 0] = '"236"76"'
#  %timeit df.loc[0, 0] = '"236"76"'
# 5.21 ms ± 401 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

或者使用pandas.DataFrame.iloc

df.iloc[0, 0] = '"236"76"'
#  %timeit df.iloc[0, 0] = '"236"76"'
# 5.12 ms ± 300 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

如果时间很重要,使用pandas.DataFrame.at是最快的方法。

解决方案 19:

那么,你的问题是将 ['x',C] 处的 NaN 转换为值 10

答案是..

df['x'].loc['C':]=10
df

替代代码是

df.loc['C', 'x']=10
df

解决方案 20:

df.loc['c','x']=10这将改变第c行和
x
的值。

解决方案 21:

如果您不想更改整行的值,而只想更改某些列的值:

x = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
x.iloc[1] = dict(A=10, B=-10)

解决方案 22:

从 0.21.1 版本开始,你也可以使用方法。与这里提到的pandas .at 与 .loc.at相比,有一些区别,但在单值替换方面速度更快.loc

解决方案 23:

除了上述答案之外,这里还有一个基准,比较了向现有数据框添加数据行的不同方法。它表明,对于大型数据框,使用 at 或 set-value 是最有效的方法(至少对于这些测试条件而言)。

  • 为每一行创建新的数据框并......

+ ... 附加(13.0 秒)
+ ... 连接它(13.1 秒)
  • 首先将所有新行存储在另一个容器中,转换为新的数据框并附加...

+ 容器 = 列表的列表(2.0 秒)
+ 容器 = 列表字典(1.9 秒)
  • 预先分配整个数据框,遍历新行和所有列并使用填充

+ ... (0.6 秒)
+ ... 设置值(0.4 秒)

为了进行测试,我们使用了一个包含 100,000 行、1,000 列和随机 numpy 值的现有数据框。向此数据框添加了 100 个新行。

代码见下文:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Nov 21 16:38:46 2018

@author: gebbissimo
"""

import pandas as pd
import numpy as np
import time

NUM_ROWS = 100000
NUM_COLS = 1000
data = np.random.rand(NUM_ROWS,NUM_COLS)
df = pd.DataFrame(data)

NUM_ROWS_NEW = 100
data_tot = np.random.rand(NUM_ROWS + NUM_ROWS_NEW,NUM_COLS)
df_tot = pd.DataFrame(data_tot)

DATA_NEW = np.random.rand(1,NUM_COLS)


#%% FUNCTIONS

# create and append
def create_and_append(df):
    for i in range(NUM_ROWS_NEW):
        df_new = pd.DataFrame(DATA_NEW)
        df = df.append(df_new)
    return df

# create and concatenate
def create_and_concat(df):
    for i in range(NUM_ROWS_NEW):
        df_new = pd.DataFrame(DATA_NEW)
        df = pd.concat((df, df_new))
    return df


# store as dict and 
def store_as_list(df):
    lst = [[] for i in range(NUM_ROWS_NEW)]
    for i in range(NUM_ROWS_NEW):
        for j in range(NUM_COLS):
            lst[i].append(DATA_NEW[0,j])
    df_new = pd.DataFrame(lst)
    df_tot = df.append(df_new)
    return df_tot

# store as dict and 
def store_as_dict(df):
    dct = {}
    for j in range(NUM_COLS):
        dct[j] = []
        for i in range(NUM_ROWS_NEW):
            dct[j].append(DATA_NEW[0,j])
    df_new = pd.DataFrame(dct)
    df_tot = df.append(df_new)
    return df_tot




# preallocate and fill using .at
def fill_using_at(df):
    for i in range(NUM_ROWS_NEW):
        for j in range(NUM_COLS):
            #print("i,j={},{}".format(i,j))
            df.at[NUM_ROWS+i,j] = DATA_NEW[0,j]
    return df


# preallocate and fill using .at
def fill_using_set(df):
    for i in range(NUM_ROWS_NEW):
        for j in range(NUM_COLS):
            #print("i,j={},{}".format(i,j))
            df.set_value(NUM_ROWS+i,j,DATA_NEW[0,j])
    return df


#%% TESTS
t0 = time.time()    
create_and_append(df)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

t0 = time.time()    
create_and_concat(df)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

t0 = time.time()    
store_as_list(df)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

t0 = time.time()    
store_as_dict(df)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

t0 = time.time()    
fill_using_at(df_tot)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

t0 = time.time()    
fill_using_set(df_tot)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

解决方案 24:

您还可以更改单元格的底层数组。

values/to_numpy()返回 DataFrame 底层数组的视图,因此如果数组中的特定值发生更改,则该更改也会反映在 DataFrame 上。

df = pd.DataFrame(index=['A','B','C'], columns=['x','y'])

# change the last value in the first column
df.values[-1, 0] = 10
df.to_numpy()[-1, 0] = 10


     x    y
A  NaN  NaN
B  NaN  NaN
C   10  NaN

您还可以选择一列,查看其底层数组并通过索引更改它。即使 dtype 是扩展 Dtype,此方法也有效。

# change the last value in column 'x'
df['x'].values[-1] = 100

以最快的方式更改 DataFrame 视图(比第二快的方法快 5 倍)来设置单元格中的值,如果在循环中完成此操作,则变得有意义。

df = pd.DataFrame(index=['A', 'B', 'C'], columns=['x', 'y'])
%timeit df.values[-1, 0] = 10   # 1.89 µs ± 85.1 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
%timeit df.iat[-1, 0] = 10      # 10.9 µs ± 380 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
%timeit df.at['C', 'x'] = 10    # 13 µs ± 307 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
%timeit df.loc['C', 'x'] = 10   # 55.4 µs ± 6.16 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
%timeit df.iloc[-1, 0] = 10     # 39.7 µs ± 1.85 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

解决方案 25:

我也在搜索这个主题,并整理了一种遍历 DataFrame 并使用第二个 DataFrame 中的查找值更新它的方法。这是我的代码。

src_df = pd.read_sql_query(src_sql,src_connection)
for index1, row1 in src_df.iterrows():
    for index, row in vertical_df.iterrows():
        src_df.set_value(index=index1,col=u'etl_load_key',value=etl_load_key)
        if (row1[u'src_id'] == row['SRC_ID']) is True:
            src_df.set_value(index=index1,col=u'vertical',value=row['VERTICAL'])
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用