向量化 pandas 次迭代
Vectorizing pandas iteration
我有一个工作代码,它迭代 df
和 returns return other_df
。我正在尝试对其进行矢量化,因为它很慢。我正在尝试创建 func
到 df.apply(func)
。
生成的数据帧长度更长,这就是为什么我似乎需要 return 另一个数据帧作为 .apply
.
的结果
我的初始 df
是 公寓 的列表,其中包含 列表 的列 rooms 及其属性。
每一行都包含这样的内容:
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
覆盖到多索引中,而不是将 table.
我的代码草稿如下所示:
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}'
谢谢你的想法!
将您的 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)
Try not to use df.apply
if you have a big dataframe because it will make your operation really slow.
我有一个工作代码,它迭代 df
和 returns return other_df
。我正在尝试对其进行矢量化,因为它很慢。我正在尝试创建 func
到 df.apply(func)
。
生成的数据帧长度更长,这就是为什么我似乎需要 return 另一个数据帧作为 .apply
.
我的初始 df
是 公寓 的列表,其中包含 列表 的列 rooms 及其属性。
每一行都包含这样的内容:
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
覆盖到多索引中,而不是将 table.
我的代码草稿如下所示:
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}'
谢谢你的想法!
将您的
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)
Try not to use
df.apply
if you have a big dataframe because it will make your operation really slow.