将数据框转换为rec数组(将对象转换为字符串)

Posted

技术标签:

【中文标题】将数据框转换为rec数组(将对象转换为字符串)【英文标题】:Convert dataframe to a rec array (and objects to strings) 【发布时间】:2019-03-05 21:12:53 【问题描述】:

我有一个带有混合数据类型(dtypes)的 pandas 数据框,我希望将其转换为 numpy 结构化数组(或记录数组,在这种情况下基本相同)。对于纯数字数据帧,使用 to_records() 方法很容易做到这一点。我还需要将 pandas 列的 dtypes 转换为 strings 而不是 objects 以便我可以使用 numpy 方法 tofile() 将数字和字符串输出到二进制文件文件,但不会输出对象。

简而言之,我需要将带有 dtype=object 的 pandas 列转换为字符串或 unicode dtype 的 numpy 结构化数组。

这是一个示例,如果所有列都有数字(浮点数或整数)dtype,代码就足够了。

import pandas as pd
df=pd.DataFrame('f_num': [1.,2.,3.], 'i_num':[1,2,3], 
                 'char': ['a','bb','ccc'], 'mixed':['a','bb',1])

struct_arr=df.to_records(index=False)

print('struct_arr',struct_arr.dtype,'\n')

# struct_arr (numpy.record, [('f_num', '<f8'), ('i_num', '<i8'), 
#                            ('char', 'O'), ('mixed', 'O')]) 

但因为我想以字符串 dtype 结尾,所以我需要添加这个额外且有些涉及的代码:

lst=[]
for col in struct_arr.dtype.names:  # this was the only iterator I 
                                    # could find for the column labels
    dt=struct_arr[col].dtype

    if dt == 'O':   # this is 'O', meaning 'object'

        # it appears an explicit string length is required
        # so I calculate with pandas len & max methods
        dt = 'U' + str( df[col].astype(str).str.len().max() )
       
    lst.append((col,dt))

struct_arr = struct_arr.astype(lst)
        
print('struct_arr',struct_arr.dtype)

# struct_arr (numpy.record, [('f_num', '<f8'), ('i_num', '<i8'), 
#                            ('char', '<U3'), ('mixed', '<U2')])

另请参阅:How to change the dtype of certain columns of a numpy recarray?

这似乎有效,因为字符和混合 dtypes 现在是 &lt;U3&lt;U2 而不是 'O' 或 'object'。我只是在检查是否有更简单或更优雅的方法。但是由于 pandas 没有像 numpy 那样的原生字符串类型,也许没有?

【问题讨论】:

dt=df['mixed'].values.astype(str).dtype 为我工作。 我很想蚕食to_records,并结合您的 dtype 转换。它在列上进行迭代,并使用np.rec.fromarrays 构建数组。 你看过那个函数的代码了吗? 我认为'cannibalize'更常用于机械,例如失事的飞机,而不是编程和功能。 @hpaulj 谢谢,这是一个很好的建议,我在我自己的问题的回答中加入了。 'cannibalize'也是一个很好的用法,我刚开始没有明白这个意思。 ;-) 【参考方案1】:

据我所知,没有本机功能。例如,一个系列中所有值的最大长度不会存储在任何地方。

但是,您可以通过列表推导和 f 字符串更有效地实现您的逻辑:

data_types = [(col, arr[col].dtype if arr[col].dtype != 'O' else \
               f'Udf[col].astype(str).str.len().max()') for col in arr.dtype.names]

【讨论】:

谢谢!我讨厌检查我自己的答案,但这最终只是我需要的一半(虽然非常不错;-)【参考方案2】:

结合来自@jpp(为了简洁列出comp)和@hpaulj(为了速度而蚕食to_records)的建议,我想出了以下代码,它是更简洁的代码,也比我的原始代码快约5倍(通过扩展测试上面的示例数据框到 10,000 行):

names = df.columns
arrays = [ df[col].get_values() for col in names ]

formats = [ array.dtype if array.dtype != 'O' 
            else f'array.astype(str).dtype' for array in arrays ] 

rec_array = np.rec.fromarrays( arrays, dtype='names': names, 'formats': formats )

上面将输出 unicode 而不是字符串,这通常可能更好,但在我的情况下,我需要转换为字符串,因为我正在读取 fortran 中的二进制文件,而字符串似乎更容易读入。因此,最好将上面的“格式”行替换为:

formats = [ array.dtype if array.dtype != 'O' 
            else array.astype(str).dtype.str.replace('<U','S') for array in arrays ]

例如&lt;U4 的 dtype 变为 S4

【讨论】:

以上是关于将数据框转换为rec数组(将对象转换为字符串)的主要内容,如果未能解决你的问题,请参考以下文章

将带有 JSON 对象数组的 Spark 数据框列转换为多行

Pandas 数据框无法将列数据类型从对象转换为字符串以进行进一步操作

将 Java 结果集转换为字符串数组

如何将字符串转换为数据框

将嵌套的 mongoDB 文档转换为平面 pandas DataFrame(对象数组中的对象数组)

是否可以将字符串转换为函数对象?