Это странный вопрос, но я получаю странные результаты. У меня есть фрейм данных, содержащий данные для баскетбольных игр в колледже:
game_id season home_team away_team net_ortg net_drtg clock period home visitor ... total_seconds_elapsed win lead p_1 p_2 p_3 p_4 p_5 p_6 total_pts
627168 401173715 2020 Air Force UC Riverside 12.0 10.5 00:06:34 1 37 24 ... 806 1 13 1 0 0 0 0 0 61
320163 401174714 2020 Arkansas State Idaho 11.4 0.4 00:01:42 2 76 67 ... 2298 1 9 0 1 0 0 0 0 143
26942 401169867 2020 Vanderbilt Tulsa 1.5 10.9 00:07:50 1 24 18 ... 730 0 6 1 0 0 0 0 0 42
213142 401170184 2020 La Salle Wagner 2.3 -13.5 00:10:19 2 57 36 ... 1781 1 21 0 1 0 0 0 0 93
1631866 401255594 2021 Virginia Tech South Florida 8.4 -1.5 00:19:32 1 2 0 ... 28 1 2 1 0 0 0 0 0 2
1644302 401263600 2021 Nebraska South Dakota 1.2 -8.1 00:14:51 1 9 11 ... 309 1 -2 1 0 0 0 0 0 20
1181057 401170704 2020 Colorado Stanford 4.7 3.1 00:14:22 1 6 4 ... 338 1 2 1 0 0 0 0 0 10
1670578 401266749 2021 Texas Tech Troy 15.2 -17.9 00:07:54 2 67 33 ... 1926 1 34 0 1 0 0 0 0 100
27199 401170392 2020 Florida Gulf Coast Campbell -5.6 -2.0 00:17:46 1 2 0 ... 134 0 2 1 0 0 0 0 0 2
1588187 401262682 2021 UNLV Montana State 4.5 -0.8 00:02:54 1 23 39 ... 1026 0 -16 1 0 0 0 0 0 62
Я использую test_train_split из sklearn, чтобы разделить фрейм данных на game_id, чтобы я мог выполнять некоторые задачи ML.
train_id, test_id = train_test_split(list(df.game_id), test_size=0.1)
train_mask = df['game_id'].isin(list(train_id))
test_mask = df['game_id'].isin(list(test_id))
print(df.shape)
print(len(train_id))
print(len(test_id))
>>(1326422, 22)
>>1193779
>>132643
Вот странная вещь (или, по крайней мере, часть, которую я не понимаю):
>>train_mask.describe()
count 1326422
unique 1
top True
freq 1326422
Name: game_id, dtype: object
>>test_mask.describe()
count 1326422
unique 1
top True
freq 1326422
Name: game_id, dtype: object
Хорошо, но что, если я сделаю то же самое, но ограничу размер train_id:
train_mask = df['game_id'].isin(list(train_id[0:100]))
train_mask.describe()
count 1326422
unique 2
top False
freq 1302107
Name: game_id, dtype: object
И просто проверить еще раз, используя индексацию массива в полном списке:
train_mask = df['game_id'].isin(list(train_id[0:-1]))
train_mask.describe()
count 1326422
unique 1
top True
freq 1326422
Name: game_id, dtype: object
На всю жизнь я не могу понять, что происходит, если только нет каких-либо ограничений на размер запросов, которые панды могут выполнять. Помощь!
Обновлено: похоже, что точный размер, в котором происходит это поведение, составляет 54 665:
>>train_mask = df['game_id'].isin(list(train_id[0:54665]))
>>train_mask.describe()
count 1326422
unique 2
top True
freq 1326180
Name: game_id, dtype: object
>>train_mask = df['game_id'].isin(list(train_id[0:54666]))
>>train_mask.describe()
count 1326422
unique 1
top True
freq 1326422
Name: game_id, dtype: object
Действительно странно!
Я считаю, что ваша маска представляет собой набор значений True False, которые являются длиной DataFrame. Когда вы ограничиваете размер train_id, вы просто уменьшаете количество значений True, а не уменьшаете длину маски. Попробуйте выполнить следующие действия для подтверждения:
print(len(df['game_id'].isin(list(train_id[0:100]))))
print(len(df['game_id'].isin(list(train_id[0:-1]))))
А затем, чтобы увидеть, сколько у вас истинных значений (сумма работает здесь, потому что True оценивается как 1, а False как 0):
df['game_id'].isin(list(train_id[0:100])).sum()
df['game_id'].isin(list(train_id[0:-1])).sum()
Pd.Series.isin возвращает логический ряд той же длины, что и все, что вы проверяли. Таким образом, вы не измените форму чего-либо, пока не нарежете свой DataFrame: df_train = df[train_mask]
Чтобы прояснить несколько вещей, вывод describe отображает следующее:
import pandas as pd
s = pd.Series([True]*10 + [False]*6)
s.describe()
#count 16 # length of the Series
#unique 2 # Number of unique values in the Series
#top True # Most common value
#freq 10 # How many times does the most common value appear
#dtype: object
Таким образом, проверка разных идентификаторов никогда не изменит количество. Но уникальные, верхние и частотные меняются, чтобы отразить тот факт, что меняется сама ваша маска.
Количество не меняется, но посмотрите на частоту и количество различных значений, которые я опубликовал. Это не имеет смысла.
@EvanZamir Я могу почти гарантировать, что проблема не в пандах, налагающих какие-либо ограничения, а в неправильном понимании данных или того, как работает метод. Например, если game_id сильно дублируется в вашем DataFrame, то, как вы делаете выборку, вероятно, один и тот же game_id появляется как в обучающем, так и в тестовом наборах. т.е. может быть, вы хотите что-то вроде train_test_split(df.game_id.unique().tolist(), 0.1)
Ах! Да, это проблема. Я тупой лол.
Я просто добавляю решение ALollz, чтобы показать вам кадры данных (так что примите его/ее ответ). Как уже говорилось, это вернет серию True и False:
import pandas as pd
df = pd.DataFrame(
[['401173715', '2020', 'Air Force'],
['401174714' , '2020', 'Arkansas State'],
['401169867' , '2020', 'Vanderbilt'],
['401170184' , '2020', 'La Salle'],
['401255594' , '2021', 'Virginia Tech'],
['401263600' , '2021', 'Nebraska'],
['401170704' , '2020', 'Colorado'],
['401266749' , '2021', 'Texas Tech'],
['401170392' , '2020', 'Florida Gulf'],
['401262682' , '2021', 'UNLV']],
columns = ['game_id', 'season', 'home_team' ])
from sklearn.model_selection import train_test_split
train_id, test_id = train_test_split(list(df.game_id), test_size=0.1)
train_mask = df['game_id'].isin(list(train_id))
test_mask = df['game_id'].isin(list(test_id))
Так что описание правильное, как описывает ALollz. Имеет 2 уникальных значения (True, False), а счетчики верхних значений либо True, либо False, в зависимости от того, на какую маску вы смотрите, и количество одинаково, а частота будет меняться. теперь, если вы ограничите количество строк и не включите последнюю строку (индекс 10), у вас останется только 1 уникальное значение в каждом наборе данных.
Теперь я предполагаю, что вы хотите получить эти строки (где это правда). Итак, вам нужно изменить синтаксис на:
train_mask = df[df['game_id'].isin(list(train_id))]
test_mask = df[df['game_id'].isin(list(test_id))]
Это даст вам 2 фрейма данных с train_ids и тестовыми идентификаторами:
Так что поиграйте с этим кодом, чтобы увидеть:
import pandas as pd
df = pd.DataFrame(
[['401173715', '2020', 'Air Force'],
['401174714' , '2020', 'Arkansas State'],
['401169867' , '2020', 'Vanderbilt'],
['401170184' , '2020', 'La Salle'],
['401255594' , '2021', 'Virginia Tech'],
['401263600' , '2021', 'Nebraska'],
['401170704' , '2020', 'Colorado'],
['401266749' , '2021', 'Texas Tech'],
['401170392' , '2020', 'Florida Gulf'],
['401262682' , '2021', 'UNLV']],
columns = ['game_id', 'season', 'home_team' ])
from sklearn.model_selection import train_test_split
train_id, test_id = train_test_split(list(df.game_id), test_size=0.1)
train_mask = df['game_id'].isin(list(train_id))
test_mask = df['game_id'].isin(list(test_id))
df_train = df[train_mask]
df_test = df[test_mask]
Это именно то, что я делаю. Это не работает, когда я использую весь фрейм данных.
Какая у тебя версия панд?
Извините, это была моя ошибка, а не панды. Мне нужно было сделать df.game_id.unique(), поскольку, должно быть, происходило то, что одни и те же идентификаторы отбирались в поезде и тесте. Виноват!
Ах поймал. Прохладный.
Если game_id не является уникальным идентификатором, вы можете получить одни и те же game_id как в поезде, так и в тестовом наборе, что, вероятно, приведет к тому, что одни и те же записи окажутся как в поезде, так и в тестовом наборе. Вместо этого создал train_test_split на уникальных game_ids.
train_id, test_id = train_test_split(df.game_id.unique(), test_size=0.1)
Извините, да, это не был уникальный идентификатор. Так что это было причиной проблемы. Мне нужно было разделить на уникальные идентификаторы.
Это действительно полезная информация - обновил мой ответ, основываясь на том, что может быть вашей истинной проблемой.
Когда я пытаюсь использовать маску для фильтрации df, это не работает. Это проблема. Он просто сохраняет все строки. Когда я это делаю df[df['game_id'].isin(list(train_id))].shape, получается точно такая же форма, как и у самого df.