Преобразовать столбец списка в несколько столбцов в кадре данных в Python [duplicate]

Мой ответ довольно длинный, поэтому я разделил его на три раздела. Поскольку вопрос касается математики с плавающей запятой, я делаю акцент на том, что на самом деле делает машина. Я также сделал это для двойной точности (64 бит), но этот аргумент применим в равной степени к любой арифметике с плавающей запятой.

Преамбула

IEEE 754 номер двойной бинарной с плавающей запятой (binary64) представляет собой номер формы

value = (-1) ^ s * (1.m51m50 ... m2m1m0 ) 2 * 2e-1023

в 64 бит:

  • Первый бит является битом знака : 1, если число отрицательно, 0 в противном случае.
  • Следующие 11 бит являются показателем , который является offset на 1023. Другими словами, после чтение битов экспоненты из числа двойной точности 1023 должно быть вычтено для получения мощности двух.
  • Остальные 52 бита представляют собой значение (или мантисса). В мантиссе «подразумеваемый» 1. всегда пропускается, поскольку самый старший бит любого двоичного значения равен 1.

1 - IEEE 754 допускает концепцию с нулевым значением - +0 и -0 обрабатываются по-разному: 1 / (+0) - положительная бесконечность; 1 / (-0) - отрицательная бесконечность. Для нулевых значений биты мантиссы и экспоненты равны нулю. Примечание: нулевые значения (+0 и -0) явно не классифицируются как denormal2.

2 - Это не относится к денормальным номерам , которые имеют показатель смещения нуля (и подразумевается 0.). Диапазон денормальных чисел двойной точности dmin ≤ | x | ≤ dmax, где dmin (наименьшее представимое ненулевое число) составляет 2-1023 - 51 (≈ 4,94 * 10-324) и dmax (наибольшее денормальное число, для которого мантисса полностью состоит из 1 s) составляет 2-1023 + 1 - 2-1023 - 51 (≈ 2.225 * 10-308).


Превращение числа двойной точности в двоичный

Существует множество онлайн-конвертеров для преобразования двойной точности (например, в binaryconvert.com ), но здесь приведен пример кода C # для получения представления IEEE 754 для числа двойной точности (я разделяю три части с двоеточиями (: ):

public static string BinaryRepresentation(double value)
{
    long valueInLongType = BitConverter.DoubleToInt64Bits(value);
    string bits = Convert.ToString(valueInLongType, 2);
    string leadingZeros = new string('0', 64 - bits.Length);
    string binaryRepresentation = leadingZeros + bits;

    string sign = binaryRepresentation[0].ToString();
    string exponent = binaryRepresentation.Substring(1, 11);
    string mantissa = binaryRepresentation.Substring(12);

    return string.Format("{0}:{1}:{2}", sign, exponent, mantissa);
}

Достижение точки: исходный вопрос

(Перейти к нижней части для версии TL; DR)

Катон Джонстон (вопросник) спросил, почему 0.1 + 0.2! = 0.3.

Написано в двоичном (с двоеточиями, разделяющими три части), представления IEEE 754 значений:

0.1 => 0:01111111011:1001100110011001100110011001100110011001100110011010
0.2 => 0:01111111100:1001100110011001100110011001100110011001100110011010

Обратите внимание, что мантисса состоит из повторяющихся цифр 0011. ключ к тому, почему есть какие-либо ошибки в расчетах - 0,1, 0,2 и 0,3 не могут быть представлены в двоичной форме точно в конечном числе двоичных битов не более 1/9, 1/3 или 1/7 могут быть представлены точно в десятичных разрядах .

Преобразование экспонентов в десятичные, удаление смещения и повторное добавление подразумеваемых 1 (в квадратных скобках), 0,1 и 0,2 :

0.1 = 2^-4 * [1].1001100110011001100110011001100110011001100110011010
0.2 = 2^-3 * [1].1001100110011001100110011001100110011001100110011010

Чтобы добавить два числа, показатель должен быть одинаковым, т. е.

0.1 = 2^-3 *  0.1100110011001100110011001100110011001100110011001101(0)
0.2 = 2^-3 *  1.1001100110011001100110011001100110011001100110011010
sum = 2^-3 * 10.0110011001100110011001100110011001100110011001100111

Поскольку сумма не имеет вид 2n * 1. { bbb} мы увеличиваем показатель на единицу и сдвигаем десятичную ( двоичную ) точку, чтобы получить:

sum = 2^-2 * 1.0011001100110011001100110011001100110011001100110011(1)

В мантиссе сейчас 53 бит (53-й квадрат скобки в строке выше). Режим округления по умолчанию для IEEE 754 равен ' Round to Nearest ' - то есть, если число x падает между двумя значениями a и b выбрано значение, в котором наименьший значащий бит равен нулю.

a = 2^-2 * 1.0011001100110011001100110011001100110011001100110011
x = 2^-2 * 1.0011001100110011001100110011001100110011001100110011(1)
b = 2^-2 * 1.0011001100110011001100110011001100110011001100110100

Обратите внимание, что a и b отличаются только последним битом; ...0011 + 1 = ...0100. В этом случае значение с младшим значащим разрядом равно b , поэтому сумма равна:

sum = 2^-2 * 1.0011001100110011001100110011001100110011001100110100

TL; DR

Запись 0.1 + 0.2 в двоичном представлении IEEE 754 (с двоеточиями, разделяющими три части) и сравнивая его с 0.3, это (я положил отдельные биты в квадратные скобки):

0.1 + 0.2 => 0:01111111101:0011001100110011001100110011001100110011001100110[100]
0.3       => 0:01111111101:0011001100110011001100110011001100110011001100110[011]

Преобразован обратно к десятичной, эти значения:

0.1 + 0.2 => 0.300000000000000044408920985006...
0.3       => 0.299999999999999988897769753748...

Разница в точности равна 2-54, что составляет ~ 5.5511151231258 × 10-17 - незначительно (для многих приложений) по сравнению с исходными значениями.

Сравнение последних нескольких бит числа с плавающей запятой по своей сути опасно, как и любой, кто читает знаменитый «

, что каждый компьютерный ученый должен знать о арифметике с плавающей точкой » (который охватывает все основные части этого ответа).

Большинство калькуляторов используют дополнительные охранные цифры , чтобы обойти эту проблему, так как 0.1 + 0.2 даст 0.3: последние несколько биты округлены.

32
задан user2938093 18 February 2016 в 21:01
поделиться

3 ответа

Вы можете использовать конструктор DataFrame с lists, созданный путем преобразования в numpy array с помощью values с tolist :

import pandas as pd

d1 = {'teams': [['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],
                ['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG']]}
df2 = pd.DataFrame(d1)
print (df2)
       teams
0  [SF, NYG]
1  [SF, NYG]
2  [SF, NYG]
3  [SF, NYG]
4  [SF, NYG]
5  [SF, NYG]
6  [SF, NYG]

df2[['team1','team2']] = pd.DataFrame(df2.teams.values.tolist(), index= df2.index)
print (df2)
       teams team1 team2
0  [SF, NYG]    SF   NYG
1  [SF, NYG]    SF   NYG
2  [SF, NYG]    SF   NYG
3  [SF, NYG]    SF   NYG
4  [SF, NYG]    SF   NYG
5  [SF, NYG]    SF   NYG
6  [SF, NYG]    SF   NYG

И для нового DataFrame:

df3 = pd.DataFrame(df2['teams'].values.tolist(), columns=['team1','team2'])
print (df3)
  team1 team2
0    SF   NYG
1    SF   NYG
2    SF   NYG
3    SF   NYG
4    SF   NYG
5    SF   NYG
6    SF   NYG

Решение с apply(pd.Series) очень медленно:

#7k rows
df2 = pd.concat([df2]*1000).reset_index(drop=True)

In [89]: %timeit df2['teams'].apply(pd.Series)
1 loop, best of 3: 1.15 s per loop

In [90]: %timeit pd.DataFrame(df2['teams'].values.tolist(), columns=['team1','team2'])
1000 loops, best of 3: 820 µs per loop
65
ответ дан jezrael 25 August 2018 в 05:46
поделиться

Более простое решение:

pd.DataFrame(df2.teams.tolist(), columns=['team1', 'team2'])

Выход,

  team1 team2
-------------
0    SF   NYG
1    SF   NYG
2    SF   NYG
3    SF   NYG
4    SF   NYG
5    SF   NYG
6    SF   NYG
7    SF   NYG

Если вы хотите разбить столбец с разделителями, а не на списки, вы также можете сделать следующее:

pd.DataFrame(df.teams.str.split('<delim>', expand=True).values,
             columns=['team1', 'team2'])
1
ответ дан Joseph Davison 25 August 2018 в 05:46
поделиться

Кажется, что синтаксически более простой способ и, следовательно, легче запомнить, в отличие от предлагаемых решений. Я предполагаю, что столбец называется «мета» в dataframe df:

df2 = pd.DataFrame(df['meta'].str.split().values.tolist())
4
ответ дан mikkokotila 25 August 2018 в 05:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: