在熊猫中为数据框单元格分配值时出现问题

时间:2019-04-04 10:09:53

标签: python pandas indexing

我正在组合不同的熊猫数据框,并对最终数据框的索引进行排序,我发现有些东西对我没有任何意义。它没有错误,但实际上没有分配。我在下面给出一个简化的例子

情况1:

import pandas as pd


ind_1 = ['a','a','b','c','c']
df_1 = pd.DataFrame(index=ind_1,columns=['col1','col2'])

df_1.col1.loc['a'].iloc[0] = 1
df_1.col1.loc['b'] = 2
df_1.col1.loc['c'].iloc[0] = 3

print('Original df_1')
print(df_1)

# Original df_1
#   col1 col2
# a    1  NaN
# a  NaN  NaN
# b    2  NaN
# c    3  NaN
# c  NaN  NaN

您可以看到此分配工作正常。但是,让我们根据排序不同的索引创建数据框。

ind_1_sorted = sorted(ind_1,reverse=True)
df_1_sorted = pd.DataFrame(index=ind_1_sorted,columns=['col1','col2'])

df_1_sorted.col1.loc['a'].iloc[0] = 1
df_1_sorted.col1.loc['b'] = 2
df_1_sorted.col1.loc['c'].iloc[0] = 3

print('Sorted df_1')
print(df_1_sorted)

# Sorted df_1
#  col1 col2
# c  NaN  NaN
# c  NaN  NaN
# b    2  NaN
# a  NaN  NaN
# a  NaN  NaN

现在您可以看到分配仅适用于非重复索引。我认为问题必须与排序有关,但让我们看看下一种情况。

情况2:

ind_2 = ['c','c','b','a','a']
df_2 = pd.DataFrame(index=ind_2,columns=['col1','col2'])

df_2.col1.loc['a'].iloc[0] = 1
df_2.col1.loc['b'] = 2
df_2.col1.loc['c'].iloc[0] = 3

print('Original df_2')
print(df_2)

# Original df_2
#  col1 col2
# c  NaN  NaN
# c  NaN  NaN
# b    2  NaN
# a  NaN  NaN
# a  NaN  NaN

现在,如果不执行排序,我们将无法获得分配。让我们看看如果对索引进行排序

ind_2_sorted = sorted(ind_2,reverse=False)
df_2_sorted = pd.DataFrame(index=ind_2_sorted,columns=['col1','col2'])

df_2_sorted.col1.loc['a'].iloc[0] = 1
df_2_sorted.col1.loc['b'] = 2
df_2_sorted.col1.loc['c'].iloc[0] = 3

print('Sorted df_2')
print(df_2_sorted)

# Sorted df_2
#   col1 col2
# a    1  NaN
# a  NaN  NaN
# b    2  NaN
# c    3  NaN
# c  NaN  NaN

现在,分配工作在排序后生效!!我看到的唯一区别是,当索引以“标准方式”(在这种情况下按字母顺序)排序时,赋值有效。有什么意义吗?

如果解决方案是先使用按字母顺序排序的索引,然后按所需顺序对其进行排序,那么如何像这些示例中那样使用重复索引进行排序?

谢谢!

1 个答案:

答案 0 :(得分:2)

正如Quickbeam2k1用户所说,问题是由于链分配引起的。

索引对象具有一种称为get_loc的方法,可用于将标签转换为位置,但是它的返回类型是多态的,这就是为什么我不喜欢使用它的原因。

使用np.nonzero并过滤数据框的索引和列,我们可以将标签转换为位置引用,并使用iloc而不是loc

修改数据框。

即您的第一个代码示例可以重写为:

# original
df_1.col1.loc['a'].iloc[0] = 1
df_1.col1.loc['b'] = 2
df_1.col1.loc['c'].iloc[0] = 3

# works for all indices
col1_mask = df_1.columns == 'col1'
a_mask, = np.nonzero(df_1.index == 'a')
b_mask, = np.nonzero(df_1.index == 'b')
c_mask, = np.nonzero(df_1.index == 'c')
df_1.iloc[a_mask[0], col1_mask] = 1
df_1.iloc[b_mask, col1_mask] = 1
df_1.iloc[c_mask[0], col1_mask] = 3

与其他示例类似