寻找用于pandas数据帧的内置,可逆,列表接受列表构造函数/解构函数对

时间:2014-09-11 15:07:48

标签: pandas

是否有内置的方法从Python列表中构建/解构数据帧?

对于我正在寻找的构造函数(我现在称之为make_df),我希望能够从文字值(包括任意类型的列)中编写数据帧的初始化,以易于理解的形式,如下所示:

df = make_df([[9.75,   1],
              [6.375,  2],
              [9.,     3],
              [0.25,   1],
              [1.875,  2],
              [3.75,   3],
              [8.625,  1]],
             ['d', 'i'])

对于解构函数,我希望从数据框df中恢复需要传递给此类make_df以重新创建df的参数。

AFAIK,

  1. officially至少,pandas.DataFrame构造函数只接受一个numpy ndarray,一个dict或另一个DataFrame(而不是一个简单的Python list of of lists)作为它的第一个参数;
  2. pandas.DataFrame.values属性不保留原始数据类型。
  3. 我可以使用自己的函数来执行此操作(例如,见下文),但我更倾向于坚持使用内置方法(如果可用)。 (Pandas API非常大,有些名称不是我所期望的,所以我很可能错过了其中一个或两个函数。)


    FWIW,下面是我上面描述的手卷版本,经过最低限度的测试。 (我怀疑它是否能够处理所有可能的角落案例。)

    import pandas as pd
    import collections as co
    import pandas.util.testing as pdt
    
    def make_df(values, columns):
        return pd.DataFrame(co.OrderedDict([(columns[i],
                                             [row[i] for row in values])
                                            for i in range(len(columns))]))
    
    def unmake_df(dataframe):
        columns = list(dataframe.columns)
        return ([[dataframe[c][i] for c in columns] for i in dataframe.index],
                columns)
    
    values = [[9.75,   1],
              [6.375,  2],
              [9.,     3],
              [0.25,   1],
              [1.875,  2],
              [3.75,   3],
              [8.625,  1]]
    columns = ['d', 'i']
    
    df = make_df(values, columns)
    

    以上是make_df上面调用的输出结果:

    >>> df
           d  i
    0  9.750  1
    1  6.375  2
    2  9.000  3
    3  0.250  1
    4  1.875  2
    5  3.750  3
    6  8.625  1
    

    简单检查往返 1

    >>> df == make_df(*unmake_df(df))
    True
    >>> (values, columns) == unmake_df(make_df(*(values, columns)))
    True
    

    顺便说一句,这是原始值类型丢失的一个例子:

    >>> df.values
    array([[ 9.75 ,  1.   ],
           [ 6.375,  2.   ],
           [ 9.   ,  3.   ],
           [ 0.25 ,  1.   ],
           [ 1.875,  2.   ],
           [ 3.75 ,  3.   ],
           [ 8.625,  1.   ]])
    

    注意第二列中的值不再是原始的整数。

    因此,

    >>> df == make_df(df.values, columns)
    False
    

    1 为了能够使用==测试上面数据帧之间的相等性,我采用了一点猴子修补:

    def pd_DataFrame___eq__(self, other):
        try:
            pdt.assert_frame_equal(self, other,
                                   check_index_type=True,
                                   check_column_type=True,
                                   check_frame_type=True)
        except:
            return False
        else:
            return True
    
    pd.DataFrame.__eq__ = pd_DataFrame___eq__
    

    如果没有这个hack,dataframe_0 == dataframe_1形式的表达式将评估数据框对象,而不是简单的布尔值。

1 个答案:

答案 0 :(得分:1)

我不确定您正在阅读哪些文档,因为您明确指出的链接表示默认构造函数接受其他类似列表的对象(其中一个是列表列表)。 / p>

In [6]: pandas.DataFrame([['a', 1], ['b', 2]])
Out[6]: 
   0  1
0  a  1
1  b  2

[2 rows x 2 columns]

In [7]: t = pandas.DataFrame([['a', 1], ['b', 2]])

In [8]: t.to_dict()
Out[8]: {0: {0: 'a', 1: 'b'}, 1: {0: 1, 1: 2}}

请注意,我最后使用to_dict,而不是尝试取回原始列表列表。这是因为返回列表参数是一个不合适的问题(除非你制作一个过度的装饰器或者实际存储构造函数被调用的有序参数的东西)。

原因是pandas DataFrame默认情况下不是有序数据结构,至少在列维度中。您可以在构造时置换列数据的顺序,然后您将获得“相同”的DataFrame。

由于两个DataFrame之间可能存在许多不同的相等概念(例如,相同的列甚至包括类型,或者只是相同的命名列,或者某些列和相同的顺序,或者只是混合顺序中的相同列等) - pandas默认试图成为最不具体的(Python的最小惊讶原则)。

因此,为了将DataFrame返回到其参数的目的,选择过于特定的相等概念对于默认或内置构造函数来说不是一个好的设计。

出于这个原因,使用to_dict会更好,因为生成的密钥将对列信息进行编码,您可以选择检查列类型或排序,但是您可以选择自己的应用程序。你甚至可以通过迭代dict来丢弃密钥,如果你真的想要,只需将内容泵入列表列表。

换句话说,因为列中的顺序可能不重要,所以list-of-list构造函数的“inverse”向后映射到一个更大的集合,即同一列的所有排列数据。因此,在没有假设更多结构的情况下,你所寻找的逆是没有明确定义 - 而DataFrame的临时用户可能不想或不需要做出那些额外的假设来获得可逆性。

如其他地方所述,您应该使用DataFrame.equals在DataFrames之间进行相等性检查。该函数有许多选项,允许您指定对您的应用程序有意义的特定类型的相等测试,同时将默认版本保留为合理通用的选项集。