Pandas矢量化:基于JSON个文件的累计和
Pandas vectorization: Cumulative sum based on JSON files
我正在尝试根据 DataFrame
和两个 json
文件中的值求和一个分数。我有一个最小的例子和一个最小的解决方案,但这需要以某种方式进行矢量化,因为在实际情况下有超过一百万行,运行 通过 1% 的行需要大约 40 分钟。
我的 first.json
- 文件是:
{
"variables" : {
"var_1": {
"values": [
{
"lb": 1.0,
"b_cumul": 0.04
},
{
"lb": 3.0,
"b_cumul": 0.28
}
]
},
"var_2": {
"values": [
{
"lb": 0,
"b_cumul": -0.09
},
{
"lb": 1,
"b_cumul": 0.14
},
{
"lb:": 4,
"b_cumul": 0.03
}
]
},
"var_4": {
"values": [
{
"lb": "1",
"b_cumul": 0.06
}
]
}
}
}
我的 second.json
文件是:
{
"variables" : {
"var_1": {
"values": [
{
"lb": 1.0,
"b_cumul": -0.15
},
{
"lb": 2.0,
"b_cumul": 0.06
},
{
"lb": 4.0,
"b_cumul": 0.02
},
{
"lb": 5.0,
"b_cumul": 0.15
}
]
},
"var_3": {
"values": [
{
"lb": 0.0,
"b_cumul": 0.12
},
{
"lb": 2.0,
"b_cumul": 0.25
}
]
},
"var_6": {
"values": [
{
"lb": 0.0,
"b_cumul": -0.16
},
{
"lb": 1.0,
"b_cumul": -0.06
}
]
}
}
}
这是我们的初始数据框:
import pandas as pd
# setup initial test-data
usage = ['first', 'second', 'first', 'second', 'second', 'second', 'first']
var_1 = [-1, -1, 0, 1, 3, 8, 2]
var_2 = [1, 3, -1, 0, 9, 2, 1]
var_3 = [0, 1, 0, -1, -1, 42, 3]
df = pd.DataFrame({'usage': usage, 'var_1': var_1, 'var_2': var_2, 'var_3': var_3})
var_1
、var_2
、var_3
df
中可用的变量决定了我们要在 json
- 中查看哪些变量文件。分数应该是从 json
文件中检索到的累积总和,具体取决于 df
.
中的值
查看我的第一行,我有 (var_1=-1, var_2=1, var_3=0)
。由于 usage='first'
对于同一行,我需要检查 first.json
这些变量对应的分数。 var_3
在 first.json
中不存在,所以这个变量给出 0 分。 var_1=-1
,所以这也给出了 0 分。 var_2=1
,所以这里我们需要查看 first.json
并获取对应于 <=1
的值的分数,在本例中为 -0.09+0.14=0.05
。所以我们想通过 df.loc[0, 'score_sum']=0+0-0.09+0.14
.
在数据框中添加此信息
我已经用下面的代码解决了这个问题,但是如前所述,这是非常低效的,并且不适用于更大的 df
。
import seaborn as sns
from matplotlib.pyplot import plt
import json
# return score based on given value and score ranges
def calculate_score(value: Number, score_ranges: pd.DataFrame) -> Number:
score_ranges.lb = pd.to_numeric(score_ranges.lb)
if score_ranges.lb.min() > value:
return 0
score_sum = score_ranges.loc[(score_ranges.lb <= value), 'b_cumul'].sum()
return score_sum
# read relevant data from json files
models = {key: [] for key in df['usage'].unique()}
for path in models:
f = open(f"{path}.json")
all_variables = json.load(f)['variables']
relevant_variables = [x for x in df.columns if x in all_variables]
for var in relevant_variables:
models[path].append({var: all_variables[var]['values']})
# calculate scores
df['score_sum'] = np.nan
for index, row in df.iterrows():
score = 0
m = row['usage']
for var in models[m]:
var_name = list(var)[0]
value = row[var_name]
if value == -1:
score += 0
elif value > -1:
score += calculate_score(value, pd.DataFrame(var[var_name]))
df.loc[index, 'score_sum'] = score
通过 运行 执行此代码然后打印 df
,我们注意到第一行具有预期的 score_sum=0.05
。我们在顶部 import seaborn, plt
因为我们想在最后 运行 sns.distplot(df['score_sum'])
并保存图形。
编辑:
根据要求,请参阅下面的总结果 DataFrame
的屏幕截图。澄清一下:对于第二行,usage='second'
这意味着我们使用 second.json
,但是我们在这个 json
中没有 var_2
,所以 var_2=3
将只需添加 score_sum+=0
,但 var_3=1
将添加 score_sum+=0.12
通过首先按 df['usage'].unique()
定义的 models
循环解决,并且将有等量的 json
文件。然后我们遍历 json
中的每个相关变量,然后是给定变量的每个增量值。我们在每个循环中创建掩码,并从最低值开始,因为我们想累加这些值。
df['new_scores'] = 0
for model in models:
for var in models[model]:
var_name = list(var)[0]
json_values = pd.DataFrame(var[var_name])
json_values = json_values.set_index('lb')
for value in json_values.index:
mask = (df[var_name] >= float(value)) & (df['usage'] == model)
df.loc[mask, 'new_scores'] += json_values.loc[value, 'b_cumul']
将旧解决方案中的列与新解决方案中的列进行比较时,值完全相同。对于约 600 万行的原始数据帧,它从花费约 4 小时迭代 5% 的 dataframe
,到约 70 秒到 运行 遍历整个脚本。
我正在尝试根据 DataFrame
和两个 json
文件中的值求和一个分数。我有一个最小的例子和一个最小的解决方案,但这需要以某种方式进行矢量化,因为在实际情况下有超过一百万行,运行 通过 1% 的行需要大约 40 分钟。
我的 first.json
- 文件是:
{
"variables" : {
"var_1": {
"values": [
{
"lb": 1.0,
"b_cumul": 0.04
},
{
"lb": 3.0,
"b_cumul": 0.28
}
]
},
"var_2": {
"values": [
{
"lb": 0,
"b_cumul": -0.09
},
{
"lb": 1,
"b_cumul": 0.14
},
{
"lb:": 4,
"b_cumul": 0.03
}
]
},
"var_4": {
"values": [
{
"lb": "1",
"b_cumul": 0.06
}
]
}
}
}
我的 second.json
文件是:
{
"variables" : {
"var_1": {
"values": [
{
"lb": 1.0,
"b_cumul": -0.15
},
{
"lb": 2.0,
"b_cumul": 0.06
},
{
"lb": 4.0,
"b_cumul": 0.02
},
{
"lb": 5.0,
"b_cumul": 0.15
}
]
},
"var_3": {
"values": [
{
"lb": 0.0,
"b_cumul": 0.12
},
{
"lb": 2.0,
"b_cumul": 0.25
}
]
},
"var_6": {
"values": [
{
"lb": 0.0,
"b_cumul": -0.16
},
{
"lb": 1.0,
"b_cumul": -0.06
}
]
}
}
}
这是我们的初始数据框:
import pandas as pd
# setup initial test-data
usage = ['first', 'second', 'first', 'second', 'second', 'second', 'first']
var_1 = [-1, -1, 0, 1, 3, 8, 2]
var_2 = [1, 3, -1, 0, 9, 2, 1]
var_3 = [0, 1, 0, -1, -1, 42, 3]
df = pd.DataFrame({'usage': usage, 'var_1': var_1, 'var_2': var_2, 'var_3': var_3})
var_1
、var_2
、var_3
df
中可用的变量决定了我们要在 json
- 中查看哪些变量文件。分数应该是从 json
文件中检索到的累积总和,具体取决于 df
.
查看我的第一行,我有 (var_1=-1, var_2=1, var_3=0)
。由于 usage='first'
对于同一行,我需要检查 first.json
这些变量对应的分数。 var_3
在 first.json
中不存在,所以这个变量给出 0 分。 var_1=-1
,所以这也给出了 0 分。 var_2=1
,所以这里我们需要查看 first.json
并获取对应于 <=1
的值的分数,在本例中为 -0.09+0.14=0.05
。所以我们想通过 df.loc[0, 'score_sum']=0+0-0.09+0.14
.
我已经用下面的代码解决了这个问题,但是如前所述,这是非常低效的,并且不适用于更大的 df
。
import seaborn as sns
from matplotlib.pyplot import plt
import json
# return score based on given value and score ranges
def calculate_score(value: Number, score_ranges: pd.DataFrame) -> Number:
score_ranges.lb = pd.to_numeric(score_ranges.lb)
if score_ranges.lb.min() > value:
return 0
score_sum = score_ranges.loc[(score_ranges.lb <= value), 'b_cumul'].sum()
return score_sum
# read relevant data from json files
models = {key: [] for key in df['usage'].unique()}
for path in models:
f = open(f"{path}.json")
all_variables = json.load(f)['variables']
relevant_variables = [x for x in df.columns if x in all_variables]
for var in relevant_variables:
models[path].append({var: all_variables[var]['values']})
# calculate scores
df['score_sum'] = np.nan
for index, row in df.iterrows():
score = 0
m = row['usage']
for var in models[m]:
var_name = list(var)[0]
value = row[var_name]
if value == -1:
score += 0
elif value > -1:
score += calculate_score(value, pd.DataFrame(var[var_name]))
df.loc[index, 'score_sum'] = score
通过 运行 执行此代码然后打印 df
,我们注意到第一行具有预期的 score_sum=0.05
。我们在顶部 import seaborn, plt
因为我们想在最后 运行 sns.distplot(df['score_sum'])
并保存图形。
编辑:
根据要求,请参阅下面的总结果 DataFrame
的屏幕截图。澄清一下:对于第二行,usage='second'
这意味着我们使用 second.json
,但是我们在这个 json
中没有 var_2
,所以 var_2=3
将只需添加 score_sum+=0
,但 var_3=1
将添加 score_sum+=0.12
通过首先按 df['usage'].unique()
定义的 models
循环解决,并且将有等量的 json
文件。然后我们遍历 json
中的每个相关变量,然后是给定变量的每个增量值。我们在每个循环中创建掩码,并从最低值开始,因为我们想累加这些值。
df['new_scores'] = 0
for model in models:
for var in models[model]:
var_name = list(var)[0]
json_values = pd.DataFrame(var[var_name])
json_values = json_values.set_index('lb')
for value in json_values.index:
mask = (df[var_name] >= float(value)) & (df['usage'] == model)
df.loc[mask, 'new_scores'] += json_values.loc[value, 'b_cumul']
将旧解决方案中的列与新解决方案中的列进行比较时,值完全相同。对于约 600 万行的原始数据帧,它从花费约 4 小时迭代 5% 的 dataframe
,到约 70 秒到 运行 遍历整个脚本。