#python-3.x #pandas
#python-3.x #pandas
Вопрос:
Мне нужно записать файлы, которые имеют формат с меткой, основанной на серии наборов, разделенных точками, и числовое значение, разделенное пробелом. Некоторые наборы могут быть строками или целыми числами, а значения могут быть целыми числами или числами с плавающей запятой
например:
a.1.1 0.19
a.1.2 1.23
1.5123.29 0
def write_myfile(df,file):
cols = df.columns[:-1]
df2 = pd.DataFrame()
df2['Labels'] = df[cols].apply(lambda x: '.'.join(x.dropna().astype(str).values.tolist()), axis=1)
df2['Values'] = df['value']
df2.to_csv(file,sep = ' ',header=False,index=False)
return dd
Итак, на данный момент я использую фрейм данных pandas с метками в первых столбцах и значением в конечном столбце. Это работает для небольших файлов, но невероятно неэффективно. Мне нужно записать файлы примерно в 3,5 миллиона строк.
Есть предложения?
Комментарии:
1. мой текущий метод повышения скорости заключается в записи файла в csv с использованием разделителя «.», затем прочитайте его снова, используя разделитель «,», указывающий dtype как string, затем объедините значения. это намного быстрее, но кажется немного ненадежным
Ответ №1:
Вы можете использовать понимание вложенного списка, потому что его нужно удалить NaN
.
Я думаю, у вас есть NaN в значениях, потому что используйте dropna
.
Сначала экспортируйте все столбцы без последнего в numpy array
by values
, а затем в list
. Последнее создание нового DataFrame
с помощью конструктора:
cols = df.columns[:-1]
a = pd.Series(['.'.join([str(y) for y in x if pd.notnull(y)])
for x in df[cols].values.tolist()])
b = df['value']
df = pd.DataFrame({'Labels' : a, 'Values' : b})
print (df)
Labels Values
0 a.1.1 0.19
1 1.2 1.23
2 a.1.1 0.19
3 1.2 1.23
4 1.5123.29 0.00
Тайминги:
(len(df)=5k)
:
In [280]: %timeit (orig(df))
1 loop, best of 3: 22.2 s per loop
In [281]: %timeit (jez(df1))
10 loops, best of 3: 145 ms per loop
df = pd.DataFrame({
'value': {0: 0.19, 1: 1.23, 2: 0.19, 3: 1.23, 4: 0.0},
's': {0: 1, 1: 2, 2: 1, 3: 2, 4: 29},
'b': {0: 1, 1: 1, 2: 1, 3: 1, 4: 5123},
'a': {0: 'a', 1: np.nan, 2: 'a', 3: np.nan, 4: '1'}})
print (df)
a b s value
0 a 1 1 0.19
1 NaN 1 2 1.23
2 a 1 1 0.19
3 NaN 1 2 1.23
4 1 5123 29 0.00
df = pd.concat([df]*10000).reset_index(drop=True)
df1 = df.copy()
def orig(df):
cols = df.columns[:-1]
df2 = pd.DataFrame()
df2['Labels'] = df[cols].apply(lambda x: '.'.join(x.dropna().astype(str).values.tolist()), axis=1)
df2['Values'] = df['value']
return (df2)
def jez(df):
cols = df.columns[:-1]
a = pd.Series(['.'.join([str(y) for y in x if pd.notnull(y)]) for x in df[cols].values.tolist()])
b = df['value']
df = pd.DataFrame({'Labels' : a, 'Values' : b})
return (df)
print (orig(df))
print (jez(df1))
Другое более эффективное решение, но оно зависит от данных, если работает для вас очень хорошо:
Сравните с помощью str(y) != 'nan'
вместо pd.notnull(y)
:
In [298]: %timeit (jez1(df1))
10 loops, best of 3: 114 ms per loop
def jez1(df):
cols = df.columns[:-1]
a = pd.Series(['.'.join([str(y) for y in x if str(y) != 'nan']) for x in df[cols].values.tolist()])
b = df['value']
df = pd.DataFrame({'Labels' : a, 'Values' : b})
return (df)
Комментарии:
1. потрясающе, это намного быстрее. a = pd.Series([‘.’.join([str(y) для y в x, если pd.notnull(y)]) для x в df[cols].значения. tolist()]) намного быстрее, чем df[cols].apply(лямбда x: ‘.’.join(x.dropna().astype(str).values. tolist()), axis=1) большое спасибо