Я новичок в пандах и типе файлов паркета. У меня есть скрипт на Python, который:
- читает в паркетном файле hdfs
- преобразует его в фреймворк pandas
- перебирает определенные столбцы и изменяет некоторые значения
- записывает фрейм данных обратно в паркетный файл
Затем файл паркета импортируется обратно в hdfs с помощью impala-shell.
Проблема, с которой я столкнулся, связана с шагом 2. Я распечатываю содержимое фрейма данных сразу после его считывания и до того, как на шаге 3 будут внесены какие-либо изменения. Похоже, что меняются типы данных и данные некоторые поля, что вызывает проблемы при записи обратно в паркетный файл. Примеры:
- поля, которые отображаются в базе данных как NULL, заменяются на string None (для строковых столбцов) или string nan (для числовых столбцов) в распечатке фрейма данных.
- поля, которые должны быть Int со значением 0 в базе данных, изменяются на 0,00000 и превращаются в число с плавающей запятой в кадре данных.
Похоже, что он на самом деле меняет эти значения, потому что, когда он записывает файл паркета, а я импортирую его в hdfs и запускаю запрос, я получаю такие ошибки:
WARNINGS: File '<path>/test.parquet' has an incompatible Parquet schema for column
'<database>.<table>.tport'. Column type: INT, Parquet schema:
optional double tport [i:1 d:1 r:0]
Я не знаю, почему это изменит данные, а не просто оставит их как есть. Если это то, что происходит, я не знаю, нужно ли мне перебирать каждый столбец и заменять все их исходными значениями, или есть другой способ сказать ему, чтобы он оставил их в покое.
Я использовал эту справочную страницу: http://arrow.apache.org/docs/python/parquet.html
Оно использует
pq.read_table(in_file)
прочитать паркетный файл, а затем
df = table2.to_pandas()
для преобразования в фрейм данных, который я могу перебирать и изменять столбцы. Я не понимаю, почему он меняет данные, и не могу найти способ предотвратить это. Есть ли другой способ чтения, кроме read_table?
Если я запрошу базу данных, данные будут выглядеть так:
tport |
---|
0 |
1 |
Моя строка print (df) для того же самого выглядит так:
tport |
---|
0.00000 |
nan |
nan |
1.00000 |
Вот соответствующий код. Я пропустил часть, которая обрабатывает аргументы командной строки, так как она длинная и не относится к этой проблеме. Передан файл in_file:
import sys, getopt
import random
import re
import math
import pyarrow.parquet as pq
import numpy as np
import pandas as pd
import pyarrow as pa
import os.path
# <CLI PROCESSING SECTION HERE>
# GET LIST OF COLUMNS THAT MUST BE SCRAMBLED
field_file = open('scrambler_columns.txt', 'r')
contents = field_file.read()
scrambler_columns = contents.split('\n')
def scramble_str(xstr):
#print(xstr + '_scrambled!')
return xstr + '_scrambled!'
parquet_file = pq.ParquetFile(in_file)
table2 = pq.read_table(in_file)
metadata = pq.read_metadata(in_file)
df = table2.to_pandas() #dataframe
print('rows: ' + str(df.shape[0]))
print('cols: ' + str(df.shape[1]))
pd.set_option('display.max_rows', None)
pd.set_option('display.max_columns', None)
pd.set_option('display.width', None)
pd.set_option('display.max_colwidth', -1)
pd.set_option('display.float_format', lambda x: '%.5f' % x)
#df.fillna(value='', inplace=True) # np.nan # \xa0
print(df) # print before making any changes
cols = list(df)
# https://pythonbasics.org/pandas-iterate-dataframe/
for col_name, col_data in df.iteritems():
#print(cols[index])
if col_name in scrambler_columns:
print('scrambling values in column ' + col_name)
for i, val in col_data.items():
df.at[i, col_name] = scramble_str(str(val))
print(df) # print after making changes
print(parquet_file.num_row_groups)
print(parquet_file.read_row_group(0))
# WRITE NEW PARQUET FILE
new_table = pa.Table.from_pandas(df)
writer = pq.ParquetWriter(out_file, new_table.schema)
for i in range(1):
writer.write_table(new_table)
writer.close()
if os.path.isfile(out_file) == True:
print('wrote ' + out_file)
else:
print('error writing file ' + out_file)
# READ NEW PARQUET FILE
table3 = pq.read_table(out_file)
df = table3.to_pandas() #dataframe
print(df)
EDIT Вот типы данных для первых нескольких столбцов в hdfs
и вот те же самые, что и в фрейме данных pandas:
id object
col1 float64
col2 object
col3 object
col4 float64
col5 object
col6 object
col7 object
Кажется, чтобы преобразовать
String to object
Int to float64
bigint to float64
Как я могу сказать пандам, какими типами данных должны быть столбцы?
Редактировать 2: мне удалось найти обходной путь, напрямую обработав таблицы Pyarrow. См. Мой вопрос и ответы здесь: Как обновить данные в pyarrow стол?
int
столбцах нули? Поддержка Pandas для int с нулевым значением является новой, и я считаю, что стрелка будет преобразовывать из int в float, если в столбце есть нули (так что nan доступен). Можете ли вы добавить выводprint(df.dtypes)
иprint(table2)
. Это покажет тип данных, который был в файле паркета, и типы данных, которые в конечном итоге использовали pandas. - person Pace   schedule 21.01.2021