37

我试图在每个时间戳处查找数据框中的列名,其值与同一时间戳的时间序列中的列名匹配。

这是我的数据框:

>>> df
                            col5        col4        col3        col2        col1
1979-01-01 00:00:00  1181.220328  912.154923  648.848635  390.986156  138.185861
1979-01-01 06:00:00  1190.724461  920.767974  657.099560  399.395338  147.761352
1979-01-01 12:00:00  1193.414510  918.121482  648.558837  384.632475  126.254342
1979-01-01 18:00:00  1171.670276  897.585930  629.201469  366.652033  109.545607
1979-01-02 00:00:00  1168.892579  900.375126  638.377583  382.584568  132.998706

>>> df.to_dict()
{'col4': {<Timestamp: 1979-01-01 06:00:00>: 920.76797370744271, <Timestamp: 1979-01-01 00:00:00>: 912.15492332839756, <Timestamp: 1979-01-01 18:00:00>: 897.58592995700656, <Timestamp: 1979-01-01 12:00:00>: 918.1214819496729}, 'col5': {<Timestamp: 1979-01-01 06:00:00>: 1190.7244605667831, <Timestamp: 1979-01-01 00:00:00>: 1181.2203275146587, <Timestamp: 1979-01-01 18:00:00>: 1171.6702763228691, <Timestamp: 1979-01-01 12:00:00>: 1193.4145103184442}, 'col2': {<Timestamp: 1979-01-01 06:00:00>: 399.39533771666561, <Timestamp: 1979-01-01 00:00:00>: 390.98615646597591, <Timestamp: 1979-01-01 18:00:00>: 366.65203285812231, <Timestamp: 1979-01-01 12:00:00>: 384.63247469269874}, 'col3': {<Timestamp: 1979-01-01 06:00:00>: 657.09956023625466, <Timestamp: 1979-01-01 00:00:00>: 648.84863460462293, <Timestamp: 1979-01-01 18:00:00>: 629.20146872682449, <Timestamp: 1979-01-01 12:00:00>: 648.55883747413225}, 'col1': {<Timestamp: 1979-01-01 06:00:00>: 147.7613518219286, <Timestamp: 1979-01-01 00:00:00>: 138.18586102094068, <Timestamp: 1979-01-01 18:00:00>: 109.54560722575859, <Timestamp: 1979-01-01 12:00:00>: 126.25434189361377}}

以及我想在每个时间戳匹配的值的时间序列:

>>> ts
1979-01-01 00:00:00    1181.220328
1979-01-01 06:00:00    657.099560
1979-01-01 12:00:00    126.254342
1979-01-01 18:00:00    109.545607
Freq: 6H

>>> ts.to_dict()
{<Timestamp: 1979-01-01 06:00:00>: 657.09956023625466, <Timestamp: 1979-01-01 00:00:00>: 1181.2203275146587, <Timestamp: 1979-01-01 18:00:00>: 109.54560722575859, <Timestamp: 1979-01-01 12:00:00>: 126.25434189361377}

那么结果将是:

>>> df_result
                             value  Column
1979-01-01 00:00:00    1181.220328  col5
1979-01-01 06:00:00    657.099560   col3
1979-01-01 12:00:00    126.254342   col1
1979-01-01 18:00:00    109.545607   col1

我希望我的问题足够清楚。任何人都知道如何获得 df_result?

谢谢

格雷格

4

5 回答 5

29

只是想在列可能具有值并且您想要列表中的所有列名的情况下添加它,您可以执行以下操作(例如,获取所有列名的值 = 'x'):

df.apply(lambda row: row[row == 'x'].index, axis=1)

这个想法是你将每一行变成一个系列(通过添加axis=1),列名现在变成系列的索引。然后,您使用条件(例如)过滤您的系列row == 'x',然后获取索引值(也就是列名!)。

于 2020-08-18T21:26:41.877 回答
16

这是一种可能不太优雅的方法:

df_result = pd.DataFrame(ts, columns=['value'])

设置一个函数来获取包含值的列名(来自ts):

def get_col_name(row):    
    b = (df.ix[row.name] == row['value'])
    return b.index[b.argmax()]

对于每一行,测试哪些元素等于该值,并提取 True 的列名。

apply它(按行):

In [3]: df_result.apply(get_col_name, axis=1)
Out[3]: 
1979-01-01 00:00:00    col5
1979-01-01 06:00:00    col3
1979-01-01 12:00:00    col1
1979-01-01 18:00:00    col1

即使用 df_result['Column'] = df_result.apply(get_col_name, axis=1).

.

注意:有很多事情发生,get_col_name所以也许需要进一步解释:

In [4]: row = df_result.irow(0) # an example row to pass to get_col_name

In [5]: row
Out[5]: 
value    1181.220328
Name: 1979-01-01 00:00:00

In [6]: row.name # use to get rows of df
Out[6]: <Timestamp: 1979-01-01 00:00:00>

In [7]: df.ix[row.name]
Out[7]: 
col5    1181.220328
col4     912.154923
col3     648.848635
col2     390.986156
col1     138.185861
Name: 1979-01-01 00:00:00

In [8]: b = (df.ix[row.name] == row['value'])
        #checks whether each elements equal row['value'] = 1181.220328  

In [9]: b
Out[9]: 
col5     True
col4    False
col3    False
col2    False
col1    False
Name: 1979-01-01 00:00:00

In [10]: b.argmax() # index of a True value
Out[10]: 0

In [11]: b.index[b.argmax()] # the index value (column name)
Out[11]: 'col5'

可能有更有效的方法来做到这一点......

于 2013-02-06T18:02:07.100 回答
14

继安迪的详细回答之后,选择每行最高值的列名的解决方案可以简化为一行:

df['column'] = df.apply(lambda x: df.columns[x.argmax()], axis = 1)
于 2013-12-10T14:31:08.550 回答
6

用于df.eq()约 300 倍的加速df.apply()

与矢量化相比,其他答案很好,但速度很慢df.eq()

df.loc[ts.index].eq(ts, axis=0).idxmax(axis=1)

# 1979-01-01 00:00:00    col5
# 1979-01-01 06:00:00    col3
# 1979-01-01 12:00:00    col1
# 1979-01-01 18:00:00    col1
# dtype: object

矢量化 vs df.apply 时间

测试数据:
index = pd.date_range('2000-01-01', periods=n, freq='1T')
df = pd.DataFrame(np.random.random(size=(n, 5)), index=index).add_prefix('col')
ts = df.apply(np.random.choice, axis=1).sample(frac=0.9)


用于np.isclose()更安全的浮动比较

除非您有特定原因来测试严格相等,否则应该将浮点数与容差进行比较,例如,使用isclose()

  • 用于isclose()与 进行比较dfts其中[:, None] 拉伸ts到与 相同的大小df

    close = np.isclose(df.loc[ts.index], ts[:, None])
    
    # array([[ True, False, False, False, False],
    #        [False, False,  True, False, False],
    #        [False, False, False, False,  True],
    #        [False, False, False, False,  True]])
    
  • 然后,和以前一样,使用idxmax(axis=1)提取每行的第一个匹配列:

    pd.DataFrame(close, index=ts.index, columns=df.columns).idxmax(axis=1)
    
    # 1979-01-01 00:00:00    col5
    # 1979-01-01 06:00:00    col3
    # 1979-01-01 12:00:00    col1
    # 1979-01-01 18:00:00    col1
    # dtype: object
    

使用isclose()将与eq()(因此比:快得多)一样快df.apply()

矢量化 eq 与 isclose 时序


请注意,如果您有更复杂的连接条件,请使用df.merge()df.join()df.reindex()。对于 OP 的问题,这些都是矫枉过正,但看起来像这样:

  • df.merge(ts.rename('ts'), left_index=True, right_index=True)
  • df.join(ts.rename('ts'), how='right')
  • df.reindex(ts.index)
于 2021-08-22T14:20:46.600 回答
2

我试图创建一个新列来指示哪个现有列具有最大的行值。这给了我所需的字符串列标签:

df['column_with_biggest_value'] = df.idxmax(axis=1)
于 2021-05-12T20:30:54.223 回答