我有一个有效的代码,该代码迭代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 应该是{strong>房间中的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}'
谢谢您的想法!
答案 0 :(得分:2)
将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', '']
现在将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_')
您以后可以重命名列。
通过在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
,因为它会使您的操作非常缓慢。