Преобразовать фрейм данных в массив rec (и объекты в строки) - PullRequest
0 голосов
/ 30 сентября 2018

У меня есть фрейм данных pandas со смесью типов данных (dtypes), которые я хочу преобразовать в простой массив (или массив записей, в основном это одно и то же в этом случае).Для чисто числовых фреймов данных это легко сделать с помощью метода to_records().Мне также нужно, чтобы dtypes столбцов панд были преобразованы в строки , а не объекты , чтобы я мог использовать метод numpy tofile(), который будет выводить числа и строки в двоичный файл,но не будет выводить объекты.

В двух словах, мне нужно преобразовать столбцы панд с dtype=object в пустые структурированные массивы строки или типа unicode.

ВотНапример, с кодом, который был бы достаточен, если бы все столбцы имели числовой тип (float или int) dtype.

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')]) 

Но так как я хочу получить строковые dtypes, мне нужно добавить это дополнительное и несколько сложноекод:

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')])

См. также: Как изменить dtype некоторых столбцов числового повторного массива?

Это работает, как символ и смешанные dtypes.теперь <U3 и <U2, а не 'O' или 'object'.Я просто проверяю, есть ли более простой или более элегантный подход.Но поскольку у панд нет собственного типа строки, как у numpy, может быть, нет?

Ответы [ 2 ]

0 голосов
/ 11 октября 2018

Объединяя предложения от @jpp (список компов для краткости) и @hpaulj (каннибализировать to_records для скорости), я придумал следующее: более чистый код, а также примерно в 5 раз быстрее, чем мой исходный код (проверено расширениемприведенный выше примерный кадр данных (до 10000 строк):

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, а не строк, что, вероятно, в целом лучше, но в моем случае мне нужно преобразовать в строки, потому что я читаю двоичный файлв Фортране и строки, кажется, читать легче.Следовательно, может быть лучше заменить строку "форматов" выше на эту:

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

Например, dtype <U4 становится S4.

0 голосов
/ 30 сентября 2018

Насколько я знаю, для этого нет встроенной функциональности.Например, максимальная длина всех значений в серии нигде не сохраняется.

Однако вы можете более эффективно реализовать свою логику с помощью понимания списка и строк f:

data_types = [(col, arr[col].dtype if arr[col].dtype != 'O' else \
               f'U{df[col].astype(str).str.len().max()}') for col in arr.dtype.names]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...