изменить тип данных столбцов в pandas

<p>я хочу преобразовать таблицу, представленную в виде списка списков, в pandas dataframe. в качестве чрезвычайно упрощенного примера:</p><pre><code>a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']] df = pd.dataframe(a) </code></pre><p>каков наилучший способ преобразования столбцов в соответствующие типы, в данном случае столбцы 2 и 3 в числа с плавающей точкой? есть ли способ указать типы при конвертации в dataframe? или лучше сначала создать dataframe, а затем перебрать столбцы, чтобы изменить тип каждого столбца? в идеале я хотел бы сделать это динамически, потому что может быть сотни столбцов, и я не хочу точно указывать, какие столбцы какого типа. все, что я могу гарантировать, это то, что каждый столбец содержит значения одного типа.</p>

<p>у вас есть три основных варианта для преобразования типов в пандах.</p><hr><h1>1. <code>to\_numeric()</code></h1><p>лучший способ преобразовать один или несколько столбцов объекта dataframe в числовые значения - использовать <a href="http://pandas.pydata.org/pandas-docs/stable/generated/pandas.to\_numeric.html"><code>pandas.to\_numeric()</code></a> .</p><p>эта функция попытается изменить нечисловые объекты (например, строки) на целые числа или числа с плавающей запятой, в зависимости от ситуации.</p><h2>основное использование</h2><p>входные данные для <code>to\_numeric()</code> - это series или отдельный столбец dataframe. </p><pre><code>>>> s = pd.series(["8", 6, "7.5", 3, "0.9"]) # mixed string and numeric values >>> s 0 8 1 6 2 7.5 3 3 4 0.9 dtype: object >>> pd.to\_numeric(s) # convert everything to float values 0 8.0 1 6.0 2 7.5 3 3.0 4 0.9 dtype: float64 </code></pre><p>как видите, новая серия возвращается. не забудьте назначить этот вывод имени переменной или столбца, чтобы продолжить его использовать:</p><pre><code># convert series my\_series = pd.to\_numeric(my\_series) # convert column "a" of a dataframe df["a"] = pd.to\_numeric(df["a"]) </code></pre><p>вы также можете использовать его для преобразования нескольких столбцов dataframe с помощью метода <code>apply()</code>:</p><pre><code># convert all columns of dataframe df = df.apply(pd.to\_numeric) # convert all columns of dataframe # convert just columns "a" and "b" df[["a", "b"]] = df[["a", "b"]].apply(pd.to\_numeric) </code></pre><p>пока ваши значения могут быть преобразованы, это, вероятно, все, что вам нужно.</p><h2>обработка ошибок</h2><p>но что, если некоторые значения не могут быть преобразованы в числовой тип?</p><p><code>to\_numeric()</code> также принимает аргумент ключевого слова <code>errors</code>, который позволяет принудительно устанавливать нечисловые значения как <code>nan</code> или просто игнорировать столбцы, содержащие эти значения.</p><p>вот пример с использованием серии строк <code>s</code>, которая имеет объект dtype:</p><pre><code>>>> s = pd.series(['1', '2', '4.7', 'pandas', '10']) >>> s 0 1 1 2 2 4.7 3 pandas 4 10 dtype: object </code></pre><p>поведение по умолчанию - повышение, если оно не может преобразовать значение. в этом случае он не может справиться со строкой 'pandas':</p><pre><code>>>> pd.to\_numeric(s) # or pd.to\_numeric(s, errors='raise') valueerror: unable to parse string </code></pre><p>вместо того, чтобы терпеть неудачу, мы могли бы хотеть, чтобы 'панды' считались отсутствующим/плохим числовым значением. мы можем привести неверные значения к <code>nan</code> следующим образом, используя аргумент ключевого слова <code>errors</code>:</p><pre><code>>>> pd.to\_numeric(s, errors='coerce') 0 1.0 1 2.0 2 4.7 3 nan 4 10.0 dtype: float64 </code></pre><p>третий вариант для <code>errors</code> просто игнорирует операцию, если встречается недопустимое значение:</p><pre><code>>>> pd.to\_numeric(s, errors='ignore') # the original series is returned untouched </code></pre><p>этот последний вариант особенно полезен, когда вы хотите преобразовать весь свой dataframe, но не знаете, какие из наших столбцов можно надежно преобразовать в числовой тип. в этом случае просто напишите:</p><pre><code>df.apply(pd.to\_numeric, errors='ignore') </code></pre><p>функция будет применена к каждому столбцу dataframe. столбцы, которые можно преобразовать в числовой тип, будут преобразованы, тогда как столбцы, которые не могут (например, содержат нецифровые строки или даты), будут оставлены в покое.</p><h2>понижающее приведение</h2><p>по умолчанию преобразование с <code>to\_numeric()</code> даст вам <code>int64</code> или <code>float64</code> dtype (или любую целую ширину, присущую вашей платформе).</p><p>обычно это то, что вы хотите, но что, если вы хотите сэкономить память и использовать более компактный тип dtype, например <code>float32</code> или <code>int8</code>?</p><p><code>to\_numeric()</code> дает вам возможность понижать до целых чисел, со знаком, без знака, с плавающей точкой. вот пример для простой серии <code>s</code> целочисленного типа:</p><pre><code>>>> s = pd.series([1, 2, -7]) >>> s 0 1 1 2 2 -7 dtype: int64 </code></pre><p>при понижении до целочисленного значения используется наименьшее возможное целое число, которое может содержать значения:</p><pre><code>>>> pd.to\_numeric(s, downcast='integer') 0 1 1 2 2 -7 dtype: int8 </code></pre><p>при даункинге с плавающей точкой аналогично выбирается плавающий тип меньше обычного:</p><pre><code>>>> pd.to\_numeric(s, downcast='float') 0 1.0 1 2.0 2 -7.0 dtype: float32 </code></pre><hr><h1>2. <code>astype()</code></h1><p>метод <a href="https://pandas.pydata.org/pandas-docs/stable/generated/pandas.dataframe.astype.html"><code>astype()</code></a> позволяет вам явно указывать dtype, который вы хотите иметь в своем dataframe или series. он очень универсален в том, что вы можете попробовать перейти от одного типа к другому.</p><h2>основное использование</h2><p>просто выберите тип: вы можете использовать dum типа numpy (например, <code>np.int16</code>), некоторые типы python (например, bool) или типы, специфичные для панд (например, категориальный dtype).</p><p>вызовите метод для объекта, который вы хотите преобразовать, и <code>astype()</code> попытается преобразовать его для вас:</p><pre><code># convert all dataframe columns to the int64 dtype df = df.astype(int) # convert column "a" to int64 dtype and "b" to complex type df = df.astype({"a": int, "b": complex}) # convert series to float16 type s = s.astype(np.float16) # convert series to python strings s = s.astype(str) # convert series to categorical type - see docs for more details s = s.astype('category') </code></pre><p>заметьте, я сказал «попробуй» - если <code>astype()</code> не знает, как преобразовать значение в series или dataframe, это вызовет ошибку. например, если у вас есть значение <code>nan</code> или <code>inf</code>, вы получите сообщение об ошибке при попытке преобразовать его в целое число.</p><p>начиная с панд 0.20.0, эту ошибку можно устранить, передав <code>errors='ignore'</code>. ваш оригинальный объект будет возвращен нетронутым.</p><h2>быть осторожен</h2><p><code>astype()</code> мощный, но иногда он будет преобразовывать значения «неправильно». например:</p><pre><code>>>> s = pd.series([1, 2, -7]) >>> s 0 1 1 2 2 -7 dtype: int64 </code></pre><p>это небольшие целые числа, так как насчет преобразования в 8-битный тип без знака для экономии памяти?</p><pre><code>>>> s.astype(np.uint8) 0 1 1 2 2 249 dtype: uint8 </code></pre><p>преобразование сработало, но значение -7 было округлено до 249 (т.е. 2<sup>8</sup> - 7)! </p><p>попытка уменьшить использование <code>pd.to\_numeric(s, downcast='unsigned')</code> вместо этого может помочь предотвратить эту ошибку.</p><hr><h1>3. <code>infer\_objects()</code></h1><p>в версии 0.21.0 pandas появился метод <a href="https://pandas.pydata.org/pandas-docs/stable/generated/pandas.dataframe.infer\_objects.html"><code>infer\_objects()</code></a> для преобразования столбцов объекта dataframe, имеющих тип данных объекта, в более конкретный тип (мягкие преобразования).</p><p>например, вот dataframe с двумя столбцами типа объекта. один содержит действительные целые числа, а другой содержит строки, представляющие целые числа:</p><pre><code>>>> df = pd.dataframe({'a': [7, 1, 5], 'b': ['3','2','1']}, dtype='object') >>> df.dtypes a object b object dtype: object </code></pre><p>используя <code>infer\_objects()</code>, вы можете изменить тип столбца 'a' на int64:</p><pre><code>>>> df = df.infer\_objects() >>> df.dtypes a int64 b object dtype: object </code></pre><p>столбец «b» остался один, поскольку его значения были строками, а не целыми числами. если вы хотите попытаться принудительно преобразовать оба столбца в целочисленный тип, вы можете использовать вместо него функцию <code>df.astype(int)</code>.</p>

<p>как насчет этого? </p><pre class="lang-py prettyprint-override"><code>a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']] df = pd.dataframe(a, columns=['one', 'two', 'three']) df out[16]: one two three 0 a 1.2 4.2 1 b 70 0.03 2 x 5 0 df.dtypes out[17]: one object two object three object df[['two', 'three']] = df[['two', 'three']].astype(float) df.dtypes out[19]: one object two float64 three float64 </code></pre>

<p>этот код ниже изменит тип данных столбца.</p><pre><code>df[['col.name1', 'col.name2'...]] = df[['col.name1', 'col.name2'..]].astype('data\_type') </code></pre><p>вместо типа данных вы можете указать свой тип данных. что вы хотите, например, str, float, int и т. д.</p>

<p>вот функция, которая принимает в качестве аргументов объект dataframe и список столбцов и приводит все данные в столбцах к числам.</p><pre><code># df is the dataframe, and column\_list is a list of columns as strings (e.g ["col1","col2","col3"]) # dependencies: pandas def coerce\_df\_columns\_to\_numeric(df, column\_list): df[column\_list] = df[column\_list].apply(pd.to\_numeric, errors='coerce') </code></pre><p>итак, для вашего примера:</p><pre><code>import pandas as pd def coerce\_df\_columns\_to\_numeric(df, column\_list): df[column\_list] = df[column\_list].apply(pd.to\_numeric, errors='coerce') a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']] df = pd.dataframe(a, columns=['col1','col2','col3']) coerce\_df\_columns\_to\_numeric(df, ['col2','col3']) </code></pre>

<p>как насчет создания двух фреймов данных, каждый с разными типами данных для своих столбцов, а затем их объединения?</p><pre><code>d1 = pd.dataframe(columns=[ 'float\_column' ], dtype=float) d1 = d1.append(pd.dataframe(columns=[ 'string\_column' ], dtype=str)) </code></pre><p><strong> результаты </strong></p><pre><code>in[8}: d1.dtypes out[8]: float\_column float64 string\_column object dtype: object </code></pre><p>после создания информационного кадра вы можете заполнить его переменными с плавающей запятой в 1-м столбце и строками (или любым другим типом данных) во 2-м столбце. </p>

<p>когда мне нужно было указать только определенные столбцы, и я хочу быть явным, я использовал (для <a href="https://pandas.pydata.org/pandas-docs/stable/generated/pandas.dataframe.astype.html">docs location</a> ):</p><pre><code>dataframe = dataframe.astype({'col\_name\_1':'int','col\_name\_2':'float64', etc. ...}) </code></pre><p>итак, используя оригинальный вопрос, но предоставив ему имена столбцов ...</p><pre><code>a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']] df = pd.dataframe(a, columns=['col\_name\_1', 'col\_name\_2', 'col\_name\_3']) df = df.astype({'col\_name\_2':'float64', 'col\_name\_3':'float64'}) </code></pre>

<p>я думал, что у меня та же проблема, но на самом деле у меня есть небольшая разница, которая облегчает решение проблемы. для других, смотрящих на этот вопрос, стоит проверить формат вашего списка ввода. в моем случае числа изначально плавающие, а не строки, как в вопросе:</p><pre><code>a = [['a', 1.2, 4.2], ['b', 70, 0.03], ['x', 5, 0]] </code></pre><p>но слишком много обрабатывая список перед созданием кадра данных, я теряю типы, и все становится строкой. </p><p>создание фрейма данных через массив numpy</p><pre><code>df = pd.dataframe(np.array(a)) df out[5]: 0 1 2 0 a 1.2 4.2 1 b 70 0.03 2 x 5 0 df[1].dtype out[7]: dtype('o') </code></pre><p>дает тот же кадр данных, что и в вопросе, где записи в столбцах 1 и 2 рассматриваются как строки. однако делать</p><pre><code>df = pd.dataframe(a) df out[10]: 0 1 2 0 a 1.2 4.20 1 b 70.0 0.03 2 x 5.0 0.00 df[1].dtype out[11]: dtype('float64') </code></pre><p>на самом деле дает кадр данных со столбцами в правильном формате</p>