У меня есть фрейм данных "работает" с непоследовательным индексом, вот пример:
Index Column1 Column2
4464 10.5 12.7
4465 11.3 12.8
4466 10.3 22.8
5123 11.3 21.8
5124 10.6 22.4
5323 18.6 23.5
мне нужно извлечь из этого кадра данных новые кадры данных, содержащие только строки, в которых индекс является последовательным, поэтому в этом случае моя цель - получить
DF_1.index=[4464,4465,4466]
DF_2.index=[5123,5124]
DF_3.index=[5323]
сохранение всех столбцов.
Может кто-нибудь помочь мне? Спасибо!
Может быть, есть более элегантный способ записать это, но вот что работает для меня:
previous_index = df.index[0]
groups = {}
for x in df.index:
if (x-previous_index) ==1 :
groups[max(groups.keys())].append(x)
else:
groups[len(groups.keys())]=[x]
previous_index = x
output_dfs = []
for key, val in groups.items():
print(key, val)
output_dfs.append(df[df.index.isin(val)])
Ваши кадры данных будут храниться в output_dfs
output_dfs[0].index
[4464,4465,4466]
На самом деле previous_index
обновляется в конце каждой итерации. Я просто отредактирую код, чтобы он принимал реальное значение вместо исходного произвольного 0
значения.
Вы можете использовать exec для создания нескольких фреймов данных и получения ожидаемых результатов:
df = pd.DataFrame({'Column1' : [10.5,11.3,10.3,11.3,10.6,18.6], 'Column2' : [10.5,11.3,10.3,11.3,10.6,18.6]})
df.index = [4464, 4465, 4466, 5123, 5124, 5323]
prev_index = df.index[0]
df_1 = pd.DataFrame(df.iloc[0]).T
num_df = 1
for i in df.index[1:]:
if i == prev_index+1:
exec('df_{} = df_{}.append(df.loc[{}])'.format(num_df, num_df, i))
else :
num_df += 1
exec('df_{} = pd.DataFrame(df.loc[{}]).T'.format(num_df, i))
prev_index = i
Вот альтернатива:
grouper = (~(pd.Series(df.index).diff() == 1)).cumsum().values
dfs = [dfx for _ , dfx in df.groupby(grouper)]
Мы используем тот факт, что непрерывная разность 1 равна последовательности (diff == 1).
Полный пример:
import pandas as pd
data = '''\
Index Column1 Column2
4464 10.5 12.7
4465 11.3 12.8
4466 10.3 22.8
5123 11.3 21.8
5124 10.6 22.4
5323 18.6 23.5
'''
fileobj = pd.compat.StringIO(data)
df = pd.read_csv(fileobj, sep='\s+', index_col='Index')
non_sequence = pd.Series(df.index).diff() != 1
grouper = non_sequence.cumsum().values
dfs = [dfx for _ , dfx in df.groupby(grouper)]
print(dfs[0])
# Column1 Column2
#Index
#4464 10.5 12.7
#4465 11.3 12.8
#4466 10.3 22.8
Другой способ увидеть это состоит в том, что мы ищем не последовательность для группировки, может быть более читаемой:
non_sequence = pd.Series(df.index).diff() != 1
grouper = non_sequence.cumsum().values
dfs = [dfx for _ , dfx in df.groupby(grouper)]
groupby
Вы можете сделать идеально "последовательный" массив с помощью
np.arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
Если бы я вычел это из индекса, который монотонно увеличивается, только те элементы индекса, которые были «последовательными», будут отображаться как равные. Это умный способ установить ключ для группировки.
list_of_df = [d for _, d in df.groupby(df.index - np.arange(len(df)))]
И распечатайте каждый, чтобы доказать это
print(*list_of_df, sep='\n\n')
Column1 Column2
Index
4464 10.5 12.7
4465 11.3 12.8
4466 10.3 22.8
Column1 Column2
Index
5123 11.3 21.8
5124 10.6 22.4
Column1 Column2
Index
5323 18.6 23.5
np.split
Вы можете использовать np.flatnonzero
, чтобы определить, где различия не равны 1
, и избегать использования cumsum
и groupby
.
list_of_df = np.split(df, np.flatnonzero(np.diff(df.index) != 1) + 1)
Доказательство
print(*list_of_df, sep='\n\n')
Column1 Column2
Index
4464 10.5 12.7
4465 11.3 12.8
4466 10.3 22.8
Column1 Column2
Index
5123 11.3 21.8
5124 10.6 22.4
Column1 Column2
Index
5323 18.6 23.5
Извините, я не понимаю, если «предыдущий_индекс» всегда равен 0, поэтому вы никогда не должны получать x-previous_index == 1. Я попытался запустить ваш код, но не получил вашего решения, потому что условие никогда не проверяется, может быть, я делаю что-то не так?