Переключение на многорядный индекс в фрейме данных, созданном в форме списка списков

#python #pandas #list

#python #pandas #Список

Вопрос:

У меня есть функция, которая создает DataFrame из списка списков:

 def logs_reader():
    path = Path("C:\Users\"   getpass.getuser()   "\DCBviz\logs\")

cols1 = ['Station ID', 'Reciever type', 'Satellite system', 'Date installed', 'Date removed']
cols2 = ['Station ID', 'Antenna type', 'Cable length', 'Date installed', 'Date removed']

file_list = [f for f in path.glob('**/*.log') if f.is_file()]
receivers_data = []
antennas_data = []
for file in file_list:
    with open(file, encoding='utf8') as f:
        contents = f.read()
        station_id = re.findall("Four Character IDs*:s*(.*?)s*$", contents, re.MULTILINE)
        
        receiver_types = re.findall("Receiver Types*:s*(.*?)s*$", contents, re.MULTILINE)
        satellite_sys = re.findall("Satellite Systems*:s*(.*?)s*$", contents, re.MULTILINE)
        date_installed = re.findall("Date Installeds*:s*(.*?)T.*$", contents, re.MULTILINE)
        date_removed = re.findall("Date Removeds*:s*(.*?)T.*$", contents, re.MULTILINE)
        
        antenna_types = re.findall("Antenna Types*:s*(.*?)s.*$", contents, re.MULTILINE)
        cable_lengths = re.findall("Antenna Cable Lengths*:s*([0-9] .*[0-9]*)s.*$", contents, re.MULTILINE)
        antenna_date_installed = re.findall("Date Installeds*:s*(.*?)T.*$", contents, re.MULTILINE)
        antenna_date_removed = re.findall("Date Removeds*:s*(.*?)T.*$", contents, re.MULTILINE)
        
        receivers_data.append([station_id, receiver_types, satellite_sys, date_installed, date_removed])
        antennas_data.append([station_id, antenna_types, cable_lengths, antenna_date_installed, antenna_date_removed])
        
        d = []
        
        for l in receivers_data:
            d.append({'Station ID': l[0]*len(l[1]), 
                  'Reciever type': l[1], 
                  'Satellite system': l[2], 
                  'Date installed': l[3][0:len(l[1])],
                  'Date removed': l[4][0:len(l[1])]})
        df = pd.DataFrame(d)   
return df

df = logs_reader()
  

и в качестве возврата у меня есть фрейм данных, который выглядит так:
введите описание изображения здесь

и я хочу разделить списки из столбцов 2-6 и создать отдельные записи из чистых записей с Station ID в качестве многорядного индекса. Как я могу это сделать?

Желаемый результат:

введите описание изображения здесь

Комментарии:

1. Было бы очень полезно, если бы вы создали простой фрейм данных, показывающий вашу проблему и ожидаемый результат от этих простых данных.

2. Вы ищете что-то вроде df.explode , но будьте осторожны, при последовательном отображении нескольких столбцов вы получите n*m*p*q*r строки

3. Все ли списки имеют одинаковую длину? Возможно, вам было бы лучше создать отдельные dfs в вашей функции обнаружения, собрать их в dict с 'Station ID' в качестве ключей и объединить все dfs с df = pd.concat(dict.values(), keys=dict.keys())

4. Нет, они имеют разную длину

5. @RichieV итак, как мне нужно изменить эту функцию для создания отдельных dfs, как вы сказали?

Ответ №1:

Итак, у вас есть ваши данные с регулярным отображением в списках

 receiver_types 
satellite_sys 
date_installed
date_removed
    
antenna_types
cable_lengths
antenna_date_installed
antenna_date_removed
  

Теперь я предполагаю, что каждый файл соответствует ОДНОМУ station_id , но строка station_id = re.findall(... все равно вернет список.

Тогда у вас будет station_id , который представляет собой список длиной 1 и множество других списков. Если все списки получателей имеют одинаковую длину, вы можете создать df и собрать его в receivers_data с помощью приведенного ниже кода (пожалуйста, скопируйте его снова, поскольку я убрал скобки вокруг station_id ).). А затем сделайте то же самое для antennae_data .

Обратите внимание, что ваш текущий код отбрасывается df на каждой итерации и возвращает данные только из последнего прочитанного файла.


Как я упоминал в комментариях, если все списки в одной строке имеют одинаковую длину, то лучшим вариантом является создание df из каждого файла и объединение их после цикла

Вы можете заменить строку

 receivers_data.append([station_id, receiver_types, satellite_sys, date_installed, date_removed])
  

с

 receivers_data.append(
    pd.DataFrame(
        [station_id * len(receiver_types), receiver_types, satellite_sys, date_installed, date_removed],
        columns=list_of_column_names
    )
)
# or instead of a list use a dict with file_name as keys
  

После того, как вы закончите чтение всех файлов, вы можете объединить оба списка с

 df_receivers = pd.concat(receivers_data)
df_antennae = pd.concat(antennae_data)
  

Комментарии:

1. Я думаю, что есть небольшое недопонимание. Да, они имеют одинаковую длину, но после завершения второго for цикла. И я получаю df, который находится на экране.