Итерирование панд - PullRequest
0 голосов
/ 01 марта 2019

У меня есть рабочий код, который повторяет df и возвращает return other_df.Я пытаюсь векторизовать это, поскольку это медленно.Пытаюсь создать func до df.apply(func).

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

Мой начальный df представляет собой список квартиры , которые содержат столбец списков из комнат и их свойства.

Каждая строка содержит что-то вроде этого:

rooms                 | apartment number 

[['375', 'LET', ''],  |   12345
['335', 'LET', ''],   |
['360', 'LET', ''],   |
['295', 'double', ''],|
['360', 'LET', '']]   |
__________________________________________________

Мне нужен результирующий df, такой как:

apartment number | room number | price | if let
   12345         | 12345-1     | 375   |  True
   12345         | 12345-2     | 335   |  True
   12345         | 12345-3     | 360   |  True
   12345         | 12345-4     | 295   |  False
   12345         | 12345-5     | 360   |  True

Результирующий df должен бытьdf из номеров .Во время трансформации выполняется некоторая очистка и извлечение данных, включая присвоение номера комнаты на основе индекса объекта в списке, сохраненного в начальной ячейке df, что, я не уверен, возможно ли вообще векторизовать (?)

Я считаю свои варианты более влажными, чтобы выполнить все сразу с .apply, если это возможно.Если это не так, то мне нужно покрыть начальную df в многоиндексную, а затем развернуть таблицу.

Мой черновой код выглядит следующим образом:

def rooms_df(row):
    columns=['room_price',
         'room_type',
         'en_suite',
         'if_let',
         'room_number',
         'listing_id']

df = pd.DataFrame(columns=columns)
    for room in row['rooms']:
        number=0
        if room[0] == 'na':
            room_price = None
            room_type = None
            en_suite = None
            if_let = None
        elif room[0] == 'occupied':
            room_price = None
            room_type = None
            en_suite = None
            if_let = True
        else:
            room_price = room[0]

            if 'single' in room:
                room_type = 'single'
            elif 'double' in room:
                room_type = 'double'
            else:
                room_type = None
            if 'suite' in room:
                en_suite = True
            else:
                en_suite = False

            if 'LET' in room:
                if_let = True
            else:
                if_let = False

        listing_id = row['listing_id']

        number = number+1
        room_number = f'{listing_id}-{number}'

Спасибо заваши идеи!

1 Ответ

0 голосов
/ 01 марта 2019
  1. Разделите ваш столбец rooms, который является столбцом списка списков, на отдельные строки, каждая со списком.

    df_new = pd.DataFrame(df['rooms'].tolist()) \
    .merge(df, left_index = True, right_index = True) \
    .drop('rooms', axis=1) \
    .melt(id_vars = ['apt'], value_name = 'rooms') \
    .drop('variable', axis=1)
    

    ВЫХОД:

    apt     rooms
    12345   ['375', 'LET', '']
    12345   ['335', 'LET', '']
    12345   ['360', 'LET', '']
    12345   ['295', 'double', '']
    12345   ['360', 'LET', '']
    
  2. Теперь разбейте каждый элемент в rooms на отдельные столбцы:

    df_new[['price','if_let', 'foo']] = pd.DataFrame(df_new['rooms'].values.tolist(), index=df_new.index) 
    df_new = df_new.drop(['rooms', 'foo'], axis=1)
    

    ВЫХОД:

    apt     price   if_let  
    12345   375     LET 
    12345   335     LET 
    12345   360     LET 
    12345   295     double  
    12345   360     LET 
    

    Если в вашем списке неравное количество элементов, вы можете использовать add_prefix.Это создаст новые столбцы, число которых равно максимальному размеру списков в столбце.

    pd.DataFrame(df_new['rooms'].values.tolist(), index=df_new.index).add_prefix('foo_')
    

    Вы можете переименовать столбцы позже.

  3. Создайте новый столбец для номера комнаты, сгруппировав по apt и используя cumcount:

    df_new['count'] = df_new.groupby('apt').cumcount()+1
    df_new['room_num'] = df_new['apt'].astype(str) + '-' + df_new['count'].astype(str)
    

    ВЫХОД:

    apt     price   if_let  count   room_num
    12345   375     LET     1       12345-1
    12345   335     LET     2       12345-2
    12345   360     LET     3       12345-3
    12345   295     double  4       12345-4
    12345   360     LET     5       12345-5
    

Теперь вы можете изменять столбцыкак вам нравится.Например:

df_new['if_let] = np.where(df_new['if_let'] == 'LET', True, False)

Старайтесь не использовать df.apply, если у вас большой фрейм данных, потому что это сделает вашу работу очень медленной.

...