为什么需要将地图转换为列表以将其分配给pandas系列?

Vai*_*ain 10 python python-3.x pandas

我刚开始学习大熊猫的基础知识,有一件事让我思考.

import pandas as pd
data = pd.DataFrame({'Column1': ['A', 'B', 'C']})
data['Column2'] = map(str.lower, data['Column1'])
print(data)
Run Code Online (Sandbox Code Playgroud)

该程序的输出是:

   Column1                             Column2
 0       A  <map object at 0x00000205D80BCF98>
 1       B  <map object at 0x00000205D80BCF98>
 2       C  <map object at 0x00000205D80BCF98>
Run Code Online (Sandbox Code Playgroud)

获得所需输出的一种可能解决方案是将地图对象类型转换为列表.

import pandas as pd
data = pd.DataFrame({'Column1': ['A', 'B', 'C']})
data['Column2'] = list(map(str.lower, data['Column1']))
print(data)
Run Code Online (Sandbox Code Playgroud)

输出:

   Column1 Column2
 0       A       a
 1       B       b
 2       C       c
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用range(),它也在Python 3中返回自己的类型,则无需将对象类型转换为列表.

import pandas as pd
data = pd.DataFrame({'Column1': ['A', 'B', 'C']})
data['Column2'] = range(3)
print(data)
Run Code Online (Sandbox Code Playgroud)

输出:

   Column1  Column2
 0       A        0
 1       B        1
 2       C        2
Run Code Online (Sandbox Code Playgroud)

有没有理由为什么范围对象不需要进行类型转换但是地图对象是?

Sco*_*ica 7

TL; DR: range ■找__getitem__,而且__len__,虽然map说自己是.


细节

我假设创建一个新的数据框列的语法在某种程度上是语法糖Pandas.DataFrame.insert,这需要作为一个参数value一个

标量,系列或类似数组

鉴于此,似乎问题简化为"为什么pandas将列表和范围视为类似数组,而不是地图?"

请参阅:numpy:"array_like"对象的正式定义?.

如果你尝试在一个范围之外创建一个数组,它可以正常工作,因为范围足够接近数组,但你不能用一个地图这样做.

>>> import numpy as np
>>> foo = np.array(range(10))
>>> bar = np.array(map(lambda x:x + 1,range(10))
>>> foo
array( [0,1,2,3,4,5,6,7,8,9])
>>>条形
数组(<地图对象位于0x7f7e553219e8>,dtype =对象)

map不是"阵列式",range而是.

进一步研究链接答案中引用的PyArray_GetArrayParamsFromObject,函数的结尾调用PySequence_Check.那段代码是python代码,在Stack Overflow上有一个很好的讨论:什么是Python的序列协议? .

早些时候,在同一个文件中,它说:

   /*
     * PySequence_Check detects whether an old type object is a
     * sequence by the presence of the __getitem__ attribute, and
     * for new type objects that aren't dictionaries by the
     * presence of the __len__ attribute as well. In either case it
     * is possible to have an object that tests as a sequence but
     * doesn't behave as a sequence and consequently, the
     * PySequence_GetItem call can fail. When that happens and the
     * object looks like a dictionary, we truncate the dimensions
     * and set the object creation flag, otherwise we pass the
     * error back up the call chain.
     */
Run Code Online (Sandbox Code Playgroud)

这似乎是"类似数组"的主要部分 - 任何具有getitemlen的项都是数组. range既有,map又有.

亲自尝试一下!

__getitem__并且__len__必须且足以创建序列,因此可以根据需要显示列而不是单个对象.

试试这个:

class Column(object):
    def __len__(self):
        return 5
    def __getitem__(self, index):
        if 0 <= index < 5:
            return index+5
        else:
            raise IndexError

col = Column()
a_col = np.array(col)
Run Code Online (Sandbox Code Playgroud)
  • 如果你没有__getitem__()或者__len()__,numpy将为你创建一个数组,但它将与其中的对象一起使用,并且它不会为你迭代.
  • 如果您同时具有这两种功能,则会显示您想要的方式.

(感谢user2357112纠正我.在一个稍微简单的例子中,我认为__iter__是必需的.但__getitem__事实并非如此.该函数确实需要确保索引在范围内.)