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

#python #pandas #dataframe #numpy #data-analysis

Вопрос:

фрейм данных(ввод)

 0     1.0     25.0
1     1.0     31.0
2     2.0     97.0
3     1.0     25.0
4     1.0     26.0
 

выход

Я хочу получить массив с индексами от 1 до 97 включительно, в котором указано, сколько раз каждый индекс был в интервалах, например, 1 был в 4 интервалах(первые два и последние два интервала), 3 был в 5 интервалах, 96 был только в 1 интервале. обратите внимание, что я не могу использовать цикл, и мне приходится делать это с помощью операций с массивами(numpy, pandas).

Я хочу получить что-то вроде:

 1    4 
2    5
3    5
.
.
.
25   5 
26   3
27   2
28   2
29   2
30   2
31   2
32   1
33   1
34   1
.
.
. 
97   1
 

Ответ №1:

пробовать:

 df1 = pd.DataFrame(data=[i for i in range(1,98)])
 

df:

     0   1       2
0   0   1.0     25.0
1   1   1.0     31.0
2   2   2.0     97.0
3   3   1.0     25.0
4   4   1.0     26.0
 

df1.головка():

     0
0   1
1   2
2   3
3   4
4   5
 

 res = df1[0].apply(lambda x: sum((df[1]<=x) amp; (df[2]>=x)))
 

RES:

 0     4
1     5
2     5
3     5
4     5
     ..
92    1
93    1
94    1
95    1
96    1
Name: 0, Length: 97, dtype: int64
 

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

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

2. @Хамед, Да, ты можешь это сделать.

Ответ №2:

Вы можете формировать диапазоны для каждой строки, а затем разносить их. Подсчет значений дает конечный результат:

 result = (pd.Series(np.arange(first, second 1) for first, second in df.to_numpy())
                   .explode()
                   .value_counts(sort=False))
 

получить

 >>> result

1.0     4
2.0     5
3.0     5
4.0     5
5.0     5
       ..
93.0    1
94.0    1
95.0    1
96.0    1
97.0    1
 

Это не обязательно будет включать все значения в 1..97, потому что, если число выпадает из каждого интервала, оно не будет учитываться. Чтобы гарантировать индекс 1..97, мы можем переиндексировать с минимальными и максимальными значениями (т. Е. 1 и 97 здесь) и поставить 0 к тем, которые не появились:

 values = df.to_numpy()
min_, max_ = values.min(), values.max()

result = result.reindex(np.arange(min_, max_ 1), fill_value=0)
 

и последнее замечание np.arange : s можно заменить на range , если значения в кадре являются целыми числами и, следовательно df = df.astype(int) , не теряют никакой информации. Если нет, np.arange то это необходимо. Кроме того, np.arange инкапсулирует range , чтобы его можно было использовать в любом случае.

Ответ №3:

Сначала нам нужно знать, сколько интервалов открывается и закрывается при каждом значении:

 >>> df
    col_1 col_2
0     1.0  25.0
1.0   1.0  31.0
2.0   2.0  97.0
3.0   1.0  25.0
4.0   1.0  26.0
>>> idx = pd.RangeIndex(1, 98)
>>> opencount = df['col_1'].value_counts().reindex(idx, fill_value=0)
>>> closecount = df['col_2'].value_counts().reindex(idx, fill_value=0)
>>> opencount
1     3
2     1
3     0
4     0
5     0
 ..
93    0
94    0
95    0
96    0
97    0
Name: col_1, Length: 97, dtype: int64
>>> closecount
1     0
2     0
3     0
4     0
5     0
 ..
93    0
94    0
95    0
96    0
97    1
Name: col_2, Length: 97, dtype: int64
 

Обратите внимание, что раньше мы reindex добавляли нули во все значения, недоступные в col_1 и col_2 .

Если на самом деле конец интервала содержится в интервале (согласно комментариям), вы можете просто сдвинуть closecount его вниз на 1:

 >>> closecount = closecount.shift(fill_value=0)
>>> closecount
1     0
2     0
3     0
4     0
5     0
     ..
93    0
94    0
95    0
96    0
97    0
Name: col_2, Length: 97, dtype: int64
 

Затем мы можем вычислить количество интервалов в каждой точке как сумму интервалов, открывавшихся ранее, за вычетом суммы интервалов, закрывавшихся ранее. Это можно сделать с помощью cumsum

 >>> opencount.cumsum() - closecount.cumsum()
1     4
2     5
3     5
4     5
5     5
     ..
93    1
94    1
95    1
96    1
97    1
Length: 97, dtype: int64
 

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

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

2. Ах, тогда вам просто нужно добавить сдвиг() @Hamed, я отредактирую свой ответ

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

Ответ №4:

пробовать:

 df1 = df.groupby(['ColumnName']).count()
 

Это вернет столбец, который вы выбрали в качестве индекса, и получит количество совпадающих интервалов

Ответ №5:

Вы можете сделать следующее. Сначала создайте новый фрейм данных со столбцом от 1 до 97

 >>> df2 = pd.DataFrame(list(range(1,98,1)), dtype=float, columns=["range"])
>>> df2
    range
0     1.0
1     2.0
2     3.0
3     4.0
4     5.0
..    ...
92   93.0
93   94.0
94   95.0
95   96.0
96   97.0
 

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

 >>> dfg = df.groupby('val').agg('count')
>>> dfg
     range
val
1.0      4
2.0      1
 

Теперь сопоставьте свои df и в то же время заполните пропущенные значения нулями. Затем приведите к целочисленному, чтобы соответствовать ожидаемому формату OP.

 >>> df2["count"] = df2["range"].map(dfg['range']).fillna(0)
>>> df2 = df2.astype(int)
>>> df2
    range  count
0       1      4
1       2      1
2       3      0
3       4      0
4       5      0
..    ...    ...
92     93      0
93     94      0
94     95      0
95     96      0
96     97      0
 

И при необходимости приведите к целочисленному

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

1. NaN вместо подсчетов есть s; это не ожидаемый результат, не так ли?