我已经创建了一个熊猫数据框架
df = DataFrame(index=['A','B','C'], columns=['x','y'])
得到了这个
x y
A NaN NaN
B NaN NaN
C NaN NaN
现在,我想给特定的单元格赋值,例如给C行和x列赋值。
我希望得到这样的结果:
x y
A NaN NaN
B NaN NaN
C 10 NaN
下面的代码:
df.xs('C')['x'] = 10
但是df的内容没有改变。数据帧仍然只包含nan。
有什么建议吗?
除了上面的答案之外,这里还有一个基准测试,比较了向已有的数据框架添加数据行的不同方法。它表明使用at或set-value对于大数据帧是最有效的方法(至少对于这些测试条件)。
为每一行创建新的数据框架,然后…
... 追加它(13.0 s)
... 串联它(13.1秒)
首先将所有新行存储在另一个容器中,转换为新数据帧一次,然后追加…
容器=列表的列表(2.0 s)
容器=列表字典(1.9 s)
预分配整个数据框架,遍历新行和所有列,并使用填充
... (0.6秒)
... Set_value (0.4 s)
在测试中,使用了包含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))
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
下面是所有用户提供的有效解决方案的摘要,用于以整数和字符串为索引的数据帧。
df。iloc, df。Loc和df。对于这两种类型的数据帧,df。Iloc仅适用于行/列整数索引df。Loc和df。At支持使用列名和/或整数索引设置值。
当指定的索引不存在时,df。Loc和df。At会将新插入的行/列追加到现有的数据帧,但df。iloc将引发“IndexError:位置索引器越界”。在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
除了上面的答案之外,这里还有一个基准测试,比较了向已有的数据框架添加数据行的不同方法。它表明使用at或set-value对于大数据帧是最有效的方法(至少对于这些测试条件)。
为每一行创建新的数据框架,然后…
... 追加它(13.0 s)
... 串联它(13.1秒)
首先将所有新行存储在另一个容器中,转换为新数据帧一次,然后追加…
容器=列表的列表(2.0 s)
容器=列表字典(1.9 s)
预分配整个数据框架,遍历新行和所有列,并使用填充
... (0.6秒)
... Set_value (0.4 s)
在测试中,使用了包含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))