python - pandas loc 函数在写入和读取时引用不同的行 -> ValueError

标签 python python-3.x pandas numpy

运行下面的示例代码时,我得到一个

ValueError: cannot set using a multi-index selection indexer with a different
length than the value

执行时出现错误

df.loc[(9, 0), ("clouds", "type")] = np.array([None, None])

这里:

~\Anaconda3\lib\site-packages\pandas\core\indexing.py in _setitem_with_indexer(self, indexer, value)
    492 
    493                     if len(obj[idx]) != len(value):
--> 494                         raise ValueError

问题似乎与将 numpy 数组写入数据帧的“单元格”有关。看来 obj[idx] 引用了数据帧中的索引 (20,),而它应该引用 (9,0)。执行时在引发错误的迭代之前进行几次迭代

df.loc[(6, 0), ("clouds", "type")] = np.array([None, None])

没有错误被引发,因为巧合obj[idx]引用了数据帧中的索引(17,),它有2个子索引,所以偶然len(obj[idx ])==len(值)==2.

备注:

当我阅读时

df.loc[(9, 0), ("clouds", "type")].values

它正确返回[104]

问题:

我是否错误地使用了.loc函数?我还做错了什么吗?或者这是 pandas 内部的问题?我怎样才能避免它?

我非常感谢任何帮助,因为这个问题让我困扰了几天:/

代码:

import pandas as pd
import numpy as np

mi = pd.MultiIndex(levels=[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22],
                           [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]],
                   labels=[[0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7, 8, 9, 10, 10, 11, 12, 12, 13, 14, 14,
                            14, 15, 16, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 22],
                           [0, 1, 0, 1, 2, 3, 0, 1, 2, 0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 2, 0, 0,
                            0, 1, 0, 1, 2, 0, 1, 2, 3, 0, 1, 2, 0, 1, 2, 0, 1, 2]])


mc = pd.MultiIndex(levels=[['clouds', 'group', 'header', 'vertical_visibility', 'visibility', 'weather', 'wind', 'windshear'],
                           ['', 'BR', 'DS', 'DU', 'DZ', 'FC', 'FG', 'FU', 'GR', 'GS', 'HZ', 'IC', 'PL', 'PO', 'PY', 'RA', 'SA', 'SG', 'SN', 'SQ', 'SS', 'UP', 'VA', 'altitude', 'ceiling', 'direction', 'form', 'from_date', 'from_hours', 'from_minutes', 'gust', 'icao_code', 'layer', 'more', 'origin_date', 'origin_hours', 'origin_minutes', 'probability', 'range', 'speed', 'till_date', 'till_hours', 'till_minutes', 'type', 'unit', 'valid_from_date', 'valid_from_hours', 'valid_till_date', 'valid_till_hours'],
                           ['bool', 'intensity', 'modifier']],
                   labels=[[0, 0, 0, 1, 1, 1],
                           [24, 32, 43, 27, 28, 29],
                           [-1, -1, -1, -1, -1, -1]])

arr = np.array(range(0,len(mi)*len(mc))).reshape(len(mi),len(mc))

df = pd.DataFrame(arr, index=mi, columns=mc)


values = {0: {0: [None]}, 1: {0: [None], 1: [None], 2: [None], 3: [None]}, 2: {0: [None], 2: [None]}, 3: {0: [None], 1: [None], 2: [None], 3: [None], 4: [None], 5: [None]}, 4: {0: [None]}, 6: {0: [None, None]}, 9: {0: [None, None]}}


for i, val in values.items():
    for j, v in val.items():
        df.loc[(i,j),("clouds", "type")] = np.array(v)

最佳答案

("clouds", "type", None) 列具有整数数据类型:

In [28]: df[("clouds", "type", None)].dtype
Out[28]: dtype('int64')

因此,如果要将 NumPy 数组分配给此列,请首先将 dtype 更改为 object:

df[("clouds", "type", None)] = df[("clouds", "type", None)].astype('object')

  • 使用df.atdf.iat 选择 DataFrame 的特定单元格或为其赋值。
  • 使用 df.locdf.iloc 选择列、行或子 DataFrame 或为其赋值。

因此,请在此处使用df.at:

df[("clouds", "type", None)] = df[("clouds", "type", None)].astype('object')
for i, val in values.items():
    for j, v in val.items():
        df.at[(i, j), ("clouds", "type", None)] = np.array(v)

这会产生一个 df ,看起来像

      clouds                         group                        
     ceiling layer          type from_date from_hours from_minutes
         NaN   NaN           NaN       NaN        NaN          NaN
0  0       0     1        [None]         3          4            5
   1       6     7             8         9         10           11
1  0      12    13        [None]        15         16           17
   1      18    19        [None]        21         22           23
   2      24    25        [None]        27         28           29
   3      30    31        [None]        33         34           35
2  0      36    37        [None]        39         40           41
   1      42    43            44        45         46           47
   2      48    49        [None]        51         52           53
3  0      54    55        [None]        57         58           59
   1      60    61        [None]        63         64           65
   2      66    67        [None]        69         70           71
   3      72    73        [None]        75         76           77
   4      78    79        [None]        81         82           83
   5      84    85        [None]        87         88           89
4  0      90    91        [None]        93         94           95
5  0      96    97            98        99        100          101
6  0     102   103  [None, None]       105        106          107
7  0     108   109           110       111        112          113
8  0     114   115           116       117        118          119
9  0     120   121  [None, None]       123        124          125
...

关于the comment您希望将云/类型列用于分类数据:

包含分类数据的列必须包含可哈希值。一般来说,让可变对象可哈希是没有意义的。因此,例如,Python 可变内置函数(例如列表)或 NumPy 数组是不可散列的。但 Python 不可变内置函数(例如元组)是可哈希的。因此,如果您使用

df.at[(i, j), ("clouds", "type", None)] = tuple(v)

然后您可以将 category("clouds", "type", None) 列设置为 dtype:

df[("clouds", "type", None)] = df[("clouds", "type", None)].astype('object')
for i, val in values.items():
    for j, v in val.items():
        df.at[(i, j), ("clouds", "type", None)] = tuple(v)

df[("clouds", "type", None)] = df[("clouds", "type", None)].astype('category')

注意,需要先将object列设为dtype,使其可以包含元组等Python对象,之后才转换为category dtype可能的值已被分配。


根据您想要对数据执行的操作,"tidy" the data 也可能更有意义。通过仅将字符串分配给clouds/type列并使用多行而不是元组:

例如,

6  0     102   103  'foo'       105        106          107
6  0     102   103  'bar'       105        106          107

而不是

6  0     102   103  ('foo', 'bar')       105        106          107

使用多行的一个优点是选择具有云/类型的所有行 'foo' 现在很容易:

df.loc[df[("clouds", "type", None)] == 'foo']

或选择带有 foobar cloud/type 的所有行:

df.loc[df[("clouds", "type", None)].isin(['foo', 'bar'])]

如果您使用元组,则必须使用类似的内容

df.loc[[any(kind in item for kind in ('foo', 'bar')) 
       for item in df[("clouds", "type", None)]]]

请注意,这只是更长、更难阅读,而且速度也更慢。

使用多行的一个缺点是它会创建重复的数据,这可能需要更多的内存使用。可能有解决这个问题的方法,例如使用多个表(并且仅在需要时连接它们),但对此的讨论将远远超出本问题的范围。

所以综上所述,一般来说,使用tidy data ,使用多行,并保持 DataFrame 数据类型简单——尽可能使用整数、 float ,必要时使用“字符串”。尽量避免使用元组、列表或 NumPy 数组作为 DataFrame 值。

关于python - pandas loc 函数在写入和读取时引用不同的行 -> ValueError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53262460/

相关文章:

python - 生成对应于循环值的矩阵

python - 让你的 python 代码在所有计算机上执行

python - 每个客户数据的回归

python - 基于多列值的重复键对两个大型 Pandas DataFrame 进行条件合并/连接 - Python

python - 如何在 Heroku 服务器中安装 django-auth-ldap==1.2.7?

python - 无法导入名称 ‘etree’

python - 与预期不同的输出格式

python - 计数器 : ordering elements with equal counts

python-3.x - 无法从 OpenGL_accelerate 加载 numpy_formathandler 加速器

python - 如何将基于 pandas 数据框的图形导出为 pdf?