Python pandas - 将具有多个日期索引的csv合并到单个日期索引

Posted

技术标签:

【中文标题】Python pandas - 将具有多个日期索引的csv合并到单个日期索引【英文标题】:Python pandas - merge csv with multiple date indexes to single date index 【发布时间】:2021-04-11 09:17:34 【问题描述】:

您好,我在电子表格中有如下数据

|aaa-date  |aaa-val|bbb-date  |bbb-val|ccc-date  |ccc-val|
|----------|-------|----------|-------|----------|-------|
|08-04-2008|-20.943|31-03-2008|-23.869|26-03-2008|+1.401 |
|09-04-2008|-20.943|01-04-2008|-19.813|27-03-2008|+1.376 |
|10-04-2008|-18.868|02-04-2008|-18.929|28-03-2008|-0.534 |
|11-04-2008|-19.057|03-04-2008|-19.917|31-03-2008|+0.688 |
|14-04-2008|-20.000|04-04-2008|-20.125|01-04-2008|+3.336 |
|15-04-2008|-18.868|07-04-2008|-21.321|02-04-2008|+3.413 |
|16-04-2008|-16.226|08-04-2008|-22.517|03-04-2008|+4.177 |
|17-04-2008|-14.340|09-04-2008|-24.857|04-04-2008|+4.279 |
|18-04-2008|-12.830|10-04-2008|-24.701|07-04-2008|+2.445 |
|21-04-2008|-15.472|11-04-2008|-24.857|08-04-2008|+1.146 |

我想导入这个(csv 或 xlsx)并到达一个只有一个日期索引和 aaa-valbbb-val 列的数据框和 ccc-val 例如

|          |aaa-val|bbb-val|ccc-val|
|----------|-------|-------|-------|
|26-03-2008|       |       |+1.401 |
|27-03-2008|       |       |+1.376 |
|28-03-2008|       |       |-0.534 |
|31-03-2008|       |-23.869|+0.688 |
|01-04-2008|       |-19.813|+3.336 |
|02-04-2008|       |-18.929|+3.413 |
|03-04-2008|       |-19.917|+4.177 |
|04-04-2008|       |-20.125|+4.279 |
|07-04-2008|       |-21.321|+2.445 |
|08-04-2008|-20.943|-22.517|+1.146 |
|09-04-2008|-20.943|-24.857|+0.917 |
|10-04-2008|-18.868|-24.701|+2.420 |
|11-04-2008|-19.057|-24.857|+1.860 |
|14-04-2008|-20.000|-26.053|+3.515 |
|15-04-2008|-18.868|-24.805|       |
|16-04-2008|-16.226|-23.557|       |
|17-04-2008|-14.340|-23.765|       |
|18-04-2008|-12.830|       |       |
|21-04-2008|-15.472|       |       |
|22-04-2008|-16.793|       |       |
|23-04-2008|-13.019|       |       |
|24-04-2008|-12.453|       |       |
|25-04-2008|-12.642|       |       | 

除了加载到临时框架然后循环遍历日期/值列对之外,还有其他聪明的方法吗?

谢谢

【问题讨论】:

【参考方案1】:

所以 FWIW 这就是我最终的结果 - 我的数据集是 176 列 x 3300 行,concataxis=1 似乎比 merge 更快

df = pd.read_csv('data.csv')
i = 0
new_df = pd.DataFrame()

while 2*(i+1) < len(df.columns):
    colname = df.columns[2*i + 1]
    tmp = df.iloc[:,[2*i, 2*i+1]].dropna()
    tmp.columns.values[0]='date'
    tmp.set_index('date', inplace=True)
    new_df = pd.concat([new_df, tmp], axis=1)
    i += 1

观察:

    我认为您无法避免循环遍历初始数据框 - 我找不到可以帮助您的 pandas 函数

    iloc[:,[2*i, 2*i+1]] 是提取感兴趣的列的超级有用的构造 - 这可能对新手 How to take column slices of a Pandas DataFrame in Python 有帮助

谢谢大家,约翰

【讨论】:

你测量时间了吗?你能展示ourpur数据框吗? @adirabargil concat 实现需要 750 毫秒,merge 实现需要 1,188 毫秒,因此延长了 58% 谢谢..欢迎您接受自己的答案...【参考方案2】:

您可以先分离数据框,然后将它们合并...:

data_csv = io.StringIO('''|aaa-date  |aaa-val|bbb-date  |bbb-val|ccc-date  |ccc-val|
|08-04-2008|-20.943|31-03-2008|-23.869|26-03-2008|+1.401 |
|09-04-2008|-20.943|01-04-2008|-19.813|27-03-2008|+1.376 |
|10-04-2008|-18.868|02-04-2008|-18.929|28-03-2008|-0.534 |
|11-04-2008|-19.057|03-04-2008|-19.917|31-03-2008|+0.688 |
|14-04-2008|-20.000|04-04-2008|-20.125|01-04-2008|+3.336 |
|15-04-2008|-18.868|07-04-2008|-21.321|02-04-2008|+3.413 |
|16-04-2008|-16.226|08-04-2008|-22.517|03-04-2008|+4.177 |
|17-04-2008|-14.340|09-04-2008|-24.857|04-04-2008|+4.279 |
|18-04-2008|-12.830|10-04-2008|-24.701|07-04-2008|+2.445 |
|21-04-2008|-15.472|11-04-2008|-24.857|08-04-2008|+1.146 |''')
df = pd.read_csv(data_csv,sep=r'\s*\|\s*',engine='python').iloc[:,1:-1]
column_names = df.columns.tolist()
cols = [col.split('-')[0] for col in column_names][::2]
cols
dfs = [df[[col+'-date',col+'-val']] for col in cols]
new_df = pd.DataFrame('date':[])
for dfi,col in zip(dfs,column_names[::2]):
    new_df = new_df.merge(dfi.rename(columns=col:'date'),how='outer')
new_df

输出:

    date        aaa-val bbb-val ccc-val
0   08-04-2008  -20.943 -22.517 1.146
1   09-04-2008  -20.943 -24.857 NaN
2   10-04-2008  -18.868 -24.701 NaN
3   11-04-2008  -19.057 -24.857 NaN
4   14-04-2008  -20.000 NaN     NaN
5   15-04-2008  -18.868 NaN     NaN
6   16-04-2008  -16.226 NaN     NaN
7   17-04-2008  -14.340 NaN     NaN
8   18-04-2008  -12.830 NaN     NaN
9   21-04-2008  -15.472 NaN     NaN
10  31-03-2008  NaN     -23.869 0.688
11  01-04-2008  NaN     -19.813 3.336
12  02-04-2008  NaN     -18.929 3.413
13  03-04-2008  NaN     -19.917 4.177
14  04-04-2008  NaN     -20.125 4.279
15  07-04-2008  NaN     -21.321 2.445
16  26-03-2008  NaN     NaN     1.401
17  27-03-2008  NaN NaN 1.376
18  28-03-2008  NaN NaN -0.534

【讨论】:

【参考方案3】:

我只是在查找其他内容时发现了这篇文章,我相信它可以帮助您:

https://pbpython.com/pandas-excel-range.html

基本上,您可以为每个时间/数据范围读取特定列范围的文件(如果您想使用列名,请使用 lambda 方法)。然后我会将日期字段重命名为相同的名称或将日期字段设置为索引。然后到多个全外连接来组合所有数据。

编辑 - 一个简单的 concat 不会像我最初写的那样工作。我建议在日期列上使用完整的外部联接。

[来自链接]

使用可调用对象的另一种方法是包含 lambda 表达式。这是一个示例,我们只想包含已定义的列列表。为了比较,我们通过将名称转换为小写来规范化名称。

cols_to_use = ['item_type', 'order id', 'order date', 'state', 'priority']
df = pd.read_excel(src_file,
                   header=1,
                   usecols=lambda x: x.lower() in cols_to_use)

编辑显示 CONCAT 和 MERGE 之间的差异:

import pandas as pd
import numpy as np
from common import  show_table

df1 = pd.DataFrame(data=[[1, 1], [2, 2]], columns=['a','b'])
print(df1)
#    a  b
# 0  1  1
# 1  2  2

df2 = pd.DataFrame(data=[[1, 1], [3, 3]], columns=['a','c'])
print(df2)
#    a  c
# 0  1  1
# 1  3  3

# no good...
df3 = pd.concat([df1, df2])
print(df3)
#    a    b    c
# 0  1  1.0  NaN
# 1  2  2.0  NaN
# 0  1  NaN  1.0
# 1  3  NaN  3.0


# good
df4 = pd.merge(df1, df2, how='outer', on='a')
print(df4)
#    a    b    c
# 0  1  1.0  1.0
# 1  2  2.0  NaN
# 2  3  NaN  3.0

编辑索引验证 - 索引上的 Concat 不执行完全外连接

import pandas as pd
import numpy as np

df1 = pd.DataFrame(data=[[1, 1], [2, 2]], columns=['a','b'])
df1 = df1.set_index('a')
print(df1)
#    b
# a   
# 1  1
# 2  2
df2 = pd.DataFrame(data=[[1, 1], [3, 3]], columns=['a','c'])
df2 = df2.set_index('a')
print(df2)
#    c
# a   
# 1  1
# 3  3

# no good...
df3 = pd.concat([df1, df2])
print(df3)
#      b    c
# a          
# 1  1.0  NaN
# 2  2.0  NaN
# 1  NaN  1.0
# 3  NaN  3.0

# good
df4 = pd.merge(df1, df2, how='outer', left_index=True, right_index=True)
print(df4)
#      b    c
# a          
# 1  1.0  1.0
# 2  2.0  NaN
# 3  NaN  3.0

【讨论】:

感谢 Ian - 基本上是循环加 concat。 pbpython 网站看起来也值得关注,所以谢谢 谢谢!但请参阅我的编辑建议加入与 concat 相对的数据。如果在数据的多个细分中存在特定日期的数据,则简单的 concat 将重复日期字段 我认为如果将日期列指定为索引,则 concat 可以工作,默认情况下 concat 将执行外部连接 - 请参阅 pandas.pydata.org/pandas-docs/stable/user_guide/… - 感谢您的澄清 Ian 嗨,再次感谢 - 如果您使用 axis=1 拨打 concat 电话,那么它将执行外连接并给出与您的 df4 示例 df3 = pd.concat([df1, df2], axis=1) 相同的结果 - 再次感谢 -熊猫新手,这对我都有帮助

以上是关于Python pandas - 将具有多个日期索引的csv合并到单个日期索引的主要内容,如果未能解决你的问题,请参考以下文章

Pandas 获取具有复合索引的数据帧的行号

合并具有非唯一索引的多个熊猫数据集

将日期时间格式的索引转换为仅限日期的python pandas

如何使用另一个日期时间索引获取具有日期时间索引的 Pandas 数据框中的行?

Python Pandas Dataframe 将特定的日期时间行标签设置为索引中的字符串?

Pandas Python - 计数和分组日期时间索引