python - Python 根据另一列的值(通过数字索引确定)为新列赋值
问题描述
我有一个大数据框(2,000,000+ 行乘 2,000+ 列),我想根据每行中包含的数据创建一些新列。一列是一个数字,我想用作索引器来选择其他列中的数据。该索引器会针对每一行进行更改,这意味着无法按名称选择列,因此我需要使用数字索引。在确定了我需要的列之后,我想将这些值输出到一组新的列(之后我将执行一些计算)。
以下是我尝试过的简化版本:
# import packages
import pandas as pd
import numpy as np
# create dataframe
n = 10000
a_bar = 9; a_sd = 2
b_bar = 1000; b_sd = 100
np.random.seed(12345)
df = pd.DataFrame(dict(month_index=np.random.normal(a_bar, a_sd, size=n),
month_1=np.random.normal(b_bar, b_sd, size=n),
month_2=np.random.normal(b_bar, b_sd, size=n),
month_3=np.random.normal(b_bar, b_sd, size=n),
month_4=np.random.normal(b_bar, b_sd, size=n),
month_5=np.random.normal(b_bar, b_sd, size=n),
month_6=np.random.normal(b_bar, b_sd, size=n),
month_7=np.random.normal(b_bar, b_sd, size=n),
month_8=np.random.normal(b_bar, b_sd, size=n),
month_9=np.random.normal(b_bar, b_sd, size=n),
month_10=np.random.normal(b_bar, b_sd, size=n),
month_11=np.random.normal(b_bar, b_sd, size=n),
month_12=np.random.normal(b_bar, b_sd, size=n)
),
columns=['month_index', 'month_1', 'month_2', 'month_3',\
'month_4', 'month_5', 'month_6', 'month_7',\
'month_8', 'month_9', 'month_10', 'month_11', 'month_12'])
# round all column values
df = df.round()
# restrict value of month index
conditions = [df.month_index < 7, df.month_index > 12, (df.month_index >= 7) & (df.month_index <= 12)]
values = [7, 12, df.month_index]
df["month_index"] = np.select(conditions, values)
# reduce size of dataframe
for column in df.columns:
df[column] = pd.to_numeric(df[column], downcast='integer')
# select relevant data using function
def select_columns(df):
i = 0
while i < len(df):
j = df.at[i, 'month_index']
df.at[i, "temp_1"] = df.iat[i, j-5]
df.at[i, "temp_2"] = df.iat[i, j-4]
df.at[i, "temp_3"] = df.iat[i, j-3]
df.at[i, "temp_4"] = df.iat[i, j-2]
df.at[i, "temp_5"] = df.iat[i, j-1]
df.at[i, "temp_6"] = df.iat[i, j]
i += 1
return df
df = select_columns(df)
我发现这是非常低效的,我宁愿使用 pandas .apply 方法,或者(如果可能的话) vectorisation。虽然我已经尝试过 numpy 的矢量化功能,但我知道这种方法只有在列可以作为 numpy 数组传递给函数时才可行。我的问题是:
- 解决我的问题的最佳方法是什么(考虑到我正在使用的行数/列数)?
- 对具有大量列的数据帧进行矢量化是否可行?
解决方案
提高性能最简单的方法是在 python 数据结构中构建值,然后将列一次附加到数据帧,而不是不断地将值附加到数据帧。
data_structure = []
mapping = {
'temp_1': 5,
'temp_2': 4,
'temp_3': 3,
'temp_4': 2,
'temp_5': 1,
'temp_6': 0
}
for row in df.itertuples():
d = {}
for name, column_offset in mapping.items():
idx = row.month_index - column_offset
column_name = df.columns[idx]
d[name] = getattr(row, column_name)
data_structure.append(d)
newdf = pd.DataFrame(data_structure)
combined = pd.concat([df, newdf], axis=1)
如果上述解决方案不够快,您应该能够使用多处理将工作拆分到多个内核。您可以尝试使用modin
透明地执行此操作,或者您可能必须自己执行此操作。
至于矢量化,似乎 temp_1 在 month_index -5 列中。因此,以下面的简化示例为例,您应该能够使用矢量化来按列索引获取行值数组。
from io import StringIO
import numpy as np
# first five rows of dataframe for example
data = StringIO("""
9,1193,942,948,1053,922,985,949,987,970
10,884,1084,912,938,1179,958,842,944,1186
8,961,1070,1081,944,1074,988,1023,979,942
8,1040,1009,896,953,947,1058,1133,921,1113
12,913,1114,985,898,1011,1152,953,842,1150
""")
>>> a = np.genfromtxt(data, delimiter=',')
... temp_1_idx = (a[:, 0] - 5).astype(int)
... a[np.arange(len(a)), temp_1_idx]
array([1053., 1179., 1081., 896., 953.])
推荐阅读
- haskell - Haskell - 返回给定列表中大于 n 的数字
- java - 如何在java 8中将列表转换为具有设定值的地图
- ios - 在相机 iOS 上绘制叠加层
- reactjs - 在 ReactJS 项目中自动导入所有 *.scss
- c# - 从字符串中读取字符并计算每个字符
- javascript - 在不使用 INCLUDES 的情况下检查值是否存在于对象数组中
- terraform - 如何使用 terraform 中的 user_data 值更改 aws_instance?
- android - 错误:程序类型已存在:com.google.android.gms.internal.measurement.zzeb
- php - 将在多个字符串中找到的缩写转换为完整的单词 - PHP
- realm - Swift Realm - 'RLMException',原因:'只有由 Realm 管理的对象才支持更改'