如何根据计算将多列添加到数据框
How to add multiple columns to a dataframe based on calculations
我有一个 csv 数据集(行数 > 800 万),我将其加载到数据框中。 csv 包含如下列:
...,started_at,ended_at,...
2022-04-01 18:23:32,2022-04-01 22:18:15
2022-04-02 01:16:34,2022-04-02 02:18:32
...
我能够将数据集加载到我的数据框中,但随后我需要为每一行向数据框中添加多个计算列。换句话说,与 不同,我不希望新列的行具有相同的初始值(col 1 所有 NAN,col 2,所有“dogs”等)。
现在,我可以通过执行以下操作来添加我的专栏:
df['start_time'] = df.apply(lambda row: add_start_time(row['started_at']), axis = 1)
df['start_cat'] = df.apply(lambda row: add_start_cat(row['start_time']), axis = 1)
df['is_dark'] = df.apply(lambda row: add_is_dark(row['started_at']), axis = 1)
df['duration'] = df.apply(lamba row: calc_dur(row'[started_at'],row['ended_at']), axis = 1)
但它似乎效率低下,因为整个数据集被处理 N 次(每次调用一次)。
看来我应该能够一次性计算出所有新列,但我缺少一些概念性方法。
示例:
def calc_dur(started_at, ended_at):
# started_at, ended_at are datetime64[ns]; converted at csv load
diff = ended_at - started_at
return diff.total_seconds() / 60
def add_start_time(started_at):
# started_at is datetime64[ns]; converted at csv load
return started_at.time()
def add_is_dark(started_at):
# tz is pytz.timezone('US/Central')
# chi_town is the astral lookup for Chicago
st = started_at.replace(tzinfo=TZ)
chk = sun(chi_town.observer, date=st, tzinfo=chi_town.timezone)
return st >= chk['dusk'] or st <= chk['dawn']
更新 1
根据 MoRe 的信息,我能够进行必要的工作。我需要通过添加 column
名称来扩充,然后使用合并来指定索引。
data = pd.Series(df.apply(lambda x: [
add_start_time(x['started_at']),
add_is_dark(x['started_at']),
yrmo(x['year'], x['month']),
calc_duration_in_minutes(x['started_at'], x['ended_at']),
add_start_cat(x['started_at'])
], axis = 1))
new_df = pd.DataFrame(data.tolist(),
data.index,
columns=['start_time','is_dark','yrmo',
'duration','start_cat'])
df = df.merge(new_df, left_index=True, right_index=True)
import pandas as pd
data = pd.Series(dataframe.apply(lambda x: [function1(x[column_name]), function2(x[column_name)], function3(x[column_name])], axis = 1))
pd.DataFrame(data.tolist(),data.index)
如果我没看错你的意思,这就是你的答案。但在一切之前请使用 Swifter pip :)
首先按列表创建一个系列并将其转换为列...
swifter 是一个简单的库(至少我认为它很简单),只有一个有用的方法:apply
import swifter
data.swifter.apply(lambda x: x+1)
它使用并行方式来提高大型数据集的速度...在小型数据集中,它不是很好,甚至更糟
我有一个 csv 数据集(行数 > 800 万),我将其加载到数据框中。 csv 包含如下列:
...,started_at,ended_at,...
2022-04-01 18:23:32,2022-04-01 22:18:15
2022-04-02 01:16:34,2022-04-02 02:18:32
...
我能够将数据集加载到我的数据框中,但随后我需要为每一行向数据框中添加多个计算列。换句话说,与
现在,我可以通过执行以下操作来添加我的专栏:
df['start_time'] = df.apply(lambda row: add_start_time(row['started_at']), axis = 1)
df['start_cat'] = df.apply(lambda row: add_start_cat(row['start_time']), axis = 1)
df['is_dark'] = df.apply(lambda row: add_is_dark(row['started_at']), axis = 1)
df['duration'] = df.apply(lamba row: calc_dur(row'[started_at'],row['ended_at']), axis = 1)
但它似乎效率低下,因为整个数据集被处理 N 次(每次调用一次)。
看来我应该能够一次性计算出所有新列,但我缺少一些概念性方法。
示例:
def calc_dur(started_at, ended_at):
# started_at, ended_at are datetime64[ns]; converted at csv load
diff = ended_at - started_at
return diff.total_seconds() / 60
def add_start_time(started_at):
# started_at is datetime64[ns]; converted at csv load
return started_at.time()
def add_is_dark(started_at):
# tz is pytz.timezone('US/Central')
# chi_town is the astral lookup for Chicago
st = started_at.replace(tzinfo=TZ)
chk = sun(chi_town.observer, date=st, tzinfo=chi_town.timezone)
return st >= chk['dusk'] or st <= chk['dawn']
更新 1
根据 MoRe 的信息,我能够进行必要的工作。我需要通过添加 column
名称来扩充,然后使用合并来指定索引。
data = pd.Series(df.apply(lambda x: [
add_start_time(x['started_at']),
add_is_dark(x['started_at']),
yrmo(x['year'], x['month']),
calc_duration_in_minutes(x['started_at'], x['ended_at']),
add_start_cat(x['started_at'])
], axis = 1))
new_df = pd.DataFrame(data.tolist(),
data.index,
columns=['start_time','is_dark','yrmo',
'duration','start_cat'])
df = df.merge(new_df, left_index=True, right_index=True)
import pandas as pd
data = pd.Series(dataframe.apply(lambda x: [function1(x[column_name]), function2(x[column_name)], function3(x[column_name])], axis = 1))
pd.DataFrame(data.tolist(),data.index)
如果我没看错你的意思,这就是你的答案。但在一切之前请使用 Swifter pip :) 首先按列表创建一个系列并将其转换为列...
swifter 是一个简单的库(至少我认为它很简单),只有一个有用的方法:apply
import swifter
data.swifter.apply(lambda x: x+1)
它使用并行方式来提高大型数据集的速度...在小型数据集中,它不是很好,甚至更糟