фрейм данных pandas с 2-строчным заголовком и экспортом в csv

#python #pandas #dataframe #csv #export-to-csv

#python #csv #pandas #фрейм данных

Вопрос:

У меня есть фрейм данных

 df = pd.DataFrame(columns = ["AA", "BB", "CC"])
df.loc[0]= ["a", "b", "c1"]
df.loc[1]= ["a", "b", "c2"]
df.loc[2]= ["a", "b", "c3"]
  

Мне нужно добавить строку secod в заголовок

 df.columns = pd.MultiIndex.from_tuples(zip(df.columns, ["DD", "EE", "FF"]))
  

теперь мой df

   AA BB  CC
  DD EE  FF
0  a  b  c1
1  a  b  c2
2  a  b  c3
  

но когда я записываю этот фрейм данных в файл csv

 df.to_csv("test.csv", index = False)
  

Я получаю на одну строку больше, чем ожидалось

 AA,BB,CC
DD,EE,FF
,,
a,b,c1
a,b,c2
a,b,c3
  

Комментарии:

1. Это определенно похоже на ошибку, поэтому рекомендуется опубликовать это как проблему github.

2. любой обходной путь, как получить ожидаемый формат без этой дополнительной строки?

3. Я знаю, что опоздал на вечеринку. Но я искал решение той же проблемы. В Pandas 0.19.0 и выше эта проблема исправлена

Ответ №1:

Это уродливый взлом, но если вам нужно что-то для работы прямо сейчас ™, вы можете записать это в двух частях:

 >>> pd.DataFrame(df.columns.tolist()).T.to_csv("noblankrows.csv", mode="w", header=False, index=False)
>>> df.to_csv("noblankrows.csv", mode="a", header=False, index=False)
>>> !cat noblankrows.csv
AA,BB,CC
DD,EE,FF
a,b,c1
a,b,c2
a,b,c3
  

Комментарии:

1. лол, щелчок! Хотя это более аккуратный способ записи заголовка!

2. Будьте осторожны… Я попробовал это, и он переупорядочил заголовки в алфавитном порядке, которые затем не совпадали со значениями столбцов.

Ответ №2:

Я думаю, что это ошибка to_csv . Если вы ищете обходные пути, то вот пара.

Для обратного чтения в этом csv укажите строки заголовка*:

 In [11]: csv = "AA,BB,CC
DD,EE,FF
,,
a,b,c1
a,b,c2
a,b,c3"

In [12]: pd.read_csv(StringIO(csv), header=[0, 1])
Out[12]:
  AA BB  CC
  DD EE  FF
0  a  b  c1
1  a  b  c2
2  a  b  c3
  

* как ни странно, это, похоже, игнорирует пустые строки.

Для записи вы можете сначала написать заголовок, а затем добавить:

 with open('test.csv', 'w') as f:
    f.write('n'.join([','.join(h) for h in zip(*df.columns)])   'n')
df.to_csv('test.csv', mode='a', index=False, header=False)
  

Обратите внимание на to_csv часть для столбца MultiIndex здесь:

 In [21]: 'n'.join([','.join(h) for h in zip(*df.columns)])   'n'
Out[21]: 'AA,BB,CCnDD,EE,FFn'
  

Комментарии:

1. это не ошибка, это определенный формат, вы можете указать tupleize_cols=True , чтобы он записывал заголовок с несколькими индексами в виде одной строки.

2. @Jeff речь идет не о том, чтобы сделать его в виде одной строки: попробуйте без tupleize_cols, он добавляет строку ,,,, в csv (ошибка ??).

3. имена отсутствуют, но у него все еще ЕСТЬ имена. это не ошибка. Для точного воспроизведения должна быть строка. оказывается, что читатель может читать любой формат. Это открытая проблема, чтобы НЕ печатать пустую строку, что является стилистической проблемой. читатель устойчив к этому. не указание заголовка в столбцах с несколькими индексами является ошибкой ПОЛЬЗОВАТЕЛЯ. это не ошибка.

Ответ №3:

Используйте df.to_csv("test.csv", index = False, tupleize_cols=True) , чтобы получить результирующий CSV-файл:

 "('AA', 'DD')","('BB', 'EE')","('CC', 'FF')"
a,b,c1
a,b,c2
a,b,c3
  

Чтобы прочитать его обратно:

 df2=pd.read_csv("test.csv", tupleize_cols=True)
df2.columns=pd.MultiIndex.from_tuples(eval(','.join(df2.columns)))
  

Чтобы получить точный результат, который вы хотели:

 with open('test.csv', 'a') as f:
    pd.DataFrame(np.asanyarray(df.columns.tolist())).T.to_csv(f, index = False, header=False)
    df.to_csv(f, index = False, header=False)
  

Комментарии:

1. В любом случае это не было бы хорошим способом записи в CSV, потому что вам также будет трудно прочитать его обратно. См. Редактирование.

2. Да, вы получите то же df самое, если это то, о чем вы спрашиваете. См. Редактирование

3. извините, но я этим не удовлетворен .. мне действительно нужен результат, как описано, потому что это вход для другого приложения, панды не читают обратно..

4. См. Редактирование. Вы можете сделать это в два этапа, написать заголовок, затем тело.

Ответ №4:

Построение поверх решения @DSM:

если вам нужно (как и мне) применить тот же хак к экспорту в Excel, основное необходимое изменение (помимо ожидаемых различий с методом to_excel) — это фактически удалить мультииндекс, используемый для меток ваших столбцов…

Это потому, что .to_excel не поддерживает запись df, имеющего мультииндекс для столбцов, но без индекса (предоставляя index=False для метода .to_excel) в отличие от .to_csv

В любом случае, вот как это будет выглядеть:

 >>> writer = pd.ExcelWriter("noblankrows.xlsx")
>>> headers = pd.DataFrame(df.columns.tolist()).T
>>> headers.to_excel(
        writer, header=False, index=False)
>>> df.columns = pd.Index(range(len(df.columns)))  # that's what I was referring to...
>>> df.to_excel(
        writer, header=False, index=False, startrow=len(headers))
>>> writer.save()
>>> pd.read_excel("noblankrows.xlsx").to_csv(sys.stdout, index=False)
AA,BB,CC
DD,EE,FF
a,b,c1
a,b,c2
a,b,c3