- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个大型 Pandas 数据框 df_gen
,其中包含 10000 个客户的时间序列数据。数据与能源使用有关。这是它的缩小版
In[1]: df_gen
Out[2]:
10053802 10053856 10053898 10058054
2013-01-01 00:00:00 0.196 1.493 0.332 0.278
2013-01-01 00:30:00 0.155 1.497 0.336 0.275
2013-01-01 01:00:00 0.109 1.487 NaN 0.310
2013-01-01 01:30:00 0.703 1.479 0.331 0.272
2013-01-01 02:00:00 0.389 1.533 0.293 0.313
我有一个填充缺失数据的过程:对于在特定时间戳中缺失数据的特定客户 ID,找到在整个数据集中具有最相似数据的时间戳,并使用它来填补空白。
使用此方法的原因是能源使用取决于外部因素,例如外部温度,因此,例如在炎热的日子里,很多顾客都开着空调。如果我们找到大多数其他客户的能源使用情况与缺失数据点的日期和时间相似的日期和时间,那么这是填充缺失数据的好地方。
它使用一个函数通过计算每一行的方差来识别数据与缺失数据的时间戳最匹配的时间戳:
def best_ts(df,ts_null,null_row):
# finds the timestamp for which the load is closest to the missing load at ts_null across the dataset df
# null_row is the row with the null data to be filled
var_df = pd.Series(index=df.index)
var_df.fillna(value=0, inplace=True)
if pd.isnull(null_row).all():
logging.info('No customer data at all for %s ',str(ts_null))
var_df = ((df-null_row).fillna(value=0)**2).sum(axis=1)
smallest = var_df.idxmin()
return smallest
脚本然后为每个客户和每个时间戳迭代,当它找到空数据时,它调用 best_ts
并从该时间戳开始填充:
for id in df_gen.columns:
for ts in df_gen.index:
if pd.isnull(df_gen.loc[ts,id]):
# slice df to remove rows that have no filling data for this customer and use this to fill from
fill_ts = best_ts(df_gen[df_gen[id].notnull()],ts, df_gen.loc[ts])
df_gen.loc[ts].fillna(df_gen.loc[fill_ts], inplace=True)
实例使用上面的示例 df,当找到 NaN
数据时,将向 best_ts
传递 3 个参数:删除缺失数据行的 df、缺失数据的时间戳,以及作为 Pandas 系列的缺失数据行
In: df_gen[df_gen[id].notnull()]
Out:
10053802 10053856 10053898 10058054
2013-01-01 00:00:00 0.196 1.493 0.332 0.278
2013-01-01 00:30:00 0.155 1.497 0.336 0.275
2013-01-01 01:30:00 0.703 1.479 0.331 0.272
2013-01-01 02:00:00 0.389 1.533 0.293 0.313
In: ts
Out:
datetime.datetime(2013, 1, 1, 1, 0)
In: df_gen.loc[ts]
Out:
10053802 0.109
10053856 1.487
10053898 NaN
10058054 0.310
在该函数中,使用与数据帧相同的 DateTimeIndex 创建了一个 pandas 系列 var_df
。每个值都是方差,即每个客户的能量值与时间戳 ts
的能量值之差的平方和。
例如 var_df
中的第一个值由 ((0.196-0.109)^2 + (1.493-1.487)^2 + 0 + (0.278-0.310)^2) = 0.008629 给出
In: var_df
Out:
2013-01-01 00:00:00 0.008629
2013-01-01 00:30:00 0.003441
2013-01-01 01:30:00 0.354344
2013-01-01 02:00:00 0.080525
dtype: float64
所以时间戳 2013-01-01 00:30:00
是最“像”缺失数据时间的时间,所以选择这个时间来填充缺失数据。
所以填充的数据框看起来像这样:
In: df_gen
Out:
10053802 10053856 10053898 10058054
2013-01-01 00:00:00 0.196 1.493 0.332 0.278
2013-01-01 00:30:00 0.155 1.497 0.336 0.275
2013-01-01 01:00:00 0.109 1.487 0.336 0.310
2013-01-01 01:30:00 0.703 1.479 0.331 0.272
2013-01-01 02:00:00 0.389 1.533 0.293 0.313
(注意:在这个小例子中,“最佳”时间戳恰好是紧接在缺失数据之前的时间戳,但在完整数据集中,它可能是一年中 17519 个时间戳中的任何一个。)
此代码有效,但伙计,它太慢了!通过数据集大约需要 2 个月的时间!我希望通过避免嵌套迭代或加速函数来加快速度的建议。
最佳答案
看起来您的相似性指标正在计算每列之间的元素平方距离之和。一种方法,诚然有点笨拙(但利用了快速的 Pandas 操作)是:
df.subtract().pow(2).sum()
计算相似度,忽略自减列,找到最小值的列名(即客户id)值(value)。 以下是草稿,但它可能足以适应您的用例。此实现的一个重要假设是每个客户只能丢失一个数据点。该代码应该可以推广到每个客户的多个缺失数据点,只需做一些工作。因此,在测试此代码时,请确保随机生成的 df
每列仅缺少一个数据点。 (通常是这样,但并非总是如此。)
生成样本数据
dates = pd.date_range('20170101', periods=10, freq='D')
ids = [10006414, 10006572, 10006630, 10006664, 10006674]
values = np.random.random(size=len(dates)*len(ids)).reshape(10,5)
df = pd.DataFrame(values, index=dates, columns=ids)
# insert random missing data
nan_size = 4
for _ in range(nan_size):
nan_row = np.random.randint(0, df.shape[0])
nan_col = np.random.randint(0, df.shape[1])
df.iloc[nan_row, nan_col] = np.nan
执行匹配插值
def get_closest(customer, dims):
cust = customer.name
nrow = dims[0]
ncol = dims[1]
replace_row = df.index[df[cust].isnull()]
# make data frame full of cust data
df2 = pd.DataFrame(np.repeat(df.loc[:,cust], ncol).values.reshape(nrow,ncol),
index=dates, columns=ids)
replace_col = (df.subtract(df2)
.pow(2)
.sum()
.replace({0:np.nan}) # otherwise 0 will go to top of sort
.sort_values()
.index[0] # index here is matching customer id
)
customer[replace_row] = df.ix[replace_row, replace_col]
return customer
print(df.apply(get_closest, axis='rows', args=(df.shape,)))
更新
根据 OP 的澄清,目标是进行逐行比较(即找到最相似的时间戳)而不是逐列比较(即找到最相似的客户)。下面是 get_closest()
的更新版本,它进行逐行比较,并顺利处理多个缺失值。
我还添加了一个报告功能,它将打印包含所有客户缺失条目的每个时间戳,以及用于估算缺失值的时间戳。报告默认关闭,只需将 True
作为 apply()
中的第二个 args
条目传递即可将其打开。
更新 2
更新后的行式 get_closest()
现在考虑了边缘情况,其中最近的时间戳也有需要插补的客户列的 NaN
值。现在,该函数将搜索最近的时间戳,该时间戳也具有需要估算的缺失值的可用数据。
示例数据:
10006414 10006572 10006630 10006664 10006674
2017-01-01 0.374593 0.982585 0.059732 0.513149 0.251808
2017-01-02 0.269229 0.998531 0.523589 0.780806 0.033106
2017-01-03 0.261173 0.828637 0.638376 0.314944 0.737646
2017-01-04 0.786112 0.101750 0.286983 0.242778 0.341717
2017-01-05 0.230358 0.387392 0.918353 0.206100 NaN
2017-01-06 0.715966 0.206121 0.153461 0.894511 0.765227
2017-01-07 0.095002 0.169697 0.465624 0.109404 0.212315
2017-01-08 0.474712 NaN 0.471861 0.773374 0.454295
2017-01-09 NaN 0.201928 0.228018 0.173968 0.248485
2017-01-10 0.542635 NaN 0.132974 0.692073 0.201721
ROW-WISE get_closest()
def get_closest(row, dims, report=False):
if row.isnull().sum():
ts_with_nan = row.name
nrow, ncol = dims
df2 = pd.DataFrame(np.tile(df.loc[ts_with_nan], nrow).reshape(nrow,ncol),
index=df.index, columns=df.columns)
most_similar_ts = (df.subtract(df2, axis='rows', fill_value=0)
.pow(2)
.sum(axis=1, skipna=True)
.sort_values()
)
# remove current row from matched indices
most_similar_ts = most_similar_ts[most_similar_ts.index != ts_with_nan]
# narrow down to only columns where replacements would occur
match_vals = df.ix[most_similar_ts.index, df.loc[ts_with_nan].isnull()]
# select only rows where all values are non-empty
all_valid = match_vals.notnull().all(axis=1)
# take the timestamp index of the first row of match_vals[all_valid]
best_match = match_vals[all_valid].head(1).index[0]
if report:
print('MISSING VALUES found at timestamp: {}'.format(ts_with_nan.strftime('%Y-%m-%d %H:%M:%S')))
print(' REPLACEMENT timestamp: {}'.format(best_match.strftime('%Y-%m-%d %H:%M:%S')))
# replace missing values with matched data
return row.fillna(df.loc[best_match])
return row
df.apply(get_closest, axis='columns', args=(df.shape, True)) # report=True
输出:
# MISSING VALUES found at timestamp: 2017-01-02 00:00:00
# REPLACEMENT timestamp: 2017-01-09 00:00:00
# MISSING VALUES found at timestamp: 2017-01-07 00:00:00
# REPLACEMENT timestamp: 2017-01-10 00:00:00
# MISSING VALUES found at timestamp: 2017-01-09 00:00:00
# REPLACEMENT timestamp: 2017-01-03 00:00:00
print(df)
10006414 10006572 10006630 10006664 10006674
2017-01-01 0.374593 0.982585 0.059732 0.513149 0.251808
2017-01-02 0.269229 0.998531 0.523589 0.780806 0.033106
2017-01-03 0.261173 0.828637 0.638376 0.314944 0.737646
2017-01-04 0.786112 0.101750 0.286983 0.242778 0.341717
2017-01-05 0.230358 0.387392 0.918353 0.206100 0.212315
2017-01-06 0.715966 0.206121 0.153461 0.894511 0.765227
2017-01-07 0.095002 0.169697 0.465624 0.109404 0.212315
2017-01-08 0.474712 0.201928 0.471861 0.773374 0.454295
2017-01-09 0.095002 0.201928 0.228018 0.173968 0.248485
2017-01-10 0.542635 0.201928 0.132974 0.692073 0.201721
除了这种逐行方法之外,我还在这个答案的开头保留了 get_closest()
的原始版本,因为我可以看到基于“最近的客户”的插补的值(value),而不是“最近的时间戳”,它可能会在将来用作其他人的引用点。
更新 3
OP 提供了这个更新和最终的解决方案:
import pandas as pd
import numpy as np
# create dataframe of random data
dates = pd.date_range('20170101', periods=10, freq='D')
ids = [10006414, 10006572, 10006630, 10006664, 10006674]
values = np.random.random(size=len(dates)*len(ids)).reshape(10,5)
df = pd.DataFrame(values, index=dates, columns=ids)
# insert random missing data
nan_size = 20
for _ in range(nan_size):
nan_row = np.random.randint(0, df.shape[0])
nan_col = np.random.randint(0, df.shape[1])
df.iloc[nan_row, nan_col] = np.nan
print ('Original df is ', df)
def get_closest(row, dims, report=False):
if row.isnull().sum():
ts_with_nan = row.name
nrow, ncol = dims
df2 = pd.DataFrame(np.tile(df.loc[ts_with_nan], nrow).reshape(nrow, ncol), index=df.index, columns=df.columns)
most_similar_ts = (df.subtract(df2, axis='rows')
.pow(2)
.sum(axis=1, skipna=True)
.sort_values())
# remove current row from matched indices
most_similar_ts = most_similar_ts[most_similar_ts.index != ts_with_nan]
if report:
print('MISSING VALUES found at timestamp: {}'.format(ts_with_nan.strftime('%Y-%m-%d %H:%M:%S')))
while row.isnull().sum():
# narrow down to only columns where replacements would occur
match_vals = df.ix[most_similar_ts.index, df.loc[ts_with_nan].isnull()]
# fill from closest ts
best_match = match_vals.head(1).index[0]
row = row.fillna(df.loc[best_match])
if report:
print(' REPLACEMENT timestamp: {}'.format(best_match.strftime('%Y-%m-%d %H:%M:%S')))
# Any customers with remaining NaNs in df.loc[ts_with_nan] also have NaNs in df.loc[best_match]
# so remove this ts from the results and repeat the process
most_similar_ts = most_similar_ts[most_similar_ts.index != best_match]
return row
return row
df_new = df.apply(get_closest, axis='columns', args=(df.shape, True)) # report=True
print ('Final df is ', df_new)
关于python - 使用 pandas dataframe 加速迭代过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43531510/
如果我声明了类似的类型 type test(NSIZE) integer, len :: NSIZE real :: dummy(NSIZE) contains procedure,
我知道这是一个不太可能的事情,但是由于“选项私有(private)模块”的限制,甚至更糟糕的“私有(private)子/函数”的限制,有谁知道是否有一种方法可以从 Excel 应用程序隐藏 VBA 过
我有两个表,property 和 component。 component.id_property = property.id。 我正在尝试创建一个过程,该过程对所选属性的组件进行计数,如果所选属性没
我有一份报告,它是在 SSRS 2005 中开发的,我正在使用存储过程从数据库中获取结果。报告输出的结果非常简单,如下图所示。 如果假设我正在寻找不同的成员 例如:- MemberID c108 c
我需要一个通用函数/过程,该函数/过程将根据提供的数据计算出我的淡入淡出时间和值,如下所示: 我将字节值保存在字节数组中:这些是起始值。然后,我在其他数组中存储了一些值:这些将是新值。然后我有时间要提
我想在界面的多个按钮上创建相同的操作。是否只能通过创建单独的操作监听器方法并调用执行操作的方法才可行,还是还有其他方法?是否可以将按钮放在一个组中并执行以下操作:- groupButton.setOn
我有以下情况: procedure Test; begin repeat TryAgain := FALSE; try // Code // Code if this an
我正在尝试执行以下操作;假设我在 Oracle 中创建了一个对象类型 create type test as object( name varchar2(12), member procedure p
问题: 如果可能的话,如何声明一个用于任何类型参数的函数 T其中 T 的唯一约束是它被定义为 1D array如 type T is array ( integer range <> ) of a_r
我正在尝试创建这个 mysql 过程来制作一个包含今年所有日期和所有时间的表(以一小时为间隔。) CREATE TABLE FECHAS ( created_at datetime ); CREA
所以, 我在这里面临一个问题,这让我发疯,我认为这是一个愚蠢的错误,所以我不是 MySQL 的新手,但它并不像我想象的那样工作。 尝试将此语句部署到 MySQL 后,我收到此错误: ERROR 106
我有一个架构,其中包含星球大战中的人物列表、他们出现的电影、他们访问的行星等。这是架构: CREATE DATABASE IF NOT EXISTS `starwarsFINAL` /*!40100
我一直在为一家慈善机构创建一款应用程序,允许家庭在节日期间注册接收礼物。数据库组织有多个表。下面列出了这些表(及其架构/创建语句): CREATE TABLE IF NOT EXISTS ValidD
正如上面标题所解释的,我正在尝试编写一个sql函数来按日期删除表而不删除系统表。我在此消息下方放置了一张图片,以便直观地解释我的问题。任何帮助将不胜感激!感谢您的时间! 最佳答案 您可以通过查询INF
DELIMITER $$ CREATE PROCEDURE INSERT_NONE_HISTORY_CHECKBOX() BEGIN DECLARE note_id bigint(20); F
是否可以编写一个存储过程或触发器,在特定时间在数据库内部自动执行,而无需来自应用程序的任何调用?如果是,那么任何人都可以给我一个例子或链接到一些我可以阅读如何做到这一点的资源。 最佳答案 查看 pgA
我需要创建一个过程:1)从表中的字段中选择一些文本并将其存储在变量中2) 更新相同的记录字段,仅添加 yyyymmdd 格式的日期以及过程中的附加文本输入...类似这样的... delimiter /
好的,这就是我想做的: 如果条目已存在(例如基于字段name),则只需返回其id 如果没有,请添加 这是我迄今为止所管理的(对于“如果不存在,则创建它”部分): INSERT INTO `object
以下是我编写的程序,用于找出每位客户每天购买的前 10 件商品。 这是我尝试过的第一个 PL/SQL 操作。它没有达到我预期的效果。 我使用的逻辑是接受开始日期、结束日期以及我对每个客户感兴趣的前“x
我正在尝试在MySQL中创建一个过程那insert week s(当年)发送至我的 week table 。但存在一个问题,因为在为下一行添加第一行后,我收到错误: number column can
我是一名优秀的程序员,十分优秀!