Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在索引和插入行时防止强制数据帧_Python_Pandas_Coercion - Fatal编程技术网

Python 在索引和插入行时防止强制数据帧

Python 在索引和插入行时防止强制数据帧,python,pandas,coercion,Python,Pandas,Coercion,我正在处理pandas数据帧的各个行,但在索引和插入行时,我遇到了强制问题。Pandas似乎总是想将混合int/float强制为所有float类型,我看不到对这种行为有任何明显的控制 例如,这里是一个简单的数据框,其中a为int,b为float: import pandas as pd pd.__version__ # '0.25.2' df = pd.DataFrame({'a': [1], 'b': [2.2]}) print(df) # a b # 0 1 2.2 pr

我正在处理pandas数据帧的各个行,但在索引和插入行时,我遇到了强制问题。Pandas似乎总是想将混合int/float强制为所有float类型,我看不到对这种行为有任何明显的控制

例如,这里是一个简单的数据框,其中
a
int
b
float

import pandas as pd
pd.__version__  # '0.25.2'

df = pd.DataFrame({'a': [1], 'b': [2.2]})
print(df)
#    a    b
# 0  1  2.2
print(df.dtypes)
# a      int64
# b    float64
# dtype: object
索引一行时存在强制问题:

print(df.loc[0])
# a    1.0
# b    2.2
# Name: 0, dtype: float64
print(dict(df.loc[0]))
# {'a': 1.0, 'b': 2.2}
df.loc[1] = {'a': 5, 'b': 4.4}
print(df)
#      a    b
# 0  1.0  2.2
# 1  5.0  4.4
print(df.dtypes)
# a    float64
# b    float64
# dtype: object
这里是插入一行时的强制问题:

print(df.loc[0])
# a    1.0
# b    2.2
# Name: 0, dtype: float64
print(dict(df.loc[0]))
# {'a': 1.0, 'b': 2.2}
df.loc[1] = {'a': 5, 'b': 4.4}
print(df)
#      a    b
# 0  1.0  2.2
# 1  5.0  4.4
print(df.dtypes)
# a    float64
# b    float64
# dtype: object

在这两种情况下,我都希望
a
列保持为整数类型,而不是强制为浮点类型。

经过一些挖掘,下面是一些非常糟糕的解决方法。(我们会接受更好的答案。)

一个怪癖是非数字列会停止强制,因此下面是如何将一行索引到
dict

dict(df.assign(_='').loc[0].drop('_', axis=0))
# {'a': 1, 'b': 2.2}
通过创建一个包含一行的新数据框,可以插入一行:

df = df.append(pd.DataFrame({'a': 5, 'b': 4.4}, index=[1]))
print(df)
#    a    b
# 0  1  2.2
# 1  5  4.4

这两个技巧都不是针对大数据帧优化的,因此我非常希望有更好的答案

问题的根源在于

  • 熊猫数据帧的索引返回熊猫系列
  • 我们可以看到:

    type(df.loc[0])
    # pandas.core.series.Series
    
    并且一个系列只能有一个数据类型,在您的例子中是int64或float64

    我想到了两个解决办法:

    print(df.loc[[0]])
    # this will return a dataframe instead of series
    # so the result will be
    #    a    b
    # 0  1  2.2
    
    # but the dictionary is hard to read
    print(dict(df.loc[[0]]))
    # {'a': 0    1
    # Name: a, dtype: int64, 'b': 0    2.2
    # Name: b, dtype: float64}
    

  • 将字典附加到数据帧时,它将首先将字典转换为系列,然后再附加。(所以同样的问题再次发生)
  • 因此,您的漫游实际上是一个坚实的漫游,否则我们可以:

    df.append(pd.Series({'a': 5, 'b': 4.4}, dtype=object, name=1))
    #    a    b
    # 0  1  2.2
    # 1  5  4.4
    

    在第一种情况下,您可以使用。序列选择不会强制为
    浮点
    ,值被放置在
    对象
    容器中。然后正确创建字典,并将基础值存储为
    np.int64

    df = pd.DataFrame({'a': [1], 'b': [2.2]})
    df['a'] = df['a'].astype('Int64')
    
    d = dict(df.loc[0])
    #{'a': 1, 'b': 2.2}
    
    type(d['a'])
    #numpy.int64
    
    对于您的语法,这几乎也适用于第二种情况,但这会向上转换到
    对象
    ,所以不太好:

    df.loc[1] = {'a': 5, 'b': 4.4}
    #   a    b
    #0  1  2.2
    #1  5  4.4
    
    df.dtypes
    #a     object
    #b    float64
    #dtype: object
    
    但是,我们可以对在末尾添加一行(使用RangeIndex)的语法做一些小的修改,现在类型得到了正确的处理

    df = pd.DataFrame({'a': [1], 'b': [2.2]})
    df['a'] = df['a'].astype('Int64')
    
    df.loc[df.shape[0], :] = [5, 4.4]
    #   a    b
    #0  1  2.2
    #1  5  4.4
    
    df.dtypes
    #a      Int64
    #b    float64
    #dtype: object
    

    稍微进行数据操作的另一种方法:

    假设您有一个字典(或数据帧)列表

    lod=[{'a':[1],'b':[2.2]},{'a':[5],'b':[4.4]}]

    其中,每个字典表示一行(请注意第二个字典中的列表)。然后,您可以通过以下方式轻松创建数据帧:

    pd.concat([pd.DataFrame(dct) for dct in lod])
       a    b
    0  1  2.2
    0  5  4.4
    
    并维护列的类型。看

    因此,如果您有一个数据帧和一个dict列表,您可以使用

    pd.concat([df] + [pd.DataFrame(dct) for dct in lod])
    

    无论何时从数据帧获取数据或将数据附加到数据帧,并且需要保持数据类型不变,都应避免转换为不知道所需数据类型的其他内部结构

    当您执行
    df.loc[0]
    时,它会转换为

    选择需要作为帧的行,然后转换为
    dict

    >>> df.loc[[0]].to_dict(orient='records')
    [{'a': 1, 'b': 2.2}]
    
    类似地,要添加新行,请使用pandas函数

    >>> df = df.append([{'a': 5, 'b': 4.4}]) # NOTE: To append as a row, use []
       a    b
    0  1  2.2
    0  5  4.4
    
    上述操作不会导致类型转换

    >>> df.dtypes
    a      int64
    b    float64
    dtype: object
    

    我发现了,但我无法发现问题是否得到了有效解决。与此同时,我想您可以这样做:
    df.loc[[0],df.columns]
    Duplicates?&。听起来pd.DataFrame不支持实例化时的类型混合?dtype param仅支持一种类型
    .read.[type]
    支持多种数据类型,但您始终可以强制post append
    df['a']=df.a.aType(mytype)
    。。。但它仍然很脏,可能效率不高。
    .astype()
    对于float->integer是危险的;将
    1.1
    更改为
    1
    没有问题,因此在执行此操作之前,您确实需要确保所有值都是“类似整数的”。可能最好使用
    pd。要使用
    downcast='integer'
    Wow读取第二个代码块三次才能得到它。这是非常微妙的。这比我过去做的好多了。。。循环遍历最终的数据帧,并使用正确的数据类型重新分配值(是的,我所做的是一个可怕的解决方案,它确实无法扩展。)。哦。很高兴使用
    对象
    数据类型帮助了这个好主意!另一种方法是从头创建一个对象数据帧:
    df=pd.DataFrame({'a':[1],'b':[2.2]},dtype=object)
    >>> df = df.append([{'a': 5, 'b': 4.4}]) # NOTE: To append as a row, use []
       a    b
    0  1  2.2
    0  5  4.4
    
    >>> df.dtypes
    a      int64
    b    float64
    dtype: object