У меня есть большой пандан DataFrame с формой (700 000, 5000), содержащий столбцы смешанных dtypes (в основном int8, некоторые float64 и пару datetime64 [ns]). Для каждой строки в кадре данных я хочу установить значение некоторых столбцов равным нулю, если другой столбец также равен нулю.
Если я переберу данные и установлю значения с помощью iloc, это будет очень медленно. Я пробовал и iterrows и itertuples, например.
1. iterrows
ix_1 = 3
ix_to_change = [20, 24, 51] # Actually it is almost 5000 columns to change
for i, row in df.iterrows():
if not row[ix_1]:
df.iloc[i, ix_to_change] = 0
2. itertuples:
ix_1 = 3
ix_to_change = [20, 24, 51] # Actually it is almost 5000 columns to change
for row in df.itertuples():
if not row[ix_1 + 1]:
df.iloc[row[0], ix_to_change] = 0
Я также пытался использовать индексацию панд, но она также очень медленная (хотя лучше, чем iterrows или itertuples).
3. Pandas Loc & iloc
df.loc[df.iloc[:, ix_1]==0, df.columns[ix_to_change]] = 0
Затем я попытался перейти к базовому массиву numpy, который прекрасно работает с точки зрения производительности, но у меня возникли проблемы с dtypes.
Он быстро перебирает базовый массив, но новый фрейм данных имеет все dty-типы 'object'. Если я попытаюсь установить dtypes для каждого столбца (как в этом примере), он потерпит неудачу в столбцах datetime - возможно, потому что они содержат элементы NaT.
4. NumPy
X = df.values
for i, x in enumerate(X):
if not x[ix_1]:
X[i].put(ix_to_change, 0)
original_dtypes = df.dtypes
df = pd.DataFrame(data=X, index=df.index, columns=df.columns)
for col, col_dtype in original_dtypes.items():
df[c] = df[c].astype(col_dtype)
Есть ли лучший способ для меня сделать обновление в первую очередь?
Или, если нет, как мне сохранить мои dtypes одинаковыми (столбцы даты и времени не должны изменяться в списке столбцов в случае необходимости)
Или, может быть, есть лучший способ обновить исходный фрейм данных с помощью моего обновленного массива numpy, где я обновляю только измененные столбцы (все из которых являются int8)?
Обновление
Как и было запрошено в комментариях, вот минимальный пример, иллюстрирующий, как dtypes int8 становятся dtypes объекта после перехода в numpy. Чтобы было ясно, это проблема только для метода 4 выше (который является единственным медленным методом, который у меня был до сих пор - если я могу исправить эту проблему dtype):
import pandas as pd
df = pd.DataFrame({'int8_col':[10,11,12], 'float64_col':[1.5, 2.5, 3.5]})
df['int8_col'] = df['int8_col'].astype('int8')
df['datetime64_col'] = pd.to_datetime(['2018-01-01', '2018-01-02', '2018-01-03'])
>>> df.dtypes
float64_col float64
int8_col int8
datetime64_col datetime64[ns]
dtype: object
X = df.values
# At this point in real life I modify the int8 column(s) only in X
new_df = pd.DataFrame(data=X, index=df.index, columns=df.columns)
>>> new_df.dtypes
float64_col object
int8_col object
datetime64_col object
dtype: object