我有一个如下所示的数据帧:
Date A B Number
2017-01-01 a b 0.9240
2017-01-01 b c 0.9101
2017-01-01 d e 0.8761
2017-01-01 c g 0.9762
2017-01-02 b c 0.5637
2017-01-02 c d 0.9643
我想在 A 和 B 中有一个每天唯一值的数据帧,具体取决于数字列中的数字。我认为逻辑将按以下顺序排列:
- 按日期对数据框进行分组
- 将 A 列中的每个值与 B 列中的每个值进行比较,以检查是否存在类似的值。
- 对于所有匹配的值,请比较"数字"列并找到两个值中的最大值。
- 返回具有唯一值的新数据帧。
例如,从上面的数据帧来看,由于 2017 年 1 月 1 日的 A 列和 B 列中有一个"b",我想比较 0.9240 和 0.9101,并将行与 0.9240 返回,因为它高于 0.9101。
最终产品应如下所示:
Date A B Number
2017-01-01 a b 0.9240
2017-01-01 d e 0.8761
2017-01-01 c g 0.9762
2017-01-02 c d 0.9643
这很复杂,但绝对有可能做到。
首先,让我们确保数据的格式正确:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6 entries, 0 to 5
Data columns (total 4 columns):
Date 6 non-null datetime64[ns]
A 6 non-null object
B 6 non-null object
Number 6 non-null float64
dtypes: datetime64[ns](1), float64(1), object(2)
memory usage: 272.0+ bytes
请注意,Date
列的类型为 datetime64
。这是必要的,因为将这些值作为时间戳允许使用 pandas resample
方法每天对数据进行分组。
对数据重新采样后,可以应用自定义方法extract
。此方法获取一个组作为数据框并应用逻辑。通过使用 pandas pivot_table
方法,可以更轻松地找到 A 列和 B 列之间的交集。我不确定这是否是最有效的方法,但如果数据集不是太大,它应该足够快地工作。
完整代码如下所示:
def extract(df):
dfs = []
pt = df.reset_index().pivot_table('Number', columns=['A', 'B'], index='Date')
# find any intersection of values between col A and B
intersection = set(pt.columns.levels[0].values)
.intersection(set(pt.columns.levels[1].values))
# iterate over all intersections to compare their values
# and choose the largest one
for value in intersection:
mask = (df['A'] == value) | (df['B'] == value)
df_intersection = df[mask]
.sort_values('Number', ascending=False)
dfs.append(df_intersection.ix[[0]])
# find all rows that do not contain any intersections
df_rest = df[(~df['A'].isin(list(intersection))) &
(~df['B'].isin(list(intersection)))]
if (len(df_rest) > 0):
dfs.append(df_rest)
return pd.concat(dfs)
df.set_index('Date')
.resample('d')
.apply(extract)
.reset_index(level=1, drop=True)
此代码导致:
A B Number
Date
2017-01-01 a b 0.9240
2017-01-01 c g 0.9762
2017-01-01 d e 0.8761
2017-01-02 c d 0.9643
上面的代码基于给定的数据集:
import pandas as pd
from io import StringIO
data = StringIO("""
Date A B Number
2017-01-01 a b 0.9240
2017-01-01 b c 0.9101
2017-01-01 d e 0.8761
2017-01-01 c g 0.9762
2017-01-02 b c 0.5637
2017-01-02 c d 0.9643
""")
df = pd.read_csv(data, sep='s+', parse_dates=[0])